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

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
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。