JavaScript 原型和原型链

时间:2022-07-28 14:39:38

对象可以分为函数对象和普通对象,prototype是函数对象才有的属性,__proto__是每个对象都有的一个属性,

通过new Function 的是函数对象,

function f() {} ==> var f = new Function();  两者是等价的
var o ={}; //普通对象
console.log(typeof o) //object
var o2 = new f(); //函数实例是普通对象
console.log(typeof o2) //object
 

重点:

1、每一个函数对象都有prototype属性,普通对象没有;prototype下面又有个construetor,指向这个函数;
2、每一个对象都有一个__proto__属性;指向它所对应的构造函数的原型对象;
 
JavaScript 原型和原型链

原型(prototype)检测

上面提到只有函数对象才有prototype,现在来检测一下
 1        var o3 ={};  //o3 = new Object()
 2        console.log(o3.prototype); //undefined
 3        console.log(o3 instanceof Object);  //实例o3在不在Object构造函数中  true
 4 
 5        function Demo() {}  //函数对象
 6        var d = new Demo();  //普通对象
 7        console.log(d.prototype);  //undefined
 8        console.log(d instanceof Demo); 
 9        console.log(typeof Demo);
10        console.log(Demo.prototype);    //{constructor: ƒ}  函数对象确实存在原型

原型对象

 1        function Cat(name,color){   //构造函数
 2            this.name = name;
 3            this.color = color;
 4         //    this.type = '动物';
 5         //    this.eat = function() {
 6         //        console.log('吃老鼠')
 7         //    }
 8        };
 9        Cat.prototype.type = '动物';
10        Cat.prototype.eat = function() {
11             console.log('吃老鼠')
12         }
13        var cat1 = new Cat('大明','黑色');
14        var cat2 = new Cat('小明','白色');

函数对象对原型属性的检测

1        //in 无论是自身的还是原型属性都返回true
2        console.log('name' in cat1) ;//true
3        console.log('type' in cat1) ;//true
4        //hasOwnProperty()  自身的属性返回true   原型属性返回false
5        console.log(cat1.hasOwnProperty('name'));  //true
6        console.log(cat1.hasOwnProperty('type'));  //false

继承

apply() 与 call()

apply() 与 call()是函数对象的两个方法,在一个函数对象中调用另一个函数对象 call(this,参数1,参数2) apply(this,[参数1,参数3]),改变其作用域绑定到当前作用域。
两者区别: 就是参数不同, apply 传数组 call 一个个传;
 
 1 function Animal(){   //一个对象   父对象
 2     this.type = '动物'
 3 };
 4 function Cat(name,color){   //另一个对象    子对象
 5     Animal.apply(this); //Animal在当前Cat对象中执行,将父对象的构造函数绑定到子对象上
 6     this.name = name;
 7     this.color = color;
 8 };
 9 var cat1 = new Cat('大毛','黄色');
10 cat1.type; //'动物'

直接继承

1)让Cat的原型直接继承Animal的实例
function Animal(){   //一个对象   父对象
    this.type = '动物'
};
function Cat(name,color){   //另一个对象    子对象
    this.name = name;
    this.color = color;
};
Cat.prototype = new Animal();
var cat1 = new Cat('大毛','黄色');
cat1.type; //'动物'

2)让Cat的原型直接继承Animal的原型

有个缺点就是Cat.prototype和Animal.prototyper指向同一个对象,指向同一块内存地址,当修改Cat.prototype的值时,Animal.prototype也会变化

function Animal(){}; //一个对象   父对象
Animal.prototype.type = '动物';
function Cat(name,color){   //另一个对象    子对象
    this.name = name;
    this.color = color;
};
Cat.prototype = Animal.prototype; 
Cat.prototype.abc = 'abc';
var cat1 = new Cat('大毛','黄色');
cat1.type; //'动物'
console.log(Animal.prototype);//{type: "动物", abc: "abc", constructor: ƒ}

原型属性的CURD操作

原型继承说白了就是通过__proto__链接起来的

Cat.prototype 继承 的是 Animal实例对象  上面说到不管是函数对象还是普通对象它都有__proto__这个属性,原本cat1实例对象的__proto__指向的是 Cat函数对象的prototype对象,

但是现在Cat.prototype = new Animal();       所以此时的cat1实例对象的__proto__指向的是 new Animal()实例   ===>   等价于   cat1.__proto__ = new Animal();  通过cat1.__proto__可以获取Animal信息

function Animal(){
    this.type= '动物';
};
function Cat(name,color){   //构造函数
    this.name = name;
    this.color = color;
};
Cat.prototype = new Animal();
var cat1 = new Cat('大明','黑色');
var cat2 = new Cat('小明','白色');
console.log(cat1.type);    //动物
//获取属性
console.log(cat1.__proto__.type='猫科动物'); //猫科动物
//设置属性
cat1.__proto__.action="敏捷";
//删除属性
delete cat1.__proto__.type;
//查看属性
console.log(cat1.__proto__.action);//敏捷
//查看继承的整个实例对象内容
console.log(cat1.__proto__);  //Animal {type: "猫科动物"}

 另一种写法

function Animal(){
    this.type= '动物';
};
Animal.prototype.type2='动物2';
function Cat(name,color){   //构造函数
    this.name = name;
    this.color = color;
};
Cat.prototype = new Animal();
var cat1 = new Cat('大明','黑色');
var cat2 = new Cat('小明','白色');
// cat1.type;

console.log(cat1.__proto__.__proto__.type2='abc');  //修改   打印出abc
delete cat1.__proto__.__proto__.type2;   //删除
console.log(cat1.type2);    //已经删除,打印出undefined
 
 cat1.__proto__指向的是 Animal的实例  如果需要获得Animal原型中的属性就需要再加上一个__proto__  中间用点连接,其实这就是原型链

原型链

F3实例对象 f 的__proto__ ==> F3.prototype,  F3.prototype的__proto__ ==>  F2实例对象,  F2.prototype  ==>  F1实例对象

function F1(){
    this.name1 = 'f1';
};
function F2(){
    this.name2 = 'f2';
};
function F3(){
    this.name3 = 'f3';
};
F2.prototype = new F1();
F3.prototype = new F2();
var f = new F3();
console.log(f.name3);   //f3