var o = Object.create(protoObj);
o.age; // 18,这里访问的是原型属性,也就是继承得到的属性
属性设置
通过属性访问表达式,我们可以得到属性的引用,就可以据此设置属性了。这里主要注意一下只读属性和继承属性即可,细节不再展开。
原型
前面也提到了,原型是实现继承的基础。那么如何去理解原型呢?
首先,要明确原型概念中的三角关系,三个主角分别是构造函数,原型,实例。我这里画了一张比较简单的图来帮助理解下。
原型这东西吧,我感觉“没人能帮你理解,只有你自己去试过才是懂了”。
不过这里说说我刚学习原型时的疑惑,疑惑的是为什么构造函数有属性prototype
指向原型,而实例又可以通过__proto__
指向原型,究竟prototype
和__proto__
谁是原型?其实这明显是没有理解对象是按引用访问这个特点了。原型对象永远只有一个,它存储于堆内存中,而构造函数的prototype
属性只是获得了原型的引用,通过这个引用可以操作原型。
同样地,__proto__
也只是原型的引用,但是要注意了,__proto__
不是ECMAScript
规范里的东西,所以千万不要用在生产环境中。
至于为什么不可以通过__proto__
访问原型,原因也很简单。通过实例直接获得了原型的访问和修改权限,这本身是一件很危险的事情。
举个例子,这里有一个类LatinDancer
,意思是拉丁舞者。经过实例化操作,得到了多个拉丁舞者。
function LatinDancer(name) {
this.name = name;
};
LatinDancer.prototype.dance = function() {
console.log(this.name + ‘跳拉丁舞…’);
}
var dancer1 = new LatinDancer(‘小明’);
var dancer2 = new LatinDancer(‘小红’);
var dancer3 = new LatinDancer(‘小王’);
dancer1.dance(); // 小明跳拉丁舞…
dancer2.dance(); // 小红跳拉丁舞…
dancer3.dance(); // 小王跳拉丁舞…
大家欢快地跳着拉丁舞,突然小王这个家伙心血来潮,说:“我要做b-boy,我要跳Breaking”。于是,他私下改了原型方法dance()
。
dancer3.proto.dance = function() {
console.log(this.name + ‘跳breaking…’);
}
dancer1.dance(); // 小明跳breaking…
dancer2.dance(); // 小红跳breaking…
dancer3.dance(); // 小王跳breaking…
这个时候就不对劲了,小明和小红正跳着拉丁,突然身体不受控制了,跳起了Breaking,心里暗骂:“沃尼玛,劳资不是跳拉丁的吗?”
这里只是举个例子哈,没有对任何舞种或者舞者不敬的意思,抱歉抱歉。
所以,大家应该也明白了为什么不能使用__proto