文章参考:你不知道的javaScript
属性屏蔽
如果myObject 对象中包含名为foo的普通数据访问属性,这条赋值语句只会修改已有的属性值。
如果foo不是直接存在于myObject中,[[Prototype]]链就会被遍历,类似[[Get]]操作。
如果原型链上找不到foo,foo就会被直接添加到myObject上。
如果属性名foo既出现在myObject中也出现在myObject的[[Prototype]]链上层,那么就会发生屏蔽。myObject中包含的foo属性会屏蔽原型链上层的所有foo属性,因为 myObject.foo 总是会选择原型链中最底层的foo属性。
function People(){
this.name = "张三";
}
People.prototype.say = function(){
console.log("我是张三");
}
var p = new People();
p.say = function(){
console.log("我是李四");
}
p.say(); //李四
People.prototype.say(); // 张三
当原型链中存在这个属性时情况,考虑到原型对象的完整性,是无法间接修改原型对象的属性的。 1.原型链上存在这个属性且writtable属性值为true的情况:
function People(){
this.name = "张三";
}
People.prototype.say = function(){
console.log("我是张三");
}
var p = new People();
p.say = function(){ // 添加属性并未影响原型的值
console.log("我是李四");
}
p.say(); //李四
People.prototype.say(); // 张三
2.原型链上存在这个属性且writtable属性值为false的情况,可以看成继承了一个无法修改的属性:
function People(){
this.name = "张三";
}
People.prototype.say = function(){
console.log("我是张三");
}
Object.defineProperty(People.prototype,"say",{
writable:false
});
var p = new People();
p.say = function(){ // 静默修改失败,严格报错
console.log("我是李四");
}
p.say(); // 张三
People.prototype.say();//张三
3.如果在[[Prototype]] 链上层存在foo并且它是一个setter,那就一定会调用这个setter。foo不会被添加到(或者说屏蔽于)myObject,也不会重新定义foo这个setter。
如果你希望在第二种和第三种情况下也屏蔽foo,那就不能使用=操作符来赋值,而是使 用Object.defineProperty(..)(参见第 3 章)来向myObject 添加foo
继承
js中的继承,实际上是委托更合适。在真正面向对象的语言中,例如java,子类继承父类的属性,子类是复制了父类的一份拷贝,就像真正父子的关系一样,继承了爸爸的大眼睛,且两个是独立的个体。但是js是通过引用来达到委托效果。
function Bar(){}
function Foo(){}
// 和你想要的机制不一样!例如设置Bar.prototype时,就是设置Foo.prototype。
Bar.prototype = Foo.prototype;
// 基本上满足你的需求,但是可能会产生一些副作用 :会执行Foo的方法,
Bar.prototype = new Foo()
因此,要创建一个合适的关联对象,我们必须使用Object.create(..)而不是使用具有副作用的Foo(..)。这样做唯一的缺点就是需要创建一个新对象然后把Bar旧原型对象抛弃掉,不能直接修改已有的默认对象。
在ES6之前, 我们只能通过设置.__proto__属性来实现,但是这个方法并不是标准并且无法兼容所有浏 览器。ES6添加了辅助函数Object.setPrototypeOf(..),可以用标准并且可靠的方法来修改关联
// ES6 之前需要抛弃默认的Bar.prototype
Bar.ptototype = Object.create( Foo.prototype );
// ES6 开始可以直接修改现有的Bar.prototype
Object.setPrototypeOf( Bar.prototype, Foo.prototype )
检查对象和类的关系
a instanceof Foo; // true
instanceof的意思是:在左边的对象的原型链上是否存在Foo.prototype这个对象。
如果使用内置的.bind(..)函数来生成一个硬绑定函数的话,该函数是没有.prototype属性的。在这样的函数上使用instanceof的话, 目标函数的.prototype会代替硬绑定函数的.prototype。
function People(){}
let People1 = People.bind();
console.log('prototype' in People1); //false
console.log('prototype' in People); // true
通常我们不会在“构造函数调用”中使用硬绑定函数,不过如果你这么 做的话,实际上相当于直接调用目标函数。同理,在硬绑定函数上使用 instanceof 也相当于直接在目标函数上使用instanceof。
function People(){}
People.prototype.say = function(){
console.log("我是张三");
}
let People1 = People.bind();
let p1 = new People1();
let p = new People();
p1.say(); // 我是张三
console.log(p instanceof People1); // true