JS高階(原型/函式)
原型
Javascript 規定,每一個建構函式都有一個 prototype
屬性,指向另一個物件。這個物件的所有屬性和方法,都會被建構函式的例項繼承。這也就意味著,我們可以把所有物件例項需要共享的屬性和方法直接定義在 prototype
物件上。
function Person (name, age) { this.name = name this.age = age } console.log(Person.prototype) Person.prototype.type = 'human' Person.prototype.sayName = function () { console.log(this.name) } var p1 = new Person(...) var p2 = new Person(...) console.log(p1.sayName === p2.sayName) // => true
這時所有例項的 type
屬性和 sayName()
方法, 都是同一個記憶體地址,指向 prototype
物件,因此就提高了執行效率。
建構函式、例項、原型三者之間的關係
任何函式都具有一個 prototype
屬性,該屬性是一個物件。
建構函式的 prototype
物件預設都有一個 constructor
屬性,指向 prototype
物件所在函式。
通過建構函式得到的例項物件內部會包含一個指向建構函式的 prototype
物件的指標 __proto__
。
總結:
-
任何函式都具有一個
prototype
屬性,該屬性是一個物件 -
建構函式的
prototype
物件預設都有一個constructor
屬性,指向prototype
物件所在函式 -
通過建構函式得到的例項物件內部會包含一個指向建構函式的
prototype
物件的指標__proto__
-
所有例項都直接或間接繼承了原型物件的成員
原型物件的問題
-
共享陣列
-
共享物件
原型物件使用建議
-
私有成員(一般就是非函式成員)放到建構函式中
-
共享成員(一般就是函式)放到原型物件中
-
如果重置了
prototype
記得修正constructor
的指向
繼承
建構函式的屬性繼承:借用建構函式
function Person (name, age) {
this.type = 'human'
this.name = name
this.age = age
}
function Student (name, age) {
// 借用建構函式繼承屬性成員
Person.call(this, name, age)
}
var s1 = Student('張三', 18)
console.log(s1.type, s1.name, s1.age) // => human 張三 18
原型繼承
function Person (name, age) {
this.type = 'human'
this.name = name
this.age = age
}
Person.prototype.sayName = function () {
console.log('hello ' + this.name)
}
function Student (name, age) {
Person.call(this, name, age)
}
// 利用原型的特性實現繼承
Student.prototype = new Person()
var s1 = Student('張三', 18)
console.log(s1.type) // => human
s1.sayName() // => hello 張三
函式宣告與函式表示式的區別
-
函式宣告必須有名字
-
函式宣告會函式提升,在預解析階段就已建立,宣告前後都可以呼叫
-
函式表示式類似於變數賦值
-
函式表示式可以沒有名字,例如匿名函式
-
函式表示式沒有變數提升,在執行階段建立,必須在表示式執行之後才可以呼叫
函式內 this
指向的不同場景
普通函式呼叫 window 嚴格模式下是 undefined
建構函式呼叫 例項物件 原型方法中 this 也是例項物件
物件方法呼叫 該方法所屬物件 緊挨著的物件
事件繫結方法 繫結事件物件
定時器函式 window
函式也是物件
所有函式都是 Function
的例項
call:
call()
方法呼叫一個函式, 其具有一個指定的 this
值和分別地提供的引數(引數的列表)。
注意:該方法的作用和 apply()
方法類似,只有一個區別,就是 call()
方法接受的是若干個引數的列表,而 apply()
方法接受的是一個包含多個引數的陣列。
apply
apply()
方法呼叫一個函式, 其具有一個指定的 this
值,以及作為一個數組(或類似陣列的物件)提供的引數。
<p class="danger"> 注意:該方法的作用和 call()
方法類似,只有一個區別,就是 call()
方法接受的是若干個引數的列表,而 apply()
方法接受的是一個包含多個引數的陣列。
bind
bind() 函式會建立一個新函式(稱為繫結函式),新函式與被調函式(繫結函式的目標函式)具有相同的函式體(在 ECMAScript 5 規範中內建的call屬性)。當目標函式被呼叫時 this 值繫結到 bind() 的第一個引數,該引數不能被重寫。繫結函式被呼叫時,bind() 也接受預設的引數提供給原函式。一個繫結函式也能使用new操作符建立物件:這種行為就像把原函式當成構造器。提供的 this 值被忽略,同時呼叫時的引數被提供給模擬函式。
總結
-
call 和 apply 特性一樣
-
都是用來呼叫函式,而且是立即呼叫
-
但是可以在呼叫函式的同時,通過第一個引數指定函式內部
this
的指向 -
call 呼叫的時候,引數必須以引數列表的形式進行傳遞,也就是以逗號分隔的方式依次傳遞即可
-
apply 呼叫的時候,引數必須是一個數組,然後在執行的時候,會將陣列內部的元素一個一個拿出來,與形參一一對應進行傳遞
-
如果第一個引數指定了
null
或者undefined
則內部 this 指向 window
-
-
bind
-
可以用來指定內部 this 的指向,然後生成一個改變了 this 指向的新的函式
-
它和 call、apply 最大的區別是:bind 不會呼叫
-
bind 支援傳遞引數,它的傳參方式比較特殊,一共有兩個位置可以傳遞
-
-
在 bind 的同時,以引數列表的形式進行傳遞
-
-
-
在呼叫的時候,以引數列表的形式進行傳遞
-
-
那到底以誰 bind 的時候傳遞的引數為準呢還是以呼叫的時候傳遞的引數為準
-
兩者合併:bind 的時候傳遞的引數和呼叫的時候傳遞的引數會合併到一起,傳遞到函式內部
-
-