我对原型链的一些理解

无聊就随便选一个话题来写吧。

原型链

其实原型链在我理解看来大概就是一段串联起来的关系链

var demoObj = {
    a: 2
}

console.log(demoObj.a) //输出2

//如果新对象里面不含有该属性, 会从 [prototype] 里面去寻找
var newObj = Object.create(demoObj); //新对象与demoObj建立起关系
console.log(newObj.a) //同样输出2, 因为newObj的 [prototype] 指向了demoObj

用函数会比较直观:

//创建父类
function Animal() {}

//添加属性
Animal.prototype.walk = function() {
    console.log('walk')
}

//创建子类
function Cat() {}

//引用父类属性
Cat.prototype = Animal.prototype;

var cat = new Cat();
cat.walk(); //输出'walk'

这样的好处就是类似Array之类原生的对象给我们提供了一些可用的方法,可以给子类继续引用使用。

但是如果原型链上存在相同属性的时候,可能会出现一些意想不到的问题。

var demoObj = {
    width: 10
};

//创建属性,设置不可写
Object.defineProperty(demoObj, 'height', {
 writable: false,
 enumerable: true,
 configurable: true,
 value: 12
};

var newObj =  Object.create(demoObj);
console.log(newObj.height); //输出12;
newObj.height = 22; //赋值
newObj.width = 33; //赋值
console.log(newObj.height, newObj.width); //12, 33

上面的例子,如果对象不存在属性,而原型链上该属性不可写,会发生以上的情况。 newObj.width 正常被赋值到了对象上, console.log(newObj) 会发现多了 width 的属性, 这是正常的现象(叫屏蔽属性)。但原型链上不可写的时候, 就触发不了了。而且若当原型链上寻找的设置有setter的话, 也会调用setter的方法, 也同样添加不了属性到 newObj 里面。


prototype的赋值也有些区别:

function parent() {
    this.a = 123;
}

parent.prototype.talk = function() {
    console.log(this.a)
}

function child1() {}
function child2() {}
function child3() {}

child1.prototype = parent.prototype;
child2.prototype = new parent();
child3.prototype = Object.create(parent.prototype);

var result1 = new child1();
var result2 = new child2();
var result3 = new child3();

result1.talk(); //输出undefined
result2.talk(); //输出123
result3.talk(); //输出undefined

child1.prototype.hello = function() {
    console.log('hello')
}

child3.prototype.goodbye = function() {
    console.log('goodbye')
}

result1.hello(); //输出'hello'
result2.hello(); //输出'hello'
result3.hello(); //输出'hello'

result1.goodbye(); //error: result1.goodbye is not a function
result2.goodbye(); //error: result2.goodbye is not a function
result3.goodbye(); //输出'goodbye'

child2 函数中new 的方法, 他会创建 this 对象, 所以也把 a 属性也赋值给了 child2.prototype 中。
child3child1 的最大区别在于一个是直接把 parent.prototype 的属性赋值给了 child1 , 另一个是使用 Object.create 创建了一个新的对象, 不会发生引用传值的问题, 引用传值会导致修改 child1.prototype 同时也会修改父元素的 prototype , 但是 Object.create 可能会导致 constructor 属性丢失, 重新设置即可。


结语

其实构造函数跟原型链一起更配。今天就写这么多吧。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容