从一个例子说起
function Foo() {}
var a = new Foo()
a.constructor === Foo //true
Foo.prototype.constructor === Foo //true
- 这个例子是在原型链中经典的问题。我们发现在Foo的原型上有一个constructor属性指向了本身Foo,可是a上并没有constructor属性,但是这个确实返回了ture是什么情况呢?
- 回到对象的[get]方法。
- 对js中的对象上取值有两种方法 . 和 [] 两者不同的区别就是在 . 后的属性名必须要是符合js的命名规范的,在 [] 就不用,在 [] 中会发生隐式转换,将内容转化为字符串形式,在 [] 内部也可以进行表达式的运算。在对象中的 key 值也会发生类型转换,自动转为字符串。
- 但使用 . 或者 [] 对对象的属性进行访问的时候。会调用 [get] 方法
var a = {
get num() {
return 12
}
}
console.log(a.num) // 12
Object.prototype.temp = 2
console.log(a.temp) // 2 说明了当查找对象的时候当对象内部没有这个属性的时候,会去
对象的原型(prototype)上进行查找。
- 若在对象上和prototype上都有属性的时候这个时候就会发生属性屏蔽,将 prototype 上的属性屏蔽。这个有很多种情况。感兴趣的可以去了解一下。涉及到属性的配置 是否可写,可配置。
- 现在我们知道了查找属性是调用了 [get] 方法。若内部没有去prototype上找。若还是没有返回undefined。但是这个并不能作为对象中有无某个属性的标志。如
var a = {b: undefined }
这个查找a[b]的时候依旧为undefined。当判断有无属性时还是使用hasoOwnProperty方法这个方法判断对象上是否包含某个属性。in 方法包含了prototype。当然如果属性配置了不可枚举,两者都失效。 - 回到主题。在new Foo() 中当Foo函数被当作构造函数调用的时候(注意他不是构造函数,只是当作构造函数去调用)创建一个新对象 a ;此时 a 对象的原型和 Foo 的原型进行关联 (不是继承);执行构造函数中的代码(为这个新对象添加属性);返回新对象 a ;,此时在a.constructor 时查找 a 对象内部,当发现无constructor时去他所关联的 Foo 原型上进行查找, 发现constructor返回 此时constructor指向Foo 所以返回true
- 下面的例子可以更好的去解释
function Foo() {}
Foo.prototype = {}
var a = new Foo()
a.constructor == Foo //false
a.constructor == Object //true
- 分析: Foo的原型为 {} 一个空的对象。a.constructor去Foo的prototype上查找,没有。此时从 {} 的prototype上查找。发现为Object 返回 {}的原型就是 Object 。这个例子说明了原型链的关联。
- 上面例子中改变条件
Foo.prototype = {constructor: 1 }
此时的a.constructor === 1 //true - 为什么说是关联
function Foo() {}
var a = new Foo()
Foo.prototype.num = 2000
a.num //2000
这个例子中说明Foo的原型和a的原型确实有关系,但是a.prototype == Foo.prototype
返回的是false。并且a.prototype
,返回的是undefined。说明a上并没有这个属性。但是a.num确实返回了2000,这样可以说在 a 中查找变量时 遵循 get 当a对象上无这个变量时,就去Foo的prototype上查找,但是这里只是返回值,无法对其修改。所以说这里只是关联,并不是拷贝