原型
一、对象属性
对象引用属性:当引用一个对象的属性时,触发默认的 [[Get]] 操作,先检查对象本身是否存在这个属性,有则使用,无则继续访问对象的 [[prototype]] 链。
所有普通的 [[prototype]] 链最终都会指向内置的 Object.prototype。
对象属性设置:
-
= 操作符
如果设置的属性既出现在对象本身,也出现在 [[prototype]] 链上层,会发生隐蔽。
对象包含的该属性会屏蔽原型链上层的所有该属性。因为对象属性的设置会选择原型链最底层的该属性。如果设置的属性不存在于该对象而是存在于原型链上层时:
1、该属性是普通数据访问属性且 writable: true 直接在该引用对象中添加该属性,屏蔽属性。
2、该属性是普通数据访问属性且 writable: false 则该赋值语句被忽略;严格模式下报错,不发生屏蔽。
3、该属性是一个 setter,那就一定会调用这个 setter。不会添加到引用对象上,也不会重新定义 setter,不发生屏蔽。 -
使用 Object.defineProperty(…)
不会受到屏蔽情况影响。
二、“类”函数
所有的函数默认都会拥有一个名为 prototype 的共有且不可枚举的属性,它会指向另一个对象。
javsscript 会在两个对象之前创建一个关联,这样一个对象就可以通过委托访问另一个对象的属性和函数。
函数不是构造函数。当且仅当使用 new 时,函数调用会变成“构造函数调用”。
new Fun() 间接完成了目的:一个关联到其他对象的新对象。
Fun.prototype 默认有一个公有且不可枚举的属性 .constructor。这个属性引用的是对象关联的函数(Fun)。
.constructor 是可变属性,但不可枚举。它的值是可写的,你可以给任意 [[prototype]] 链中的任意对象添加一个名为 constructor 的属性或对其进行修改。可以任意对其赋值。
function Fun(name) {
this.name = name;
}
Fun.prototype.constructor === Fun; //true
Fun.prototype.myName = function() {
return this.name;
}
var a = new Fun("a");
a.constructor === Fun; //true
a.myName(); //"a"
面向类技巧:
- this.name = name 给每个对象(a)都添加了 .name 属性。有点像类实例封装的数据值。
- Fun.prototype.myName = … 给 Fun.prototype 对象添加了个属性函数。而 a 的内部 [[prototype]] 关联到 Fun.prototype。
所以调用时在 a 无法找到会在 Fun.prototype 上找。 - a.constructor 引用同样委托给了 Fun.prototype。
三、(原型)继承
关联方法:
- Fun2.prototype = Object.create(Fun1.prototype);
创建一个新的 Fun2.prototype 对象并把它关联到 Fun1.prototype;旧对象被抛弃,不能直接修改已有默认对象。 - Fun2.prototype = Fun1.prototype;
直接引用 Fun1.prototype 对象,对新对象赋值会直接修改 Fun1.prototype 对象本身。 - Fun2.prototype = new Fun1();
构造函数调用,小副作用,影响后代,尽量不用。 - Object.setPrototypeOf(Fun2.prototype, Fun1.prototype);
标准可靠的方法(ES6)
检查“类”关系:
- instanceof:只能处理对象和函数。
注意:构造函数中使用 .bind() 相当于直接调用目标函数,在硬绑定函数上使用 instanceof 相当于直接在目标函数上使用 instanceof。 - isPrototypeOf(…):处理对象和对象。
- Object.getPrototypeOf(…) = .__ proto __ :引用内部 [[prototype]] 对象来判断。
//使用
a instanceof Fun;
Fun.prototype.isPrototypeOf(a);
b.isPrototypeOf(a);
Object.getPrototypeOf(a) === a.__proto__ === Fun.prototype
其中 .__ proto __ 像属性,但更像 getter。
Object.defineProperty(Object.prototype, "__proto__", {
get: function() {
return Object.getPrototypeOf(this);
},
set: function() {
Object.setPrototypeOf(this, o);
return o;
}
})
四、对象关联
Object.create()
ES5之前版本 ployfill
if(!Object.create) {
Object.create = function() {
function F() {};
F.prototype = o;
return new F();
}
}
Object.create(null) 会创建一个拥有空 [[prototype]] 链接的对象。这个对象无法进行委托。