首頁 web前端 js教程 Javascript this 的一些學習總結_javascript技巧

Javascript this 的一些學習總結_javascript技巧

May 16, 2016 pm 05:51 PM
javascript this

1.1.1 摘要
相信有C 、C#或Java等程式設計經驗的各位,對於this關鍵字再熟悉不過了。由於Javascript是一種物件導向的程式語言,它和C 、C#或Java一樣都包含this關鍵字,接下來我們將向大家介紹Javascript中的this關鍵字。
本文目錄
全域程式碼中的this
函數中的this
引用型別
函式呼叫以及非引用型別
引用型別以及this的null值
函式作為建構器被呼叫時this的值
手動設定函數呼叫時this的值

1.1.2 正文

由於許多物件導向的程式語言都包含this關鍵字,我們會很自然地把this和物件導向的程式設計方式連結在一起,this通常指向利用建構器新創建出來的物件。而在ECMAScript中,this不只用來表示創建出來的對象,也是執行上下文的屬性:
複製程式碼



複製程式碼


複製程式碼

代碼如下: activeExecutionContext = { // Variable object. VO: {...}, this: thisValue
};



全域程式碼中的this




複製程式碼


程式碼如下:


程式碼如下:


/ Global scope
// The implicit property of
// the global object
foo1 = "abc";
alert(foo1); // abc
// The explicit property of
// the global object
this.foo2 = "def"; alert(foo2); // def // The implicit property of // the global object var foo3 = "ijk"; alert(foo3); // ijk
前面我們透過顯式和隱式定義了全域屬性foo1、foo2和foo3,由於this在全域上下文中,所以它的值是全域物件本身(在瀏覽器中是window object);接下來我們將介紹函數中的this。
函數中的this
當this在函數程式碼中,情況就複雜多了,並且會引發很多的問題。
函數程式碼中this值的第一個特性(同時也是最主要的特性)就是:它並非靜態的綁定在函數上。
正如先前所提到的,this的值是在進入執行上下文(Excution context)的階段確定的,並且在函數程式碼中的話,其值每次都不盡相同。
然而,一旦進入執行程式碼階段,其值就不能改變了。如果要想給this一個新的值是不可能的,因為在那時this根本就不是變數了。
接下來,我們透過具體的例子來說明函數中的this。
首先我們定義兩個物件foo和person,foo包含一個屬性name,而person包含屬性name和方法say(),具體的定義如下:




複製程式碼


程式碼如下:


// Defines foo object.
var foo = {
name: "Foo"
}; 🎜>// Defines person object.
var person = {
name: "JK_Rush",
say: function() { alert(this === person); alert() { alert(this === person); alert( "My name is " this.name); } };
person.say(); // My name is JK_Rush
// foo and person object refer to
// the same function say
foo.say = person.say;
foo.say(); // My name is Foo.


透過上面的程式碼,我們發現呼叫person的say()方法時,this指向person對象,當透過賦值方式使得foo的say()方法指向peson中的say()方法。我們呼叫foo的say()方法,發現this不是指向person對象,而不是指向foo對象,這究竟是什麼原因呢?
首先,我們必須知道this的值在函數中是非靜態的,它的值確定在函數調用時,具體程式碼執行前,this的值是由激活上下文程式碼的呼叫者決定的,比如說,調用函數的外層上下文;更重要的是,this的值是由呼叫表達式的形式決定的,所以說this並非靜態的綁定在函數上。
由於this並非靜態地綁定在函數上,那麼我們是否可以在函數中動態地修改this的值呢?




複製程式碼

程式碼如下: // Defines foo object. { name: "Foo" }; // Defines person object. var person = { name: "JK_Rush", say: function() { alert(this === person); this = foo; // ReferenceError alert("My name is " this.name); } }; person.say (); // My name is JK_Rush
現在我們在方法say()中,動態地修改this的值,當我們重新執行以上程式碼,發現this的值引用錯誤。這是由於一旦進入執行程式碼階段(函數呼叫時,具體程式碼執行前),this的值就確定了,所以不能改變了。
引用類型
前面我們提到this的值是由啟動上下文程式碼的呼叫者決定的,更重要的是,this的值是由呼叫表達式的形式決定的;那麼表達式的形式是如何影響this的值呢?
首先,讓我們介紹一個內部類型-引用類型,它的值可以用偽代碼表示為一個擁有兩個屬性的物件分別是:base屬性(屬性所屬的物件)以及該base物件中的propertyName屬性:
複製程式碼 程式碼如下:

// Reference type.


// Reference type. = {
base: mybase,
propertyName : 'mybasepropertyName'
};


引用類型的值只有可能是以下兩種情況:
當處理一個標識符的時候
或是進行屬性存取的時候
標識符其實就是變數名、函數名、函數參數名、全域物件的未受限的屬性。 複製程式碼
程式碼如下:


// Declares varible.


// Declares varible.
var foo = 23232 ;
// Declares a function
function say() {
// Your code.
複製程式碼


程式碼如下:


// Reference type.
var fooRefer>var fooRefer. >base: global,
propertyName: 'foo'
};
var sayReference = {
base: global,
propertyName: 'say'
}; 複製程式碼



複製程式碼

程式碼如下:
// Invokes the say method. foo.say(); foo['say'](); 由於say( )方法是識別符,所以它對應foo物件參考型別如下:



複製程式碼


程式碼如下:



程式碼如下: 程式碼如下:


// Reference type.
var fooSayReference = {
base: foo,
propertyName: 'say'
};


我們發現say()方法的base屬性值為foo對象,那麼它對應的this屬性也會指向foo對象。
假設,我們直接呼叫say()方法,它對應的參考類型如下:


複製程式碼 程式碼如下:
// Reference type.
var sayReference = {
base: global,
propertyName: 'say'
};

propertyName: 'say'
};

由於🎜>由於🎜>因為; say()方法的base屬性值為global(通常來說是window object),那麼它對應的this屬性也會指向global。
函數上下文中this的值是函數呼叫者提供並且由目前呼叫表達式的形式而定的。如果在呼叫括號()的左邊有引用類型的值,那麼this的值就會設定為該引用類型值的base物件。 所有其他情況下(非引用類型),this的值總是null。然而,由於null對於this來說沒有任何意義,因此會隱式轉換為全域物件。 函數呼叫以及非引用型別 前面我們提到,當呼叫括號左側為非引用型別的時,this的值會設定為null,最後隱式轉換為全域物件。 現在我們定義了一個匿名自執行函數,具體實作如下:
複製程式碼 程式碼如下: // Declares anonymous function (function () { alert(this); // null => global })(); 由於 因括號()左邊的匿名函數是非引用型別物件(它既不是識別碼也不屬於屬性存取),因此,this的值設定為全域物件。 複製程式碼 程式碼如下:

// Declares object.
var foo = {
bar: function () {
alert(this);
}
};
(foo. bar)(); // foo.
(foo.bar = foo.bar)(); // global?
(false || foo.bar)(); // global?
( foo.bar, foo.bar)(); // global

這裡注意到四個表達式中,只有第一個表達式this是指向foo物件的,而其他三個表達式則執行global。
現在我們又有疑問了:為什麼屬性訪問,但是最終this的值不是引用型別物件而是全域物件呢?
我們注意到表達式二是賦值(assignment operator),與表達式一組運算子不同的是,它會觸發呼叫GetValue方法(參見11.13.1中的第三步)。 最後回傳的時候就是一個函數物件了(而不是引用型別的值了),這表示this的值會被設定為null,最後會變成全域物件。
第三和第四種情況也是類似的-逗號運算子和OR邏輯表達式都會觸發呼叫GetValue方法,於是相應地就會失去原先的引用型別值,變成了函數型,this的值就變成全了全局對象了。
引用型別以及this的null值
對於前面提及的情形,還有例外的情況,當呼叫表達式左邊是引用型別的值,但是this的值卻是null,最後變成全域物件(global object)。 發生這種情況的條件是當引用類型值的base物件恰好為活躍物件(activation object)。
當內部子函數在父函數中被呼叫的時候就會發生這種情況,透過下面的示意程式碼介紹活躍物件:
複製程式碼 程式碼如下:

// Declares foo function.
function foo() {
function bar() {
alert(this); / global
}
// The same as AO.bar().
bar();
}

由於活躍物件(activation object)總是會傳回this值為-null(用偽代碼表示AO.bar()就相當於null.bar()),然後,this的值最後會由null轉變為全域物件。
當函數呼叫包含在with語句的程式碼區塊中,且with物件包含一個函數屬性的時候,就會出現例外的情況。 with語句會將該物件加入到作用域鏈的最前面,在活躍物件的之前。 相應地,在引用類型的值(標識符或屬性存取)的情況下,base物件就不再是活躍物件了,而是with語句的物件。另外,值得一提的是,它不只針對內部函數,全域函數也是如此, 原因就是with物件掩蓋了作用域鏈中更高層的物件(全域物件或活躍物件):
函數作為建構器被呼叫時this的值
函數當作建構子時,我們透過new運算子建立實例物件是,它會呼叫Foo()函數的內部[[Construct]]方法;在物件建立之後,會呼叫內部的[[Call]]方法,然後所有Foo()函數中this的值會設定為新建立的物件。
複製程式碼 程式碼如下:

// Declares constructor


// Declares constructor
function Foo()
// The new object.
alert(this);
this.x = 10;
}
var foo = new Foo();
foo.x = 23;
alert(foo.x); // 23手動設定函數呼叫時this的值

Function.prototype原型上定義了兩個方法,允許手動指定函數呼叫時this的值。這兩個方法分別是:.apply()和.call()。這兩個方法都接受第一個參數作為呼叫上下文中this的值,而這兩個方法的區別是傳遞的參數,對於.apply()方法來說,第二個參數接受數組類型(或者是類數組的對象,例如arguments), 而.call()方法接受任意多的參數(透過逗號分隔);這兩個方法只有第一個參數是必要的-this的值。 透過範例程式碼介紹call()方法和apply()方法的使用: 複製程式碼

程式碼如下:


var myObject = {};
var myFunction = function(param1, param2) {
//setviacall()'this'points to my Object when function is invoked
this. foo = param1;
this.bar = param2;
//logs Object{foo = 'foo', bar = 'bar'}
console.log(this);
};
};
}; >// invokes function, set this value to myObject
myFunction.call(myObject, 'foo', 'bar'); // logs Object {foo = 'foo', bar = 'bar'} console.log(myObject);
call()方法第一個參數是必要的this值,接著我們可以傳遞任意多個參數,接著介紹apply()方法的使用。
複製程式碼 程式碼如下:

var myObject = {};


var myObject = {};
var myFunction = function(param1, param2) {
//set via apply(), this points to my Object when function is invoked
this.foo=param1;
this.bar=param2
; logs Object{foo='foo', bar='bar'}
console.log(this);
};
// invoke function, set this value
myFunction.apply(myObject, ['foo', 'bar']);
// logs Object {foo = 'foo', bar = 'bar'}
console.log(myObject);

透過與call()方法對比,我們發現apply()方法和call()方法沒有太大的區別,只是方法簽名不一樣。

1.1.3 總結


本文介紹Javascript中this的使用,更重要的是幫助我們能更好地理解this值在全局、函數、建構函數以及一些特例的情況中位數的變化。

對於在函數上下文中this的值是函數呼叫者提供並且由當前呼叫表達式的形式而定的。如果在呼叫括號()的左邊有引用類型的值,那麼this的值就會設定為該引用類型值的base物件。 所有其他情況下(非引用類型),this的值總是null。然而,由於null對於this來說沒有任何意義,因此會隱式轉換為全域物件。
對於特例情況,我們要記住賦值符、逗號運算子以及||邏輯表達式,會使this丟失原先的引用類型值,變成了函數類型,this的值就變成了全域物件了參考
[1] http://dmitrysoshnikov.com/ecmascript/chapter-3-this/ 英文版
[2] http:// blog.goddyzhao.me/post/11218727474/this 翻譯
[3]
https://net.tutsplus.com/tutorials/javascript-ajax/fully-understanding-the-this-keyplus.com/tutorials/javascript-ajax/fully-understanding-the-this-keyplusword/ [作者]: JK_Rush
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1317
25
PHP教程
1268
29
C# 教程
1246
24
如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles