摘要:的指向只和函數的調用位置方式有關,和函數聲明的位置無關。全局瀏覽器全局這是中的默認綁定,在全局上下文中,會默認綁定到全局對象。同時上面四條綁定規則在箭頭函數中不適用,使得的查找更可控。
本文共 1065 字,讀完只需 4 分鐘概述
在 JAVA 中,this 的概念很透徹,就是指向當前對象(方法和屬性的持有者),在編譯的時候就能確定 this 指代,而由于 JavaScript 中 this 是動態綁定,或稱為運行期綁定的,在絕大多數情況下,函數的調用方式決定了 this 的值,所以在 JS 中不能在定義時決定地定義 this 是哪個上下文對象。
this 的指向只和函數的調用位置(方式)有關,和函數聲明的位置無關。
本文就從 this 應用場景調用方式的角度,解析 this 的用法。
首先,要知道,this 的作用是什么?
函數體內部,指代函數當前的運行上下文。一、全局上下文
在全局上下文中,this 指向全局對象,在瀏覽器中指向 window,在 NodeJs 中指向 global。
var a = "全局"; console.log(this) // 瀏覽器:window console.log(this) // nodejs:global console.log(this.a) // "全局"
這是 JS 中的默認綁定,在全局上下文中,this 會默認綁定到 全局對象。
二、函數聲明在非嚴格模式下,未加關鍵字 var 聲明的變量,會成為全局對象下的屬性,所以,此時
在嚴格模式下,this 將保持他進入執行上下文時的值,所以下面的 this 將會默認為 undefined。
function foo() { "use strict"; console.log(this); } foo(); // undefined 嚴格模式
上述也是 JS 中 this 的默認綁定,在函數定義中,函數中的 this 會默認綁定到全局對象或者 undefined。
當函數作為對象里的方法被調用時,函數中 this 是調用該函數的對象。
function foo() { console.log("foo"); } var obj = { this.bar = "bar"; this.foo = foo; } obj.foo(); // "foo"
在調用位置,是 obj 對象調用了 foo 函數,此時 this 就指向了 obj 對象。
function foo() { console.log(this.bar); } var obj2 = { bar: "2", foo: foo } var obj1 = { bar: "1", obj2: obj2 } obj1.obj2.foo() // "2";
這是 JS 中 this 的隱式綁定,this 會隱式綁定到調用的最近一層上下文對象。
三、call & apply其實在函數中,函數正確的調用應該是用 call, apply 函數的形式。
function foo() { console.log(this.bar); } let obj = { bar: "1", foo: foo } obj.foo(); // `.` 點調用其實是語法糖 foo.call(obj) // 1 正確的姿勢 foo.apply(obj) // 1
這是 JS 中 this 的顯式綁定,函數通過從 call 和 apply 函數可以顯式指定函數的調用對象。
ES5 提供了一個 bind()方法:
let obj2 = { a: 2 } let foo = function () { console.log(this.a); } let bar = foo.bind(obj2); bar() // 2;
就是 JS 中 this 的硬綁定,bind() 函數會返回一個指定了調用對象的函數,返回的函數的被指定了 this 且 this 無法改變。
四、構造函數當函數加上關鍵字 new 后,函數會變成一個構造函數,此時構造函數中的 this 指向即將創建的對象實例,同時對象實例會關聯到構造函數的原型對象 prototype 上。
function Foo() { this.a = 3; } var obj = new Foo(); obj.a // 3五、箭頭函數
ES6 中,提供了函數定義的語法糖,讓定義函數變得更簡潔(沒有 arguments, 沒有原型)。同時上面四條綁定規則在箭頭函數中不適用,使得 this 的查找更可控。
// 一般函數: var a = 1; var obj = { a: 2, say: function() { console.log(this.a) } } obj.say(); // console.log 打印值為 2 // 箭頭函數 var a = 1; var obj = { a: 2, say: () => { console.log(this.a) } } obj.say(); // 1 !!!
由于箭頭函數定義時, obj {} 不是執行上下文,say 變量引用的箭頭函數,其 this 是父級執行上下文,也就是全局上下文,所以 this.a 就是 全局變量 a: 1;
在箭頭函數中,this 與封閉詞法上下文的 this 保持一致,this 被永久綁定到了它最近一層非箭頭函數的 this,而與函數的調用位置無關。
總結在絕大多數情況下,函數的調用方式決定了 this 的值,但最終都指向了調用了它的那個上下文對象。
歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98533.html
摘要:深入系列第七篇,結合之前所講的四篇文章,以權威指南的為例,具體講解當函數執行的時候,執行上下文棧變量對象作用域鏈是如何變化的。前言在深入之執行上下文棧中講到,當代碼執行一段可執行代碼時,會創建對應的執行上下文。 JavaScript深入系列第七篇,結合之前所講的四篇文章,以權威指南的demo為例,具體講解當函數執行的時候,執行上下文棧、變量對象、作用域鏈是如何變化的。 前言 在《Jav...
摘要:也就是說當返回的函數作為構造函數的時候,時指定的值會失效,但傳入的參數依然生效。構造函數效果的優化實現但是在這個寫法中,我們直接將,我們直接修改的時候,也會直接修改函數的。 JavaScript深入系列第十一篇,通過bind函數的模擬實現,帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會創建一個新函數。當這個新函數被調用時,bind() 的第一個參數...
摘要:深入系列第十二篇,通過的模擬實現,帶大家揭開使用獲得構造函數實例的真相一句話介紹運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象類型之一也許有點難懂,我們在模擬之前,先看看實現了哪些功能。 JavaScript深入系列第十二篇,通過new的模擬實現,帶大家揭開使用new獲得構造函數實例的真相 new 一句話介紹 new: new 運算符創建一個用戶定義的對象類型的實例或具...
摘要:深入系列第十五篇,講解各種繼承方式和優缺點。優點融合原型鏈繼承和構造函數的優點,是中最常用的繼承模式。寄生組合式繼承為了方便大家閱讀,在這里重復一下組合繼承的代碼組合繼承最大的缺點是會調用兩次父構造函數。 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎...
摘要:在全局對象中調用,自然讀取的是全局對象的值構造器調用說明作為構造器調用時,指向返回的這個對象。最直觀的表現就是,去看一些優秀框架的源代碼時,不再是被繞的暈乎乎的。 學習起因: 在之前的JavaScript學習中,this,call,apply總是讓我感到迷惑,但是他們的運用又非常的廣泛。遂專門花了一天,來弄懂JavaScript的this,call,apply。中途參考的書籍也很多,以...
摘要:深入系列第十四篇,講解創建對象的各種方式,以及優缺點。也就是說打著構造函數的幌子掛羊頭賣狗肉,你看創建的實例使用都無法指向構造函數這樣方法可以在特殊情況下使用。 JavaScript深入系列第十四篇,講解創建對象的各種方式,以及優缺點。 寫在前面 這篇文章講解創建對象的各種方式,以及優缺點。 但是注意: 這篇文章更像是筆記,因為《JavaScript高級程序設計》寫得真是太好了! 1....
閱讀 3987·2021-09-22 16:03
閱讀 5338·2021-09-22 15:40
閱讀 1196·2021-09-06 15:02
閱讀 874·2019-08-30 15:53
閱讀 2228·2019-08-29 15:35
閱讀 1112·2019-08-23 18:22
閱讀 3342·2019-08-23 16:06
閱讀 650·2019-08-23 12:27