JavaScript this綁定與this指向問題的解析
一、this 綁定
怎么理解 this?
其實 this 就是一個指針,它指示的就是當前的一個執(zhí)行環(huán)境,可以用來對當前執(zhí)行環(huán)境進行一些操作。
MDN 解釋:在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了 this 的值(運行時綁定)。this 不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時 this 的值也可能會不同。ES5 引入了 bind 方法來設(shè)置函數(shù)的 this 值,而不用考慮函數(shù)如何被調(diào)用的。ES2015 引入了箭頭函數(shù),箭頭函數(shù)不提供自身的 this 綁定(this 的值將保持為閉合詞法上下文的值)。
this 是如何綁定的?
每個函數(shù)的 this 是在調(diào)用時被綁定的,完全取決于函數(shù)的調(diào)用位置。我們找到函數(shù)的調(diào)用位置,然后運用以下四種綁定規(guī)則來判斷函數(shù)的 this 指向。
1、默認綁定
函數(shù)的 this 會默認綁定到全局對象 window 上,如果在嚴格模式中,this 綁定到 undefined。
function foo (){ console.log(this.a) } let a = 1 foo() // 1
2、隱式綁定
調(diào)用位置是否有上下文對象,或者被某個對象擁有或包含。
function foo(){ console.log(this.a) } let obj = { a: 2, foo:foo } let a = 1 obj.foo(); // 2 function foo(){ console.log(this.a) } let obj1 = { a: 2, foo: foo } let obj2 = { a: 3, obj1: obj1 } let a = 1 obj2.obj1.foo(); // 2
3、顯式綁定
直接改變 this 指向,綁定到另一個執(zhí)行環(huán)境
function foo(){ console.log(this.a) } let obj = { a: 1 } foo.call(obj)
4、new 綁定
new 出來的函數(shù) this 綁定的是新創(chuàng)建的對象
function Foo(a){ this.a = a } let bar = new Foo(2) console.log(bar.a) // 2
this 綁定優(yōu)先級
默認綁定的優(yōu)先級是最低的
new 綁定 > 顯式綁定 > 隱式綁定 > 默認綁定
1、顯示綁定 VS 隱式綁定
function foo(){ console.log(this.a) } let obj1 = { a: 1, foo: foo } let obj2 = { a: 2 } console.log(obj1.foo()) // 1 obj1.foo.call(obj2) // 2
通過以上代碼我們可以看到 顯式綁定 的優(yōu)先級高于 隱式綁定
2、顯示綁定 VS new 綁定
function foo(a){ this.a = a } let obj1 = { foo } let bar = foo.bind(obj1) bar(2) console.log(obj1.a) // 2 let bar2 = new bar(3) console.log(obj1.a) // 2 console.log(bar2.a) // 3
new 修改了顯示綁定 調(diào)用 bar 中的 this,所以 new 綁定的優(yōu)先級高于顯式綁定
二、this 指向
判斷準則
第一準則:this 永遠指向函數(shù)運行時所在的對象,而不是函數(shù)被創(chuàng)建時所在的對象。(不包含箭頭函數(shù))
第二準則:無論是否在嚴格模式下,在全局執(zhí)行環(huán)境中(在任何函數(shù)體外部)this 都指向全局對象。
判斷順序
- 函數(shù)是否在 new 中調(diào)用,如果是的話 this 綁定的是新創(chuàng)建的對象;
- 函數(shù)是否通過 call、apply、bind 的方式調(diào)用,如果是的話 this 綁定的是指定的對象;
- 函數(shù)是否在某個上下文中被調(diào)用,如果是的話 this 綁定的是函數(shù)調(diào)用的上下文;
- 除此之外 this 綁定的就是全局對象 在嚴格模式下綁定的是 undefined。
常見的指向問題
- 箭頭函數(shù)沒有自己的 this 指針(需要從執(zhí)行上下文來進行判斷)
三、改變 this 指向
有四種方式
- 變量保存 this:將 this 臨時保存下來
- call():使用一個指定的 this 值和單獨給出的一個或多個參數(shù)來調(diào)用一個函數(shù)。
- bind():會有一個返回值,返回值是一個擁有第一個函數(shù)作用域的新的函數(shù)體
- apply():調(diào)用一個具有給定 this 值的函數(shù),以及以一個數(shù)組(或一個類數(shù)組對象)的形式提供的參數(shù)。
變量保存 this
var _this = window; var obj = { name:"張三", show:function(){ console.log(this) //obj console.log(_this) // window } } obj.show()
call
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數(shù)來調(diào)用一個函數(shù)。
函數(shù)名稱.bind(參數(shù)1,參數(shù)2,a,b,c.....)
參數(shù)1:當前函數(shù)的作用域
參數(shù)2:需要傳遞的參數(shù),參數(shù)是一個一個傳
function fn(a,b){ console.log(this,a,b) } document.onclick = functioin(){ fn.call(document,1,2) }
可以使用 call 來實現(xiàn)繼承:寫一個方法,然后讓另外一個新的對象來繼承它(而不是在新對象中再寫一次這個方法)。
function Product(name, price) { this.name = name; this.price = price; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } var cheese = new Food('feta', 5); var fun = new Toy('robot', 40);
bind
bind 創(chuàng)建一個新的函數(shù),在 bind() 被調(diào)用時,這個新函數(shù)的 this 被指定為 bind() 的第一個參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調(diào)用時使用。
特性就是會有一個返回值,返回值是一個擁有第一個函數(shù)作用域的新的函數(shù)體
函數(shù)名稱.bind(參數(shù)1,參數(shù)2.....)() // 必須調(diào)用一下
參數(shù)1:當前函數(shù)的作用域
參數(shù)2:需要傳遞的參數(shù)
var obj = { name:"張三", show:function(val){ console.log(this) //obj 沒有修改前 console.log(this,1) // document 1 修改后 } } obj.show().bind(document,1)()
MDN:ECMAScript 5 引入了 Function.prototype.bind()。調(diào)用 f.bind(someObject) 會創(chuàng)建一個與 f 具有相同函數(shù)體和作用域的函數(shù),但是在這個新函數(shù)中,this 將永久地被綁定到了 bind 的第一個參數(shù),無論這個函數(shù)是如何被調(diào)用的。
apply
apply() 方法調(diào)用一個具有給定 this 值的函數(shù),以及以一個數(shù)組(或一個類數(shù)組對象)的形式提供的參數(shù)。
函數(shù)名稱.bind(參數(shù)1,[參數(shù)2,a,b,c.....])
參數(shù)1:當前函數(shù)的作用域
參數(shù)2:需要傳遞的參數(shù) 數(shù)組
function fn(a,b,c){ console.log(this,a,b,c) } document.onclick = functioin(){ fn.apply(document,[1,2,3]) }
call ,apply ,bind 三者的區(qū)別
不同點:
- bind 會有一個返回值,返回值是函數(shù)體,因此需要加上 () 才能調(diào)用
- call,apply 是沒有返回值的,當改變函數(shù) this 指向的時候,函數(shù)就會執(zhí)行,不需要加 () 調(diào)用
- call 傳遞參數(shù)的時候是一個一個傳遞的
- apply 是傳遞一個數(shù)組或者類數(shù)組對象的參數(shù)
到此這篇關(guān)于JavaScript this綁定與this指向問題的解析的文章就介紹到這了,更多相關(guān)JavaScript this綁定與this指向內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
webpack使用 babel-loader 轉(zhuǎn)換 ES6代碼示例
本篇文章主要介紹了webpack使用 babel-loader 轉(zhuǎn)換 ES6代碼 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-08-08uni-app h5端在jenkins構(gòu)建報錯解決
這篇文章主要為大家介紹了uni-app h5端在jenkins構(gòu)建報錯解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06JS實現(xiàn)去除數(shù)組中重復json的方法示例
這篇文章主要介紹了JS實現(xiàn)去除數(shù)組中重復json的方法,涉及javascript針對json數(shù)組數(shù)據(jù)的遍歷、判斷、存取等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12