當試圖訪問一個對象的屬性時,它不單單在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。bash
var n = new Number(1)
n.toString() // "1"
複製代碼
1.調用toString方法時,會先在n實例上查找這個屬性,沒有找到?app
2.查找n的原型對象,就是Number.prototype(n.__proto__
), 咱們能夠看到函數
var n = new Number(1)
n.hasOwnProperty('') // ""
複製代碼
1.在n實例上沒有找到hasOwnProperty方法ui
2.在n的原型對象上沒有找到this
3.在n的原型對象的原型對象上繼續查找,找到了Object.prototype(n.__proto__.__proto__
)spa
n.__proto__ === Number.prototype
複製代碼
n便是Nubmer的實例,也是Object的實例prototype
// 判斷一個對象是構造函數的實例咱們用instanceof
n instanceof Number // true
n instanceof Object // true
複製代碼
由於全部的對象都是基於Object建立,全部的對象都是Object的實例code
理解原型鏈是很是重要的,特別是在編寫複雜的代碼時cdn
var obj = {name: 'obj'}
// obj繼承了Object.prototype的屬性
// 原型鏈: obj ---> Object.prototype ---> null
複製代碼
var arr = [1, 2, 3]
// arr繼承了Array.prototype的屬性(forEach)
// 原型鏈:arr ---> Array.prototype ---> Object.prototype ---> null
複製代碼
function fun () {return 1}
// fun繼承了Function.prototype的屬性(call.apply)
// 原型鏈:fun ---> Function.prototype ---> Object.prototype ---> null
複製代碼
function Person () {
this.type = []
}
Person.prototype.add = function (v) {
this.type.push(v)
}
var p = new Person()
// p 擁有了構造函數Person的屬性type, 且p.__proto__ = Person.prototype
複製代碼
var p = {};
Person.call(p) //執行Person() this變量指向對象p, p擁有了Person的屬性
p.__proto__ = Person.prototype // p繼承了Person的原型對象
複製代碼
1.this指向不同對象
2.構造函數默認返回實例對象
p.__proto__ === Person.prototype
// 返回簡單數據類型
function Person () {
var a = 1
return a
}
var p = new Person() // Person
var p = Person() // 1
// 返回引用數據類型
function Person () {
var a = {name: 'a'}
return a
}
var p = new Person() // {name: 'a'}
var p = Person() // {name: 'a'}
複製代碼
var obj = {name: 'obj'} // obj是個實例對象
// 原型鏈:obj ---> Object.prototype ---> null
var child = Object.create(obj)
// 原型鏈:child ---> obj ---> Object.prototype ---> null
複製代碼
object.create的實現方式:
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
複製代碼
方式1:
function Person () {
this.type = ['good', 'bad']
}
Person.prototype.move = function () {
console.log('gogogo')
}
function Child () {}
Child.prototype = new Person()
var child = new Child()
child.move() // gogogo
複製代碼
方式2:
var child = Object.create(Person)
複製代碼
問題在於原型鏈中的引用類型,被全部子類實例共享了,咱們想要這樣嘛? 爲何會這樣呢?
var child1 = new Child()
var child2 = new Child()
child1.type.push('innocent')
child2.type // 'good', 'bad', 'innocent'
複製代碼
咱們先看下原型鏈: child1 ---> Child.prototype ---> Person.prototype
引用類型type對象是Child.prototype上面的屬性, 因此子類的實例的type屬性都是指向同一個Child.prototype.type
問題:父類實例的引用對象不共享,子類實例會共享? 由於new關鍵字
function Person () {
this.type = ['good', 'bad']
}
Person.prototype.move = function () {
console.log('gogogo')
}
function Child () {
Person.call(this)
}
Child.prototype = new Person()
var child = new Child()
child.move() // gogogo
var child2 = new Child()
child.type.push('innocent')
child2.type // "good", "bad"
複製代碼