瞭解JS的原型鏈和繼承

原型鏈的概念:

當試圖訪問一個對象的屬性時,它不單單在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依次層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。bash

eg1:

var n = new Number(1)
n.toString() // "1"
複製代碼

1.調用toString方法時,會先在n實例上查找這個屬性,沒有找到?app

2.查找n的原型對象,就是Number.prototype(n.__proto__), 咱們能夠看到函數

eg2:

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
複製代碼

new關鍵字在這裏作了什麼?

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'}
複製代碼

使用Object.create建立對象

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"
複製代碼
相關文章
相關標籤/搜索