JavaScript 原型和原型链

对象可以分为函数对象和普通对象,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属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个 constructor构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。People.prototype. constructor 指向 People。
2、当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性__proto__),指向构造函数的原型对象( People.prototype) 。
3、每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,
则继续搜索指针指向的原型对象
 

原型(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__  中间用点连接,其实这就是原型链

原型链

f 实例 指向 F3的原型,此时F3原型存放着F2实例的属性,  F3的原型又指向F2原型,F2原型对象里面存放着F1实例的值,  然后F2原型指向 F1原型.最终都会指向Object原型

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

 

 
 
 
 
posted @ 2019-07-05 10:25  观月吖  阅读(151)  评论(0编辑  收藏  举报