JS01原型和原型链

#三个关系

1
2
3
4
function Ninja() {
}
console.log(Ninja) //[Function: Ninja]
console.log(Ninja.prototype) //Ninja {}

方法具有prototype属性,方法的prototype属性是一个对象

1
2
3
4
5
6
7
var ninja = new Ninja()
console.log(ninja.__proto__) //Ninja {}
console.log(ninja.prototype) //undefined
console.log(Ninja.prototype === ninja.__proto__) //true
console.log(Object.getPrototypeOf(ninja) === Ninja.prototype)//true
//Object.setPrototypeOf(a,b)方法将 b 对象设置为 a 对象的原型
console.log(Ninja === Ninja.prototype.constructor) // true

构造函数创建的对象(通过 new 操作符调用函数意味着作为构造器调用)具有__proto__属性,而且Ninja.prototypeninja.__proto__是同一个对象

#实例属性和原型属性

1
2
3
4
5
6
7
8
9
function Ninja() {
}
Ninja.prototype.name = 'tony'
const ninja = new Ninja()
console.log(ninja)
ninja.name = 'lu'
console.log(ninja.name)
delete ninja.name
console.log(ninja.name)

当读取实例的属性时,如果找不到,就会查找与对象原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

实例中可以查找到的属性就不会查找原型。

实例会隐藏原型中与实例方法重名的方法。

并不是继承

继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。

原型的原型

#JavaScript动态特性的副作用

对象与函数原型之间引用关系是在对象创建时建立的,如果原型在代码过程中被篡改,新创建的对象将引用新的原型,原来旧的对象保持着原有的原型的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var log = console.log.bind(this)
function Ninja() {
this.swung = true
}
const ninja1 = new Ninja()
Ninja.prototype.swingSword = function () {
return this.swung
}
log(ninja1.__proto__)//Ninja { swingSword: [Function] }
Ninja.prototype = {
pierce : function () {
return true
}
}
log(ninja1.__proto__) //Ninja { swingSword: [Function] }
const ninja2 = new Ninja()
log(ninja2.__proto__) //{ pierce: [Function: pierce] }

函数(function)对象的原型链

在JavaScript中,函数是一个特殊的对象,所有函数都是构造函数Function的实例,所以原型链会有所不同

1
2
3
4
5
6
7
8
9
var log = console.log.bind(this)
function Ninja() {
}
log(Ninja)//[Function: Ninja]
log(typeof Function)//function
log(Ninja.__proto__)//[Function] 对象的__proto__是对象,不可能是方法
log(Ninja.__proto__ === Function.prototype)//true
log(Function.__proto__)//[Function]
log(Function.prototype)//[Function]

#Cautions

Tips

  1. 因为所有实例对象都可以访问 constructor 属性所以可以使用 const ninja2 = new ninja1.constructor()来初始化

  2. instanceof 操作符的实质是:检查操作符右边的函数的原型是否存在于操作符左边的对象的原型链上

##还有很多细节可继续阅读《JavaScript忍者秘籍》(第二版)第七章的内容补充