日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

深入理解javascript中的this

瀏覽:11日期:2023-06-09 14:02:52
深入理解Js中的this

JavaScript作用域為靜態(tài)作用域static scope,但是在Js中的this卻是一個例外,this的指向問題就類似于動態(tài)作用域,其并不關(guān)心函數(shù)和作用域是如何聲明以及在何處聲明的,只關(guān)心它們從何處調(diào)用,this的指向在函數(shù)定義的時候是確定不了的,只有函數(shù)執(zhí)行的時候才能確定this到底指向誰,當(dāng)然實際上this的最終指向的是那個調(diào)用它的對象。

作用域

我們先來了解一下JavaScript的作用域,以便理解為什么說this更類似于動態(tài)作用域,通常來說,一段程序代碼中所用到的名字并不總是有效或可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域scope,當(dāng)一個方法或成員被聲明,他就擁有當(dāng)前的執(zhí)行上下文context環(huán)境,在有具體值的context中,表達(dá)式是可見也都能夠被引用,如果一個變量或者其他表達(dá)式不在當(dāng)前的作用域,則將無法使用。作用域也可以根據(jù)代碼層次分層,以便子作用域可以訪問父作用域,通常是指沿著鏈?zhǔn)降淖饔糜蜴湶檎遥荒軓母缸饔糜蛞米幼饔糜蛑械淖兞亢鸵谩avaScript作用域為靜態(tài)作用域static scope,也可以稱為詞法作用域lexical scope,其主要特征在于,函數(shù)作用域中遇到既不是參數(shù)也不是函數(shù)內(nèi)部定義的局部變量時,去函數(shù)定義時上下文中查,而與之相對應(yīng)的是動態(tài)作用域dynamic scope則不同,其函數(shù)作用域中遇到既不是參數(shù)也不是函數(shù)內(nèi)部定義的局部變量時,到函數(shù)調(diào)用時的上下文中去查。

var a = 1;var s = function(){ console.log(a);};(function(){ var a = 2; s(); // 1})();

調(diào)用s()是打印的a為1,此為靜態(tài)作用域,也就是聲明時即規(guī)定作用域,而假如是動態(tài)作用域的話在此處會打印2。現(xiàn)在大部分語言都采用靜態(tài)作用域,比如C、C++、Java、PHP、Python等等,具有動態(tài)作用域的語言有Emacs Lisp、Common Lisp、Perl等。

全局作用域

直接聲明在頂層的變量或方法就運行在全局作用域,借用函數(shù)的[[Scopes]]屬性來查看作用域,[[Scopes]]是保存函數(shù)作用域鏈的對象,是函數(shù)的內(nèi)部屬性無法直接訪問但是可以打印來查看。

function s(){}console.dir(s);/* ... [[Scopes]]: Scopes[1] 0: Global ...*/// 可以看見聲明的s函數(shù)運行的上下文環(huán)境是全局作用域函數(shù)作用域

當(dāng)聲明一個函數(shù)后,在函數(shù)內(nèi)部聲明的方法或者成員的運行環(huán)境就是此函數(shù)的函數(shù)作用域

(function localContext(){ var a = 1; function s(){ return a; } console.dir(s);})();/* ... [[Scopes]]: Scopes[2] 0: Closure (localContext) {a: 1} 1: Global ...*/// 可以看見聲明的s函數(shù)運行的上下文環(huán)境是函數(shù)localContext的作用域,也可以稱為局部作用域塊級作用域

代碼塊內(nèi)如果存在let或者const,代碼塊會對這些命令聲明的變量從塊的開始就形成一個封閉作用域。

{ let a = 1; function s(){return a;} console.dir(s); /* ... [[Scopes]]: Scopes[2] 0: Block {a: 1} 1: Global ... */}// 可以看見聲明的s函數(shù)運行的上下文環(huán)境是Block塊級作用域,也是局部作用域分析

我們在使用this之前有必要了解為什么在JavaScript中要有this這個設(shè)計,在這之前我們先舉個小例子,通常我們使用this時可能會遇到的典型問題就類似于下面這樣,雖然我們運行的都是同一個函數(shù),但是執(zhí)行的結(jié)果可能會不同。

var obj = { name: 1, say: function() { return this.name; }};window.name = 2;window.say = obj.say;console.log(obj.say()); // 1console.log(window.say()); // 2

產(chǎn)生這樣的結(jié)果的原因就是因為使用了this關(guān)鍵字,前文已經(jīng)提到了this必須要在運行時才能確定,在這里,對于obj.say()來說,say()運行的環(huán)境是obj對象,對于window.say()來說,say()運行的環(huán)境是window對象,所以兩者運行的結(jié)果不同。此時我們就來了解一下,為什么JavaScript會有this這樣一個設(shè)計,我們首先來了解一下JavaScript的內(nèi)存結(jié)構(gòu)中的堆棧,堆heap是動態(tài)分配的內(nèi)存,大小不定也不會自動釋放,棧stack為自動分配的內(nèi)存空間,在代碼執(zhí)行過程中自動釋放。JavaScript在棧內(nèi)存中提供一個供Js代碼執(zhí)行的環(huán)境,關(guān)于作用域以及函數(shù)的調(diào)用都是棧內(nèi)存中執(zhí)行的。Js中基本數(shù)據(jù)類型String、Number、Boolean、Null、Undefined、Symbol,占用空間小且大小固定,值直接保存在棧內(nèi)存中,是按值訪問,對于Object引用類型,其指針放置于棧內(nèi)存中,指向堆內(nèi)存的實際地址,是通過引用訪問。那么此時我們來看一下上邊的示例,在內(nèi)存中對于obj對象是存放在堆內(nèi)存的,如果在對象中的屬性值是個基本數(shù)據(jù)類型,那么其會跟這個對象存儲在同一塊內(nèi)存區(qū)域,但是這個屬性值同樣可能是一個引用類型,那么對于say這個函數(shù)也是存在于堆內(nèi)存中的,實際上在此處我們可以將其理解為這個函數(shù)的實際定義在一個內(nèi)存區(qū)域(以一個匿名函數(shù)的形式存在),而obj這個對象同樣在其他的一個內(nèi)存區(qū)域,obj通過say這個屬性指向了這個匿名函數(shù)的內(nèi)存地址,obj --say--> funtion,那么此時問題來了,由于這種內(nèi)存結(jié)構(gòu),我們可以使任何變量對象等指向這個函數(shù),所以在JavaScript的函數(shù)中是需要允許我們?nèi)〉眠\行環(huán)境的值以供使用的,我們必須要有一種機制,能夠在函數(shù)體內(nèi)部獲得當(dāng)前的運行環(huán)境context,所以this就出現(xiàn)了,它的設(shè)計目的就是在函數(shù)體內(nèi)部,指代函數(shù)當(dāng)前的運行環(huán)境。

使用

我們需要記住,this是在運行時進(jìn)行綁定的,并不是在定義時綁定,它的context取決于函數(shù)調(diào)用時的各種條件,簡單來說this的綁定和函數(shù)聲明的位置沒有任何關(guān)系,只取決于函數(shù)的調(diào)用方式,再簡單來說this永遠(yuǎn)指向調(diào)用者,但箭頭函數(shù)除外,接下來我們介紹一下五種this的使用情況。

默認(rèn)綁定

最常用的函數(shù)調(diào)用類型即獨立函數(shù)調(diào)用,這個也是優(yōu)先級最低的一個,此時this指向全局對象,注意如果使用嚴(yán)格模式strict mode,那么全局對象將無法使用默認(rèn)綁定,因此this會變?yōu)閡ndefined。

var a = 1; // 變量聲明到全局對象中function f1() { return this.a;}function f2() { 'use strict'; return this;}console.log(f1()); // 1 // 實際上是調(diào)用window.f1()而this永遠(yuǎn)指向調(diào)用者即windowconsole.log(f2()); // undefined // 實際上是調(diào)用 window.f2() 此時由于嚴(yán)格模式use strict所以在函數(shù)內(nèi)部this為undefined隱式綁定

對象屬性引用鏈中只有最頂層或者說最后一層會影響this,同樣也是this永遠(yuǎn)指向調(diào)用者,具體點說應(yīng)該是指向最近的調(diào)用者,當(dāng)然箭頭函數(shù)除外,另外我們可能有意無意地創(chuàng)建間接引用地情況,這個情況下同樣也適用于this指向調(diào)用者,在上文分析那部分使用的示例就屬于間接引用的情況。

function f() { console.log(this.a);}var obj1 = { a: 1, f: f};var obj2 = { a: 11, obj1: obj1};obj2.obj1.f(); // 1 // 最后一層調(diào)用者即obj1

function f() { console.log(this.a);}var obj1 = { a: 1, f: f};var obj2 = { a: 11,};obj2.f = obj1.f; // 間接引用obj2.f(); // 11 // 調(diào)用者即為obj2顯示綁定

如果我們想把某個函數(shù)強制在某個環(huán)境即對象上,那么就可以使用apply、call、bind強制綁定this去執(zhí)行即可,每個Function對象都存在apply()、call()、bind()方法,其作用都是可以在特定的作用域中調(diào)用函數(shù),等于設(shè)置函數(shù)體內(nèi)this對象的值,以擴充函數(shù)賴以運行的作用域,此外需要注意使用bind綁定this的優(yōu)先級是大于apply和call的,即使用bind綁定this后的函數(shù)使用apply和call是無法改變this指向的。

window.name = 'A'; // 掛載到window對象的namedocument.name = 'B'; // 掛載到document對象的namevar s = { // 自定義一個對象s name: 'C'}var rollCall = { name: 'Teacher', sayName: function(){ console.log(this.name); }}rollCall.sayName(); // Teacher// applyrollCall.sayName.apply(); // A // 不傳參默認(rèn)綁定windowrollCall.sayName.apply(window); // A // 綁定window對象rollCall.sayName.apply(document); // B // 綁定document對象rollCall.sayName.apply(s); // C // 綁定自定義對象// callrollCall.sayName.call(); // A // 不傳參默認(rèn)綁定windowrollCall.sayName.call(window); // A // 綁定window對象rollCall.sayName.call(document); // B // 綁定document對象rollCall.sayName.call(s); // C // 綁定自定義對象// bind // 最后一個()是為讓其執(zhí)行rollCall.sayName.bind()(); //A // 不傳參默認(rèn)綁定windowrollCall.sayName.bind(window)(); //A // 綁定window對象rollCall.sayName.bind(document)(); //B // 綁定document對象rollCall.sayName.bind(s)(); // C // 綁定自定義對象new綁定

在JavaScript中new是一個語法糖,可以簡化代碼的編寫,可以批量創(chuàng)建對象實例,在new的過程實際上進(jìn)行了以下操作。

創(chuàng)建一個空的簡單JavaScript對象即{}。鏈接該對象(即設(shè)置該對象的構(gòu)造函數(shù))到另一個對象。將步驟1新創(chuàng)建的對象作為this的上下文context。如果該函數(shù)沒有返回對象,則返回步驟1創(chuàng)建的對象。

function _new(base,...args){ var obj = {}; obj.__proto__ = base.prototype; base.apply(obj, args); return obj;}function Funct(a) { this.a = a;}var f1 = new Funct(1);console.log(f1.a); // 1var f2 = _new(Funct, 1);console.log(f2.a); // 1箭頭函數(shù)

箭頭函數(shù)沒有單獨的this,在箭頭函數(shù)的函數(shù)體中使用this時,會取得其上下文context環(huán)境中的this。箭頭函數(shù)調(diào)用時并不會生成自身作用域下的this,它只會從自己的作用域鏈的上一層繼承this。由于箭頭函數(shù)沒有自己的this指針,使用apply、call、bind僅能傳遞參數(shù)而不能動態(tài)改變箭頭函數(shù)的this指向,另外箭頭函數(shù)不能用作構(gòu)造器,使用new實例化時會拋出異常。

window.name = 1;var obj = { name: 11, say: function(){ const f1 = () => { return this.name; } console.log(f1()); // 11 // 直接調(diào)用者為window 但是由于箭頭函數(shù)不綁定this所以取得context中的this即obj對象 const f2 = function(){ return this.name; } console.log(f2()); // 1 // 直接調(diào)用者為window 普通函數(shù)所以 return this.name; }}console.log(obj.say()); // 11 // 直接調(diào)用者為obj 執(zhí)行過程中的函數(shù)內(nèi)context的this為obj對象示例

function s(){ console.log(this);}// window中直接調(diào)用 // 非 use stricts(); // Window // 等同于window.s(),調(diào)用者為window// window是Window的一個實例 // window instanceof Window //true// 新建對象s1var s1 = { t1: function(){ // 測試this指向調(diào)用者 console.log(this); // s1 s(); // Window // 此次調(diào)用仍然相當(dāng) window.s(),調(diào)用者為window }, t2: () => { // 測試箭頭函數(shù),this并未指向調(diào)用者 console.log(this); }, t3: { // 測試對象中的對象 tt1: function() { console.log(this); } }, t4: { // 測試箭頭函數(shù)以及非函數(shù)調(diào)用this并未指向調(diào)用者 tt1: () => { console.log(this); } }, t5: function(){ // 測試函數(shù)調(diào)用時箭頭函數(shù)的this的指向,其指向了上一層對象的調(diào)用者 return { tt1: () => { console.log(this); } } }}s1.t1(); // s1對象 // 此處的調(diào)用者為 s1 所以打印對象為 s1s1.t2(); // Windows1.t3.tt1(); // s1.t3對象s1.t4.tt1(); // Windows1.t5().tt1(); // s1對象

到此這篇關(guān)于深入理解Js中的this的文章就介紹到這了,更多相關(guān)深入理解Js中的this內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: JavaScript
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美a在线观看| 涩涩涩久久久成人精品| 欧美精品中文字幕亚洲专区| 1000部精品久久久久久久久| 日本少妇精品亚洲第一区| 国产精品久久久久久av公交车 | 欧美天堂视频| 日韩大片在线播放| av成人国产| 亚洲一区二区三区免费在线观看| 亚洲综合电影| 欧美激情三区| 国产欧美日韩一级| 亚洲一区激情| 鲁大师精品99久久久| 久久久久久美女精品| 亚洲精品电影| 99精品在线免费在线观看| 亚洲电影在线一区二区三区| 日韩毛片网站| 蜜桃视频一区二区三区在线观看| 在线观看视频免费一区二区三区| 国产精品毛片一区二区在线看| 国产精品xxxav免费视频| 久久久91麻豆精品国产一区| 成人羞羞视频播放网站| 午夜精品成人av| 久久久久久黄| 亚洲精品美女| 国产亚洲精品久久久久婷婷瑜伽| 国产激情精品一区二区三区| 日韩一区精品| 夜鲁夜鲁夜鲁视频在线播放| 国产精品啊啊啊| 日韩中文字幕av电影| 爽好多水快深点欧美视频| 中文在线不卡| 欧美专区一区二区三区| 久久亚洲在线| 高清一区二区| 成人三级高清视频在线看| 国产精品大片| 欧美jjzz| 日本免费一区二区视频| 国产精品探花在线观看| 91成人福利| 国产精品99一区二区| 欧美韩一区二区| 亚洲激情偷拍| 欧美精品影院| 欧美精品高清| 欧美成人高清| 亚洲精品自拍| 欧美国产极品| 日韩欧美精品| 精品国产精品国产偷麻豆| 国内精品福利| 日本一区二区免费高清| 夜久久久久久| 黄色成人在线网址| 伊人久久成人| 国产精品一区2区3区| 麻豆精品av| 日韩不卡视频在线观看| 一区在线免费| 日本中文字幕视频一区| 久久亚洲美女| 91综合网人人| 国产精品日本| 国产成人精品三级高清久久91| 婷婷亚洲综合| 亚洲91网站| 亚洲国产一区二区三区在线播放 | 丝袜美腿成人在线| 牛牛精品成人免费视频| 欧美日韩99| 毛片在线网站| 欧美日韩免费观看视频| 加勒比视频一区| 久久先锋影音| 欧洲在线一区| 欧美日韩18| 国产专区一区| 日本电影久久久| 黄毛片在线观看| 美女视频黄久久| 亚洲精品国产嫩草在线观看| 日韩在线网址| 99精品美女| 亚洲综合电影| 国产aⅴ精品一区二区四区| 亚洲久久一区| 亚洲精品无播放器在线播放| 免费久久99精品国产自在现线| 国产专区精品| 精品中文字幕一区二区三区四区| 欧美在线亚洲| 亚洲午夜黄色| 日韩不卡在线| 欧美亚洲激情| 欧美a级一区二区| 欧美日韩视频免费看| 日韩国产综合| 精品九九久久| 国产精品伊人| 综合欧美亚洲| 99久久亚洲精品| 香蕉精品视频在线观看| 福利视频一区| 免费在线亚洲欧美| 国产精品麻豆成人av电影艾秋| 亚洲欧美网站在线观看| 国产欧美日韩精品一区二区三区| 国产精品入口久久| 手机在线电影一区| 精品国产亚洲日本| 午夜久久美女| 蜜臀a∨国产成人精品| 首页国产欧美日韩丝袜| 天堂网av成人| 亚洲精品欧美| 清纯唯美亚洲综合一区| 99riav国产精品| 国产日韩一区二区三区在线| 国产精品免费大片| 日本特黄久久久高潮| 91tv亚洲精品香蕉国产一区| 亚洲一级二级| 国产一区二区三区91| 欧美日韩18| 久久精品 人人爱| 久久中文字幕二区| 精品三级av| 欧美国产三级| 日本不卡视频在线观看| 亚洲欧美日韩精品一区二区 | 国产农村妇女精品一二区 | 亚洲一区二区三区久久久| 日韩美女精品| 久久国产精品久久久久久电车| 午夜在线视频一区二区区别| 亚洲精选91| 在线成人动漫av| 五月天综合网站| 久久一区精品| 欧美日韩网址| 天堂av在线一区| 国产精品欧美在线观看| 亚洲成av在线| 久久亚洲资源中文字| 少妇高潮一区二区三区99| 日韩视频在线一区二区三区 | 日韩三区四区| 日韩专区欧美专区| 中文字幕成人| 亚洲激情另类| 精品欧美激情在线观看| 亚洲v天堂v手机在线| 日韩欧美中文字幕在线视频| 在线一区欧美| 国产欧洲在线| 国产欧美日韩亚洲一区二区三区| 国产精品啊v在线| 福利一区在线| 综合欧美亚洲| 欧美日韩精品免费观看视完整| 中文字幕人成乱码在线观看| 中文字幕色婷婷在线视频| 日韩一区欧美| 激情黄产视频在线免费观看| 国内精品亚洲| 日产精品一区| 99视频精品| 久久久一本精品| 久久久久免费av| 日本国产亚洲| 蜜桃一区二区三区在线观看| 中文字幕av一区二区三区人| 国产精品大片| 日韩综合小视频| 免费成人av在线播放| 国产伦理久久久久久妇女| 久久精品女人| 美女精品一区二区| 国产66精品| 色综合视频一区二区三区日韩 | 尤物网精品视频| 蜜桃视频一区二区| av高清不卡| 久久中文视频| 日本在线不卡视频一二三区| 美女视频免费精品| 999在线观看精品免费不卡网站| 日韩中文字幕av电影| 欧美日韩精品一区二区三区在线观看| 久久一区精品| 久久最新视频| 国产亚洲一区二区手机在线观看| 欧美1级日本1级| 清纯唯美亚洲综合一区|