前言
JS 是一種腳本語言雷滋,因此被很多人認(rèn)為是簡單易學(xué)的。然而情況可能與之相悖臼勉,JS 遵從函數(shù)式編程邻吭、閉包、基于原型的繼承等高級(jí)功能宴霸。本文介紹一下JS中的 this 關(guān)鍵字囱晴,可以這樣說,正確掌握了 JS 中的 this 關(guān)鍵字瓢谢,才算邁入了 JS 這門語言的門檻畸写。
注: 本文采用部分 es6 進(jìn)行代碼分析
Java工程師所熟識(shí)的this
在 Java 中定義類經(jīng)常會(huì)使用 this 關(guān)鍵字,多數(shù)情況下是為了避免命名沖突氓扛,比如在下面例子的中枯芬,定義一個(gè) Image 類,很自然的采郎,大家會(huì)使用 width千所、height 為其屬性或成員變量命名,在構(gòu)造函數(shù)中蒜埋,使用 width淫痰、height 為參數(shù)命名。無論哪種情況理茎,this 的含義是一樣的黑界,均指當(dāng)前類對(duì)象管嬉,當(dāng)調(diào)用構(gòu)造方法時(shí)全局變量width、height的值會(huì)被修改朗鸠。
public class Image {
private int width = 0;
private int height = 0;
public Image(int width, int height) {
this.width = width;
this.height = height;
}
public void println() {
System.out.println("width = " + this.width);
System.out.println("height = " + this.height);
}
}
調(diào)用方式如下:
Image image = new Image(10, 10);
image.println();
輸出結(jié)果:
width = 10
height = 10
Process finished with exit code 0
可以看得出來this.x 與 this.y 直接修改的全局變量的值蚯撩,也證明了我們上面的觀點(diǎn)~
JS語言中的 this
由于JS等腳本語言運(yùn)行期進(jìn)行解釋的特性,JS 中的 this 含義要豐富得多烛占,它可以是全局對(duì)象胎挎、當(dāng)前對(duì)象或者任意對(duì)象,這完全取決于函數(shù)的調(diào)用方式忆家。
JS 中函數(shù)的調(diào)用有以下幾種方式:
1犹菇、作為對(duì)象方法調(diào)用
2、作為函數(shù)調(diào)用
3芽卿、作為構(gòu)造函數(shù)調(diào)用
4揭芍、使用 apply 或 call 調(diào)用
接下來我們按照調(diào)用方式的不同,分別討論 this 的含義卸例。
作為對(duì)象方法調(diào)用
var image = {
width : 0,
height : 0,
update : function(width, height) {
this.width = this.width + width
this.height = this.height + height
}
}
// this 綁定到當(dāng)前對(duì)象称杨,即 image 對(duì)象
// 執(zhí)行此方法后image的width與Height屬性值變?yōu)?
image.update(1, 1)
作為函數(shù)調(diào)用
當(dāng)調(diào)用函數(shù)時(shí),此時(shí) this 綁定到全局對(duì)象筷转,在瀏覽器中姑原,window 就是該全局對(duì)象,例如下面:setLocalValue 函數(shù)被調(diào)用時(shí)呜舒,this 被綁定到全局對(duì)象锭汛,接下來執(zhí)行賦值語句,相當(dāng)于隱式的聲明了一個(gè)全局變量袭蝗,這顯然不是調(diào)用者希望的效果~
function setLocalValue(value) {
this.localValue = value
}
setLocalValue(5)
// localValue 已經(jīng)聲明成一個(gè)值為 5 的全局變量
console.log(localValue) // ==> 5
對(duì)于內(nèi)部函數(shù)唤殴,即聲明在一個(gè)函數(shù)體內(nèi)的函數(shù),這種綁定到全局對(duì)象的方式會(huì)衍生出一個(gè)新的問題呻袭,我們?nèi)匀灰郧懊嫣岬降?image 對(duì)象為例眨八,這次我們希望在 update 方法內(nèi)定義兩個(gè)函數(shù)腺兴,分別將 width左电、height 屬性進(jìn)行修改。結(jié)果可能出乎大家意料页响,不僅 image 對(duì)象沒有移動(dòng)篓足,反而多出兩個(gè)全局變量 width、height闰蚕。
var image = {
width : 0,
height : 0,
update : function(width, height) {
// 內(nèi)部函數(shù)
var updateWidth = function(width) {
//this 綁定到了哪里栈拖?
this.width = width;
}
// 內(nèi)部函數(shù)
var updateHeight = function(height) {
//this 綁定到了哪里?
this.height = height;
}
updateWidth(width)
updateHeight(height)
}
}
image.update(1, 1)
console.log(image.width) // ==> 0
console.log(image.height) // ==> 0
console.log(width) // ==> 1
console.log(height) // ==> 1
這屬于 JS 語言的設(shè)計(jì)缺陷没陡,正確的設(shè)計(jì)方式是內(nèi)部函數(shù)的 this 應(yīng)該綁定到其外層函數(shù)對(duì)應(yīng)的對(duì)象上涩哟,為了規(guī)避這一設(shè)計(jì)缺陷索赏,我們一般采用變量替換的方法,該變量草民習(xí)慣命名為成 self~
var image = {
width : 0,
height : 0,
update : function(width, height) {
var self = this
// 內(nèi)部函數(shù)
var updateWidth = function(width) {
self.width = width;
}
// 內(nèi)部函數(shù)
var updateHeight = function(height) {
self.height = height;
}
updateWidth(width)
updateHeight(height)
}
}
image.update(1, 1)
console.log(image.width) // ==> 1
console.log(image.height) // ==> 1
這樣就達(dá)到了我們想要的效果~
作為構(gòu)造函數(shù)調(diào)用
JS 支持面向?qū)ο缶幊烫耍c主流的面向?qū)ο笫骄幊陶Z言不同潜腻。
:es6之前JS 并沒有類(class)的概念,而是使用基于原型(prototype)的繼承方式器仗,JS 中的構(gòu)造函數(shù)也很特殊融涣,如果不使用 new 調(diào)用,則和普通函數(shù)一樣精钮,作為又一項(xiàng)約定俗成的準(zhǔn)則威鹿,構(gòu)造函數(shù)以大寫字母開頭,提醒調(diào)用者使用正確的方式調(diào)用轨香,如下es5示例忽你。
:es6之后支持了class的概念,重寫constructor方法臂容,this 綁定到新創(chuàng)建的對(duì)象上檀夹。
es5示例 :
function Image(width, height){
this.width = width
this.height = height
}
var img1 = new Image(10, 10)
es6 示例 :
class Image {
constructor(width, height) {
this.width = width
this.height = height
}
}
let img1 = new Image(10, 10)
使用 apply 或 call 調(diào)用
此次著重強(qiáng)調(diào)一下,在 JS 語言中函數(shù)也是對(duì)象策橘,對(duì)象則有行為(方法)炸渡,apply 和 call 就是函數(shù)對(duì)象的方法。這兩個(gè)方法功能超級(jí)強(qiáng)大丽已,它們?cè)试S切換函數(shù)執(zhí)行的上下文環(huán)境(context)蚌堵,即 this 指向的對(duì)象,在很多JS庫中也得到了廣泛應(yīng)用~
class Image {
constructor(width, height) {
this.width = width
this.height = height
}
update(width, height) {
this.width = width
this.height = height
}
}
let img1 = new Image(0, 0)
let img2 = {width: 0, height: 0}
img1.update(10, 10)
// img2 width沛婴、height ==> 20
img1.update.apply(img2, [20, 20])
// img2 width吼畏、height ==> 20
img1.update.call(img2, 20, 20)
在上面的例子中,我們使用構(gòu)造函數(shù)生成了一個(gè)對(duì)象 img1嘁灯,該對(duì)象同時(shí)具有 update 方法泻蚊,同時(shí)定義了另一個(gè)對(duì)象 img2,使用 apply 可以將 img1 的方法應(yīng)用到 img2 上丑婿,這時(shí)候 this 也被綁定到對(duì)象 img2 上性雄。
結(jié)語:
JS之this關(guān)鍵字就介紹到這里,謝謝大家的觀看羹奉,希望對(duì)大家有所幫助~