摘要:在等面向對象的語言中,關鍵字的含義是明確且具體的,即指代當前對象。一般在編譯期確定下來,或稱為編譯期綁定。無論是用還是這種方式,都取決于傳入該函數的對象。使用方法綁定使用在創建時綁定指針。如果是行內的事件監聽者,指針會被設置為其所在的元素
this
在 Java 等面向對象的語言中,this 關鍵字的含義是明確且具體的,即指代當前對象。一般在編譯期確定下來,或稱為編譯期綁定。而在 JavaScript 中,this 是動態綁定,或稱為運行期綁定的,這就導致 JavaScript 中的 this 關鍵字有能力具備多重含義,變得有點隨意。而在ES6中又引入了Arrow Function以及Class,它們對于this指針也帶來了一定的影響。
Global Context(全局上下文)在任何函數之外的全局環境中,不管在不在strict模式中,this指針往往指向一個全局變量。
console.log(this.document === document); // true // In web browsers, the window object is also the global object: console.log(this === window); // true this.a = 37; console.log(window.a); // 37Function Context(函數上下文) 簡單調用
在某個函數中,this的值取決于該函數的調用者。無論是用hello("world”)還是call這種方式,都取決于傳入該函數的對象。不過,在ES5的嚴格或者不嚴格模式下,同樣的調用方式會有不同的結果。
function hello(thing) { console.log("Hello " + thing); } // this: hello("world") // desugars to: hello.call(window, "world");
而如果是strict模式下:
// this: hello("world") // desugars to: hello.call(undefined, "world");對象方法
另一種常用的調用函數的方法就是在object中調用:
function hello(thing) { console.log(this + " says hello " + thing); } person = { name: "Brendan Eich" } person.hello = hello; person.hello("world") // still desugars to person.hello.call(person, "world") [object Object] says hello world hello("world") // "[object DOMWindow]world"bind
很多時候,需要為某個函數指定一個固定的this對象,最簡單的方式即是使用閉包來獲取一個不變的this對象。
var person = { name: "Brendan Eich", hello: function(thing) { console.log(this.name + " says hello " + thing); } } var boundHello = function(thing) { return person.hello.call(person, thing); } boundHello("world");
不過,這種方式仍然存在著一定的問題,ES5為Function對象引入了一個新的bind方法來解決這個問題:
var boundHello = person.hello.bind(person); boundHello("world") // "Brendan Eich says hello world"
這種方式在設置回調函數中的this指針的時候會起到很大的作用,特別是在React中,為了保證指針的穩定性,往往需要為內置方法設置bind。
var person = { name: "Alex Russell", hello: function() { console.log(this.name + " says hello world"); } } $("#some-div").click(person.hello.bind(person)); // when the div is clicked, "Alex Russell says hello world" is printedapply/call
在 JavaScript 中函數也是對象,對象則有方法,apply 和 call 就是函數對象的方法。這兩個方法異常強大,他們允許切換函數執行的上下文環境(context),即 this 綁定的對象。很多 JavaScript 中的技巧以及類庫都用到了該方法。讓我們看一個具體的例子:
function Point(x, y){ this.x = x; this.y = y; this.moveTo = function(x, y){ this.x = x; this.y = y; } } var p1 = new Point(0, 0); var p2 = {x: 0, y: 0}; p1.moveTo(1, 1); p1.moveTo.apply(p2, [10, 10]);array.forEach
在這樣一個回調函數中,回調函數的this指針是由調用者決定的,完整的forEach聲明如下:array.forEach(callback[, thisArg]),這個傳入的thisArg即是回調的調用者。
var o={ v:"hello", p:["a1","a2"], f:function f(){ this.p.forEach(function (item){ console.log(this.v+" "+item); }); } } o.f(); //undefined a1 //undefined a2Arrow Function
Arrow Function是ES6新增的特性,很類似于Java或者C#中的Lambda表達式。Arrow函數中的this指針在創建時就被綁定到了閉合的作用域內,不會收到new、bind、call以及apply這些方法的影響。
var o = { traditionalFunc: function () { // Normal function, bound as expected console.log("traditionalFunc this === o?", this === o); }, arrowFunc: () => { // Arrow function, bound to scope where it"s created console.log("arrowFunc this === o?", this === o); console.log("arrowFunc this === window?", this === window); } }; o.traditionalFunc(); // traditionalFunc this === o? true o.arrowFunc(); // arrowFunc this === o? false // arrowFunc this === window? true
上述代碼中的arrowFunc隸屬于o對象,但是在window的作用域中被創建,因此,最終arrow函數中的this指針的值等于window對象。ES5中的對于this的控制已然非常復雜,特別是在處理異步代碼中如何傳入合適的this對象也是一件麻煩事,如下文所示:
var asyncFunction = (param, callback) => { window.setTimeout(() => { callback(param); }, 1); }; // With a traditional function if we don"t control // the context then can we lose control of `this`. var o = { doSomething: function () { // Here we pass `o` into the async function, // expecting it back as `param` asyncFunction(o, function (param) { // We made a mistake of thinking `this` is // the instance of `o`. console.log("param === this?", param === this); }); } }; o.doSomething(); // param === this? false
為了綁定上述代碼中的this指針,一般來說有三個辦法:
為this指針創建一個固定的引用。
var asyncFunction = (param, callback) => { window.setTimeout(() => { callback(param); }, 1); }; // Define a reference to `this` outside of the callback, // but within the callback"s lexical scope var o = { doSomething: function () { var self = this; // Here we pass `o` into the async function, // expecting it back as `param` asyncFunction(o, function (param) { console.log("param === this?", param === self); }); } }; o.doSomething(); // param === this? true
使用bind方法綁定this
var asyncFunction = (param, callback) => { window.setTimeout(() => { callback(param); }, 1); }; // Here we control the context of the callback using // `bind` ensuring `this` is correct var o = { doSomething: function () { // Here we pass `o` into the async function, // expecting it back as `param` asyncFunction(o, function (param) { console.log("param === this?", param === this); }.bind(this)); } }; o.doSomething(); // param === this? true
使用Arrow Function在創建時綁定this指針。
var asyncFunction = (param, callback) => { window.setTimeout(() => { callback(param); }, 1); }; var o = { doSomething: function () { // Here we pass `o` into the async function, // expecting it back as `param`. // // Because this arrow function is created within // the scope of `doSomething` it is bound to this // lexical scope. asyncFunction(o, (param) => { console.log("param === this?", param === this); }); } }; o.doSomething(); // param === this? trueDOM Event handler(Dom事件)
當某個函數作為事件監聽器時,它的this值往往被設置為它的調用者。
// When called as a listener, turns the related element blue function bluify(e){ // Always true console.log(this === e.currentTarget); // true when currentTarget and target are the same object console.log(this === e.target); this.style.backgroundColor = "#A5D9F3"; } // Get a list of every element in the document var elements = document.getElementsByTagName("*"); // Add bluify as a click listener so when the // element is clicked on, it turns blue for(var i=0 ; i如果是行內的事件監聽者,this指針會被設置為其所在的DOM元素:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86029.html
摘要:擴展運算符是以下簡稱中又一非常好用的實戰技術它的寫法只需要三個點作用則顧名思義用來展開你想要使用的任意變量本質上是對所有擁有迭代器接口的對象進行迭代。 擴展運算符(spreading)是 ECMASCRIPT 6(以下簡稱ES 6) 中又一非常好用的實戰技術, 它的寫法只需要三個點(...),作用則顧名思義,用來展開你想要使用的任意變量,本質上是對所有擁有迭代器接口(Iterator)...
摘要:相信解構賦值自以下簡稱面世以來被大家快速地熟悉并運用到實際開發中了這是一種能有效減少代碼量,使代碼邏輯更簡單優雅的技術下面我們就再來回顧總結一下解構賦值的種種用法吧基本用法從對象解構假設有一個對象,它的結構為以對稱的形式從從邊的對象中匹配與 相信解構賦值(Destructuring)自 ECMASCRIPT 6(以下簡稱 ES 6) 面世以來被大家快速地熟悉并運用到實際開發中了, 這是...
摘要:前端培訓初級階段語法變量值類型運算符語句前端培訓初級階段內置對象函數前端培訓初級階段類模塊繼承基礎內容知識我們會用到。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思想,我們開課啦(每周四)。 該文為前端培訓-初級階段(1...
摘要:執行函數調用規范中的第一步是一個明顯的賦值語句,我們查看規范,賦值語句會發生什么可以看出簡單賦值語句返回的是對等于號右邊進行之后的結果,上一節講了,執行過就會返回的類型,此處會返回也就是一個類型。 前言 this是JavaScript中的著名月經題,每隔一段時間就有人翻出了拿各種奇怪的問題出來討論,每次都會引發一堆口水之爭。從搜索引擎搜了一下現在的比較熱門的關于this的用法,如:Ja...
摘要:插件開發前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內優雅的實現文件分片斷點續傳。 Vue.js 插件開發 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....
閱讀 3043·2021-11-25 09:43
閱讀 1626·2021-11-24 11:15
閱讀 2359·2021-11-22 15:25
閱讀 3501·2021-11-11 16:55
閱讀 3240·2021-11-04 16:10
閱讀 2773·2021-09-14 18:02
閱讀 1685·2021-09-10 10:50
閱讀 1070·2019-08-29 15:39