日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

深入理解JS中this关键字

發(fā)布時間:2025/3/20 javascript 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解JS中this关键字 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

為什么要使用this關(guān)鍵字

???看個例子

function indetify() {retun this.name.toUpperCase()}var obj = {name: 'zz'}indetify.call(obj) // 'ZZ' 復(fù)制代碼

這里函數(shù)identify中的this指向變量obj,如果不使用this的話,想實現(xiàn)這種效果,就需要顯示的傳入上下文對象,例如

function indetify(context) {retun context.name.toUpperCase()}var obj = {name: 'zz'}indetify(obj) // 'ZZ' 復(fù)制代碼

當(dāng)模式越來越復(fù)雜的時候,顯示的傳遞上下文對象就會變得不太好管理,而this提供了一種更優(yōu)雅的方式,隱式的"傳遞"一個對象的引用,因此可以將API設(shè)計的更加簡潔并且易于復(fù)用。

對于this的誤解

  • this指向自身
  • this指向函數(shù)作用域(需要明確的是,this在任何情況下都不指向函數(shù)的詞法作用域)
  • this到底是什么

    this是在運行的時候被綁定的,并不是編寫的時候,它的上下文取決于函數(shù)調(diào)用的各種條件。當(dāng)一個函數(shù)被調(diào)用時,會創(chuàng)建一個活動記錄(即執(zhí)行上下文),這個記錄包含函數(shù)的調(diào)用棧(call Stack),調(diào)用方式,傳入?yún)?shù)等信息,this就是這個記錄的一個屬性,在函數(shù)執(zhí)行的過程中找到。

    要想找到this的綁定對象,首先得找到函數(shù)的調(diào)用位置,調(diào)用位置就在當(dāng)前執(zhí)行函數(shù)的前一個調(diào)用中。

    function baz () {// 當(dāng)前調(diào)用棧是baz// 當(dāng)前調(diào)用位置是全局作用域console.log('baz')bar() // bar的調(diào)用位置}function bar () {// 當(dāng)前的調(diào)用棧是baz -> bar// 所以當(dāng)前的調(diào)用位置在baz中console.log('bar')foo() // foo的調(diào)用位置}function foo () {// 當(dāng)前的調(diào)用棧是baz -> bar -> foo// 所以當(dāng)前的調(diào)用位置在bar中console.log('foo')}baz() // baz的調(diào)用位置 復(fù)制代碼

    找到調(diào)用位置,接下來就要分析this的綁定規(guī)則了。

    this綁定規(guī)則

  • 默認(rèn)綁定規(guī)則
  • function foo () {console.log(this.a) }var a = 1foo() // 1 復(fù)制代碼

    因為foo()是直接不帶任何修飾的函數(shù)引用進行調(diào)用的,所以只能使用默認(rèn)綁定。非嚴(yán)格模式下指向window,嚴(yán)格模式下綁定到undefined

  • 隱私綁定規(guī)則
  • 分析隱式綁定時,必須在一個對象內(nèi)部包含一個指向函數(shù)的屬性,通過這個屬性間接引用函數(shù)

    function foo () {console.log(this.a) }var obj = {a: 2,foo: foo }obj.foo() // 2 復(fù)制代碼

    首先要聲明的是,無論foo函數(shù)是先聲明還是直接在obj對象中定義,這個函數(shù)嚴(yán)格來說,都不屬于obj對象。

    隱式綁定會遇到一個問題,就是會丟失綁定對象,也就是會應(yīng)用默認(rèn)綁定。比如

    function foo () {console.log(this.a) }var obj = {a: 2,foo: foo }var another = obj.foo // 函數(shù)別名var a = '隱式丟失'obj.foo() // 2 another() // '隱式丟失' 復(fù)制代碼

    這里雖然bar是obj.foo的一個引用,但實際上引用的是foo函數(shù)本身,因此bar()是不帶任何修飾的函數(shù)調(diào)用,所以也是默認(rèn)綁定。

    還有一種更微妙的情況,發(fā)生在傳入回調(diào)函數(shù)的時候

    function foo () {console.log(this.a) }var obj = {a: 2,foo: foo }function doFun (fn) {// fn 其實是引用foo// 相當(dāng)于var fn = foofn() }var a = '又隱式丟失'obj.foo() // 2 doFun(obj.foo) // '又隱式丟失' 復(fù)制代碼

    實際上傳遞參數(shù),實際上就是一種賦值操作,所以結(jié)果和上面一樣

  • 顯示綁定規(guī)則
  • 通常情況,我們使用js提供的call和apply方法實現(xiàn)顯示綁定

    這倆個方法的第一個參數(shù)是一個對象,是給this準(zhǔn)備的,在調(diào)用函數(shù)是將函數(shù)綁定到this,因此稱為顯示綁定。第二個參數(shù)就是一個參數(shù)列表或參數(shù)對象,就是傳遞函數(shù)的調(diào)用的參數(shù)。

    function foo (name) {console.log(this.a+name) }var obj = {a: 1 }foo.call(obj,'顯示綁定') // 1'顯示綁定' 復(fù)制代碼

    但是,顯示綁定還是會出現(xiàn)綁定丟失的情況,能有辦法解決嗎?當(dāng)然有

    • 硬綁定
    function foo () {console.log(this.a) }var obj = {a: 1 }var bar = function () {foo.call(obj) }var a = '會丟失嗎'bar() // 1// 現(xiàn)在不會丟失了setTimeOut(bar, 1000) // 1 bar.call(window) // 1 復(fù)制代碼

    我們創(chuàng)建了函數(shù)bar(),并且在內(nèi)部手動調(diào)用foo.call(obj),強制將foo的this綁定到了obj,無論后面如何調(diào)用函數(shù)bar,都會手動在obj上調(diào)用foo

    • API調(diào)用的“上下文”

    js語言和宿主環(huán)境中許多新的內(nèi)置函數(shù),都提供了一個可選參數(shù),通常稱為“上下文”(context),作用和bind(..)一樣,確保回調(diào)函數(shù)使用指定的this

    function foo (el) {console.log(el, this.id)}var obj = {id: 'awesome'}// 調(diào)用foo的同時把this綁定到obj上[1,2,3].forEach(foo, obj)// 1'awesome' 2'awesome' 3'awesome' 復(fù)制代碼
  • new綁定規(guī)則
  • js中的new的機制和面向類的語言完全不同

    我們習(xí)慣把new的函數(shù)叫做構(gòu)造函數(shù),實際上,只是使用new操作符時被調(diào)用的函數(shù),不會實例化一個類,因為實例化的類與類之間是復(fù)制,是兩位完全沒關(guān)系的,但js不是。只能說這些函數(shù)是被new操作符調(diào)用的普通函數(shù)而已。

    首先,我們看看new操作符會做些什么

  • 創(chuàng)建(或者說構(gòu)造)一個全新的對象

  • 這個對象會被執(zhí)行[[prototypt]]鏈(原型鏈)

  • 新的對象會綁定到函數(shù)調(diào)用的this上

  • 如果函數(shù)沒有返回對象,那new表達式中的函數(shù)會自動返回這個新對象

  • function foo (a) {console.log(a)}var bar = new foo(1)bar() // 1 復(fù)制代碼

    優(yōu)先級

    既然this有這么多種綁定方式,肯定會存在綁定的優(yōu)先級

    首先,毫無疑問,默認(rèn)綁定的優(yōu)先級是最低的

  • 那隱式綁定和顯示綁定的優(yōu)先級誰高?
  • funtion foo (){console.log(this.a)}var obj1 = {a: 1,foo: foo}var obj2 = {a: 2,foo: foo}obj1.foo() // 1obj2.foo() // 2// 顯示綁定改變了this的指向obj1.foo.call(obj2) // 2obj.foo.call(obj1) // 1 復(fù)制代碼

    很顯然,顯示綁定的優(yōu)先級比隱式綁定的高。

  • 隱式綁定和new綁定誰的優(yōu)先級高
  • function foo (something) {this.a = somethig}var obj1 = {foo: foo}var obj2 = {}obj1.foo(1)console.log(obj1.a) // 1obj1.foo.call(obj2, 2)console.log(obj2.a) // 2var bar = new obj1.foo(3)console.log(obj2.a) // 2console.log(bar.a) // 3復(fù)制代碼

    看來new綁定的優(yōu)先級是比隱式綁定高的,最后我們看一下new和顯示綁定誰的優(yōu)先級高,因為new和call/apply無法一起使用,所以沒法通過new foo.call(obj1)來直接測試,我們選擇用硬綁定來測試。

    回憶一下硬綁定是如何工作的,Function.prototype.bind(..)會創(chuàng)建一個新的包裝函數(shù),這個函數(shù)會忽略它當(dāng)前的this綁定,并把提供的對象綁定到this上。

  • new和顯示綁定誰的優(yōu)先級高
  • function foo (something) {this.a = somethig}var obj1 = {}var bar = foo.bind(obj1)bar(1)console.log(bar.a) // 1var baz = new bar(2)console.log(obj1.a) // 1console.log(baz.a) // 2復(fù)制代碼

    bar被硬綁定到obj1上,但是new bar(2),并沒有將obj1.a修改成2,相反,new修改了硬綁定(到obj1的)調(diào)用bar(..)中的this。這樣看來new調(diào)用的函數(shù),新創(chuàng)建的this替換了硬綁定的參數(shù),所以new的優(yōu)先級是最高的。

    那我們判定優(yōu)先級的方法就是從優(yōu)先級由高往下去判定。

    綁定例外

    凡事都有例外,不是所有的綁定都遵循這個規(guī)則的。

  • 如果是call(null)或者apply(undefined),這里對應(yīng)的其實是默認(rèn)綁定,因為其實,null和undefined只是基礎(chǔ)的數(shù)據(jù)類型,并不是對象。

  • 軟綁定

  • 硬綁定可以強制綁定到指定對象,但是這大大降低了函數(shù)的靈活性,之后無法使用隱式或顯示綁定修改this的指向,所以我們來實現(xiàn)一下軟綁定

    // 實現(xiàn)軟綁定if (!Function.prototype.softBind) {Function.prototype.softBind = function (obj) {var fn = this// 捕獲所有curried參數(shù)var curried = [].slice.call(arguments, 1)var bound = function () {return fn.apply((!this || this === (window || global)) ?obj : this,curried.concat.apply(curried, arguments))}bound.prototype = Object.create(fn.prototype)return bound}}// 驗證function foo () {console.log("name: " + this.name)}var obj1 = { name: "obj1"}var obj2 = { name: "obj2"}var obj3 = { name: "obj3"}var fooOBJ = foo.softBind(obj)fooOBJ() // "obj"obj2.foo = foo.softBind(obj)obj2.foo() // "obj2"fooOBJ.call(obj3) // "obj3"setTimeOut(obj2.foo, 10) // "obj" 復(fù)制代碼

    可以看到,軟綁定的foo()可以手動的將this綁定到obj2或者obj3,但如果應(yīng)用默認(rèn)綁定則將this綁定到obj1上。

  • this詞法
  • 此前的4條規(guī)則使用與大部分函數(shù),但在ES6中的箭頭函數(shù)卻不適用,因為箭頭函數(shù)不是function關(guān)鍵字定義的,而是使用被稱為“胖箭頭”的操作符 => 定義的。箭頭函數(shù)不使用this的四種標(biāo)準(zhǔn)規(guī)則,而是根據(jù)外層的作用域決定this的。所以叫做詞法

    function foo () {// 返回一個箭頭函數(shù)return (a) => {// this繼承自foo()console.log(this.a)}}var obj1 = {a: 2}var obj2 = {a: 3}var bar = foo.call(obj1)bar.call(obj2) // 2 復(fù)制代碼

    foo內(nèi)部創(chuàng)建的箭頭函數(shù)會捕獲調(diào)用時foo()的this,由于foo()的this是綁定到obj1上的,bar(只是引用箭頭函數(shù))的this也會綁定到obj1上,箭頭函數(shù)的綁定無法修改。類似于

    function foo () {var self = thissetTimeout(function () {console.log(self.a)}, 100)} 復(fù)制代碼

    關(guān)于this的理解就說這么多,歡迎指正和交流。

    轉(zhuǎn)載于:https://juejin.im/post/5cf4e610f265da1b897aba93

    總結(jié)

    以上是生活随笔為你收集整理的深入理解JS中this关键字的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 99久久99久久精品国产片 | 久久99精品久久久久久 | 亚洲午夜精品一区二区三区他趣 | 亚洲综合资源 | 久久久久久电影 | 亚洲激情久久久 | 亚洲一区二区视频在线 | 韩国三级免费 | 丰满人妻一区二区三区无码av | 五月婷中文字幕 | 免费av小说 | 国产成人精品亚洲精品色欲 | 亚洲国产aⅴ精品一区二区的游戏 | 激情久久网 | 黄色免费视频 | 婷婷资源网 | 91亚洲影院| 国产三级在线观看 | 国产又粗又猛又色又 | 免费看的黄色小视频 | 欧美一级二级视频 | 亚洲成人a√ | 久色国产| 美女视频在线观看免费 | 国产一区二区在线免费观看视频 | 亚洲九九 | 国产欧美精品久久 | 国产激情福利 | 欧美成人免费大片 | 国产精品揄拍一区二区 | 成人黄色小说在线观看 | 午夜视频在线观看一区二区 | 国产精品美女久久久网av | 看毛片的网址 | 国内外成人在线视频 | 视频在线观看电影完整版高清免费 | 亚洲免费在线看 | 99热这里只有精品4 精品国产黄色 | 久久久久人妻一区二区三区 | 精品视频 | 少妇又紧又深又湿又爽视频 | free国产hd露脸性开放 | 久久久久亚洲av无码专区体验 | 欧美草b | 国产精品自产拍在线观看 | 91免费视频播放 | 永久久久久久 | 51av在线| 最新中文字幕免费 | 日韩毛片网 | 性一交一乱一伧国产女士spa | 精品人妻无码专区视频 | 亚洲男人第一网站 | 91成人国产综合久久精品 | 激情小视频 | 国产中文字幕视频 | 免费成人深夜夜视频 | 免费成人黄色 | 国产乱来| 亚洲欧美一区二区三区四区五区 | 狠狠干b | 四虎影院在线 | av免费播放网站 | 欧美日本韩国一区二区 | 久久久久久国产免费a片 | 欧美日韩电影一区 | 成人免费视频网站在线观看 | 日本一区二区三区免费在线观看 | 欧洲亚洲自拍 | 精品午夜久久久 | 国产精品久久久久久久久久免费看 | 天天操夜夜拍 | 在线视频自拍 | 国产精品视频一区二区三区, | 免费在线观看成人av | 夜夜噜噜噜 | 午夜视频入口 | 好大好舒服视频 | 亚洲国产影院 | 亚洲视频在线一区二区 | 国产精品一区二区三区免费观看 | 中文字幕丝袜 | 91av导航| 福利片网址| 夜夜av| 黄色图片小说 | 亚洲伊人成人网 | 色欲无码人妻久久精品 | www.亚洲一区二区 | 久久精品伊人 | 女人叉开腿让男人桶 | 丝袜制服中文字幕 | 国产精品99久久免费黑人人妻 | 成年人在线观看视频 | 国产伦精品一区二区三区在线 | 亚洲蜜桃精久久久久久久久久久久 | 欧美日韩免费看 | 黄色片视频 | 中文字幕在线视频免费 |