无聊就随便选一个话题来写吧。
原型链
其实原型链在我理解看来大概就是一段串联起来的关系链
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
中。
child3
和 child1
的最大区别在于一个是直接把 parent.prototype
的属性赋值给了 child1
, 另一个是使用 Object.create
创建了一个新的对象, 不会发生引用传值的问题, 引用传值会导致修改 child1.prototype
同时也会修改父元素的 prototype
, 但是 Object.create
可能会导致 constructor
属性丢失, 重新设置即可。
结语
其实构造函数跟原型链一起更配。今天就写这么多吧。
网友评论