属性设置和屏蔽
当执行obj.a
这段代码,且a
不直接存在于obj
上时
- 如果原型链上不存在
a
,a
就会被直接添加到obj
上 - 如果存在,并且
writeable: true
,那么也会被直接添加到obj
上 - 如果存在,但是
writeable: false
,那么即无法修改,也无法创建属性 - 如果存在,并且它是一个
setter
,那不管怎么都会调用这个函数 - 如果希望前面两种情况直接像第二种情况一样屏蔽掉原型链上的
a
,那么定义的属性的时候就不能使用=
号,而是使用Object.defineProperty()
来添加
类 函数
在javaScript
中,没有其他面向类的语言中的复制机制,你不能创建一个类的多个实例,只能创建多个对象,他们的[[Prototype]]
关联的是同一个对象,默认情况下不会进行复制,因此这些对象之间不会完全失去联系他们是互相关联的
继承意味着复制操作,javaScript
中不存在复制
构造函数
应该这样说,在javaScript
中对于构造函数最准确的解释是,所有带new
的函数调用
技术
注意constructor
指向的可变性,即不一定指向创建它的那个函数
原型 继承
正确的原型继承应该像下面这样书写
function Foo(name) {
this.name = name
}
Foo.prototype.myName = function () {
return this.name
}
function Bar(name, label) {
Foo.call(this, name)
this.label = label
}
Bar.prototype = Object.create(Foo.prototype) // 这里是关键 创建一个新的对象,原型指向为Foo
Bar.prototype.constructor = Bar
Bar.prototype.myLabel = function() {
return this.label
}
var a = new Bar("a", "obj a")
a.myName() // "a"
a.myLabel() // "obj a"
错误做法一
Bar.prototype = Foo.prototype
这种做法让Bar
与Foo
的原型指向同一个,当修改一个的原型的时候,会影响另一个
错误做法二
Bar.prototype = new Foo()
这个方法的确会创建一个关联到Bar.prototype
的新对象,但是它使用了Foo
的构造函数的调用,如果Foo
有一些副作用(比如写日志,修改状态,注册到其他对象,给this
添加数据属性等等),会影响到Bar
的后代,后果严重
几种修改[[Prototype]]
关联的方式
- es6之前,
Bar.prototype = Object.create( Foo.prototype )
- es6,
Object.setPrototypeOf( Bar.prototype, Foo.prototype)
检查类关系
instanceof
: 这个方法只能处理对象和函数(带.prototype
)之间的关系Foo.prototype.isPrototypeOf(a)
,它的大体实现如下
function isPrototypeOf(a) {
function F () {}
F.prototype = this
return a instanceof F
}
Object.getPrototypeOf(a)
:获取这个对象的[[Prototype]]
链
Object.getPrototypeOf(a) === Foo.prototype // 这样来使用它
- 或者使用
__proto__
来获取[[Prototype]]
链:它的大体实现如下
Object.definedProperty( Object.prototype, "__proto__", {
get: function() {
return Object.getPrototypeOf(this)
},
set: function(o) {
Object.setPrototypeOf(this, o)
return o
}
})
Object.create(o)
它会创建一个新的对象,并把它关联到我们指定的对象,当参数为null
时,会创建一个拥有空[[Prototype]]
链接的对象,意思就是它不会有原型链,因此也非常适合用来做存储数据。它的大体实现如下
if (!Object.create) {
Object.create = function (o) {
function F () {}
F.prototype = o
return new F()
}
}