js的原型和原型链

43 阅读3分钟

原型

原型的出现,是为了解决构造函数的缺点,(只能给对象添加属性,不能合理地添加函数),也就是提供了一个给对象添加函数的方法。

JS的每一个函数天生自带一个属性,叫prototype,它是个指针,默认情况下指向一个普通Object对象空间,(既然每个函数都有,那么构造函数也有),prototype属性指向的对象,就是构造函数的原型对象。(即prototype是构造函数的原型)

JS中每一个对象(除了null)都具有一个__proto__属性,(既然每个对象都有,那么构造函数的实例化对象也有),这个属性被称为对象的原型,该指针指向构造函数的原型对象。(即__proto__是构造函数的实例对象的原型,它指向构造函数的原型prototype)

每一个对象都有一个自己所属的构造函数,(数组所属的构造函数是Array,函数所属的构造函数是Function),对象的__proto__里面也有一个成员叫做constructor,这个属性就是指向当前这个对象所属的构造函数。

    function Star(name) {
        this.name = name;
    }
    let obj = new Star('小红');
    console.log(Star.prototype.constructor === Star);//true
    console.log(obj.__proto__.constructor === Star); //true

原型中this的指向是实例。

www.jianshu.com/p/7d58f8f45…

image-20190211200314401

附:一文看懂proto和prototype


什么是原型链

当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,这种链式查找过程称之为原型链。

原型链的尽头是null。也就是Object.prototype.proto

原型、原型链的意义:原型对象的作用,是用来存放实例中共有的那部份属性、方法,可以大大减少内存消耗。


通过实例对象修改原型链上属性

情况如js原型链上面的炕:通过实例对象修改原型(链)上面的属性所示。

所谓的坑,其实就是因为原型链的查找机制。

当我们通过赋值值类型也好,或者说是赋值引用类型也好,在执行obj1.name = '小黑'的时候,相当于给该obj1实例对象创建了一个同名属性,而没有修改原型链上的属性。所以自然不会影响其他实例对象。

function superType() {
}
superType.prototype = {
    name:'小白'
}
let obj1 = new superType()
let obj2 = new superType()
​
// 相当于给obj1实例对象上挂了一个属性name
obj1.name = '小黑'
// 在obj1对象内部查找到了name属性
console.log(obj1.name);     // 小黑
// 在obj2对象内部没找到,从其原型对象上读取name
console.log(obj2.name);     // 小白

而当我们通过数组方法如push、pop等操作,或者通过key修改value、通过索引修改某一项的时候,相当于修改了实例对象的原型对象,也就是obj1.__proto__.arr,而有obj1.__proto === superType.prototype,所以相当于修改了原型上面的属性。自然就会影响其所有的实例对象。

function superType() {
}
superType.prototype = {
    arr: ['a'],
}
let obj1 = new superType()
let obj2 = new superType()
​
// 相当于修改了obj1.__proto__,也就是原型上的属性
obj1.arr.push('b')
// 在obj1对象内部没找到,从其原型对象上读取arr
console.log(obj1.arr);      // [a,b]
// 在obj2对象内部没找到,从其原型对象上读取arr
console.log(obj2.arr);      // [a,b]