真正的原型叫[[Prototype]]
__proto__是[[Prototype]]的因历史原因而留下来的 getter/setter。__proto__属性有点过时了,但是能用。
现在用Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型
for..in 循环也会迭代继承的属性。
let animal = { eats: true };
let rabbit = { jumps: true, __proto__: animal };
*// Object.keys 只返回自己的 key
alert(Object.keys(rabbit)); // jumps*
*// for..in 会遍历自己以及继承的键
for(let prop in rabbit) alert(prop); // jumps,然后是 eats*
有一个内建方法 obj.hasOwnProperty(key):如果 obj 具有自己的(非继承的)名为 key 的属性,则返回 true。
hasOwnProperty也是继承自Object.prototype的,奇怪的是for..in 循环会列出继承的属性,但没列出来 hasOwnProperty。
因为:它是不可枚举的。就像 Object.prototype 的其他属性,hasOwnProperty 有 enumerable:false 标志。并且 for..in 只会列出可枚举的属性。这就是为什么它和其余的 Object.prototype 属性都未被列出。
- 通过构造函数创建的对象设置
[[Prototype]]的方法:F.prototype属性在new ‘ 的时候可以指定新对象的原型F.prototype的值要么是一个对象,要么就是null`:其他值都不起作用。
"prototype" 属性仅在设置了一个构造函数(constructor function),并通过 new 调用时,才具有这种特殊的影响。
let animal = { eats: true };
function Rabbit(name) { this.name = name; }
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit");
// rabbit.__proto__ == animal
alert( rabbit.eats ); // true
原生的原型是可以被修改的。
例如,我们向 String.prototype 中添加一个方法,这个方法将对所有的字符串都是可用的:
String.prototype.show = function() { alert(this); };
"BOOM!".show(); // BOOM!
现代的方法
- Object.create(proto, [descriptors]) —— 利用给定的
proto作为[[Prototype]]和可选的属性描述来创建一个空对象。 - Object.getPrototypeOf(obj) —— 返回对象
obj的[[Prototype]]。 - Object.setPrototypeOf(obj, proto) —— 将对象
obj的[[Prototype]]设置为proto。
let animal = { eats: true }; // 创建一个以 animal 为原型的新对象
let rabbit = Object.create(animal);
alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // true
Object.setPrototypeOf(rabbit, {}); // 将 rabbit 的原型修改为 {}
Object.create 有一个可选的第二参数:属性描述器。我们可以在此处为新对象提供额外的属性,就像这样
let animal = { eats: true };
let rabbit = Object.create(animal, { jumps: { value: true } });
alert(rabbit.jumps); // true