国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - js教程 - 深入理解javascript中的this

深入理解javascript中的this

2022-01-19 15:16WindrunnerMax js教程

這篇文章主要介紹了深入理解Js中的this,有隊這方面感興趣的同學可以閱讀學習下

深入理解Js中的this

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

作用域

我們先來了解一下JavaScript的作用域,以便理解為什么說this更類似于動態作用域,通常來說,一段程序代碼中所用到的名字并不總是有效或可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域scope,當一個方法或成員被聲明,他就擁有當前的執行上下文context環境,在有具體值的context中,表達式是可見也都能夠被引用,如果一個變量或者其他表達式不在當前的作用域,則將無法使用。作用域也可以根據代碼層次分層,以便子作用域可以訪問父作用域,通常是指沿著鏈式的作用域鏈查找,而不能從父作用域引用子作用域中的變量和引用。
JavaScript作用域為靜態作用域static scope,也可以稱為詞法作用域lexical scope,其主要特征在于,函數作用域中遇到既不是參數也不是函數內部定義的局部變量時,去函數定義時上下文中查,而與之相對應的是動態作用域dynamic scope則不同,其函數作用域中遇到既不是參數也不是函數內部定義的局部變量時,到函數調用時的上下文中去查。

?
1
2
3
4
5
6
7
8
var a = 1;
var s = function(){
 console.log(a);
};
(function(){
 var a = 2;
 s(); // 1
})();

調用s()是打印的a為1,此為靜態作用域,也就是聲明時即規定作用域,而假如是動態作用域的話在此處會打印2。現在大部分語言都采用靜態作用域,比如CC++JavaPHPPython等等,具有動態作用域的語言有Emacs LispCommon LispPerl等。

全局作用域

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

?
1
2
3
4
5
6
7
8
function s(){}
console.dir(s);
/*
 ...
 [[Scopes]]: Scopes[1]
 0: Global ...
*/
// 可以看見聲明的s函數運行的上下文環境是全局作用域

函數作用域

當聲明一個函數后,在函數內部聲明的方法或者成員的運行環境就是此函數的函數作用域

?
1
2
3
4
5
6
7
8
9
10
11
12
(function localContext(){
 var a = 1;
 function s(){ return a; }
 console.dir(s);
})();
/*
 ...
 [[Scopes]]: Scopes[2]
 0: Closure (localContext) {a: 1}
 1: Global ...
*/
// 可以看見聲明的s函數運行的上下文環境是函數localContext的作用域,也可以稱為局部作用域

塊級作用域

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

?
1
2
3
4
5
6
7
8
9
10
11
12
{
 let a = 1;
 function s(){return a;}
 console.dir(s);
 /*
 ...
 [[Scopes]]: Scopes[2]
 0: Block {a: 1}
 1: Global ...
 */
}
// 可以看見聲明的s函數運行的上下文環境是Block塊級作用域,也是局部作用域

分析

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

?
1
2
3
4
5
6
7
8
9
10
11
var obj = {
 name: 1,
 say: function() {
 return this.name;
 }
};
window.name = 2;
window.say = obj.say;
 
console.log(obj.say()); // 1
console.log(window.say()); // 2

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

使用

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

默認綁定

最常用的函數調用類型即獨立函數調用,這個也是優先級最低的一個,此時this指向全局對象,注意如果使用嚴格模式strict mode,那么全局對象將無法使用默認綁定,因此this會變為undefined

?
1
2
3
4
5
6
7
8
9
10
11
12
var a = 1; // 變量聲明到全局對象中
function f1() {
 return this.a;
}
 
function f2() {
 "use strict";
 return this;
}
 
console.log(f1()); // 1 // 實際上是調用window.f1()而this永遠指向調用者即window
console.log(f2()); // undefined // 實際上是調用 window.f2() 此時由于嚴格模式use strict所以在函數內部this為undefined

隱式綁定

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

?
1
2
3
4
5
6
7
8
9
10
11
12
function f() {
 console.log(this.a);
}
var obj1 = {
 a: 1,
 f: f
};
var obj2 = {
 a: 11,
 obj1: obj1
};
obj2.obj1.f(); // 1 // 最后一層調用者即obj1
?
1
2
3
4
5
6
7
8
9
10
11
12
function f() {
 console.log(this.a);
}
var obj1 = {
 a: 1,
 f: f
};
var obj2 = {
 a: 11,
};
obj2.f = obj1.f; // 間接引用
obj2.f(); // 11 // 調用者即為obj2

顯示綁定

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
window.name = "A"; // 掛載到window對象的name
document.name = "B"; // 掛載到document對象的name
var s = { // 自定義一個對象s
 name: "C"
}
 
var rollCall = {
 name: "Teacher",
 sayName: function(){
 console.log(this.name);
 }
}
rollCall.sayName(); // Teacher
 
// apply
rollCall.sayName.apply(); // A // 不傳參默認綁定window
rollCall.sayName.apply(window); // A // 綁定window對象
rollCall.sayName.apply(document); // B // 綁定document對象
rollCall.sayName.apply(s); // C // 綁定自定義對象
 
// call
rollCall.sayName.call(); // A // 不傳參默認綁定window
rollCall.sayName.call(window); // A // 綁定window對象
rollCall.sayName.call(document); // B // 綁定document對象
rollCall.sayName.call(s); // C // 綁定自定義對象
 
// bind // 最后一個()是為讓其執行
rollCall.sayName.bind()(); //A // 不傳參默認綁定window
rollCall.sayName.bind(window)(); //A // 綁定window對象
rollCall.sayName.bind(document)(); //B // 綁定document對象
rollCall.sayName.bind(s)(); // C // 綁定自定義對象

new綁定

JavaScriptnew是一個語法糖,可以簡化代碼的編寫,可以批量創建對象實例,在new的過程實際上進行了以下操作。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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); // 1
 
var f2 = _new(Funct, 1);
console.log(f2.a); // 1

箭頭函數

箭頭函數沒有單獨的this,在箭頭函數的函數體中使用this時,會取得其上下文context環境中的this。箭頭函數調用時并不會生成自身作用域下的this,它只會從自己的作用域鏈的上一層繼承this。由于箭頭函數沒有自己的this指針,使用applycallbind僅能傳遞參數而不能動態改變箭頭函數的this指向,另外箭頭函數不能用作構造器,使用new實例化時會拋出異常。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.name = 1;
var obj = {
 name: 11,
 say: function(){
 const f1 = () => {
 return this.name;
 }
 console.log(f1()); // 11 // 直接調用者為window 但是由于箭頭函數不綁定this所以取得context中的this即obj對象
 const f2 = function(){
 return this.name;
 }
 console.log(f2()); // 1 // 直接調用者為window 普通函數所以
 return this.name;
 }
}
 
console.log(obj.say()); // 11 // 直接調用者為obj 執行過程中的函數內context的this為obj對象

示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function s(){
 console.log(this);
}
 
// window中直接調用 // 非 use strict
s(); // Window // 等同于window.s(),調用者為window
// window是Window的一個實例 // window instanceof Window //true
 
// 新建對象s1
var s1 = {
 t1: function(){ // 測試this指向調用者
 console.log(this); // s1
 s(); // Window // 此次調用仍然相當 window.s(),調用者為window
 },
 t2: () => { // 測試箭頭函數,this并未指向調用者
 console.log(this);
 },
 t3: { // 測試對象中的對象
 tt1: function() {
 console.log(this);
 }
 },
 t4: { // 測試箭頭函數以及非函數調用this并未指向調用者
 tt1: () => {
 console.log(this);
 }
 },
 t5: function(){ // 測試函數調用時箭頭函數的this的指向,其指向了上一層對象的調用者
 return {
 tt1: () => {
 console.log(this);
 }
 }
 }
}
s1.t1(); // s1對象 // 此處的調用者為 s1 所以打印對象為 s1
s1.t2(); // Window
s1.t3.tt1(); // s1.t3對象
s1.t4.tt1(); // Window
s1.t5().tt1(); // s1對象

到此這篇關于深入理解Js中的this的文章就介紹到這了,更多相關深入理解Js中的this內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/WindrunnerMax/p/14379232.html

延伸 · 閱讀

精彩推薦
  • js教程JavaScript this關鍵字的深入詳解

    JavaScript this關鍵字的深入詳解

    這篇文章主要給大家介紹了關于JavaScript this關鍵字的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要...

    JAVA_樸先生9062021-12-31
  • js教程js實現碰撞檢測

    js實現碰撞檢測

    這篇文章主要為大家詳細介紹了js實現碰撞檢測,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    搬磚大法8172022-01-11
  • js教程基于javascript實現移動端輪播圖效果

    基于javascript實現移動端輪播圖效果

    這篇文章主要為大家詳細介紹了基于javascript實現移動端輪播圖效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    A.香辣雞腿堡9012021-12-15
  • js教程繪制微信小程序驗證碼功能的實例代碼

    繪制微信小程序驗證碼功能的實例代碼

    這篇文章主要介紹了繪制微信小程序驗證碼功能的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參...

    WALL*E8802021-12-27
  • js教程原生js實現自定義滾動條組件

    原生js實現自定義滾動條組件

    這篇文章主要為大家詳細介紹了原生js實現自定義滾動條組件的開發,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    蒲公英芽11422022-01-05
  • js教程js事件模型與自定義事件實例解析

    js事件模型與自定義事件實例解析

    JavaScript一個最簡單的事件模型,需要有事件綁定與觸發,還有事件刪除。本文將對其具體實現代碼進行解析,需要的朋友一起來看下吧...

    caihg5642021-12-15
  • js教程JavaScript實現4位隨機驗證碼的生成

    JavaScript實現4位隨機驗證碼的生成

    這篇文章主要為大家詳細介紹了JavaScript實現4位隨機驗證碼的生成,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    weixin_4202683110432022-01-10
  • js教程聊一聊六個JavaScript圖表庫

    聊一聊六個JavaScript圖表庫

    作為一名前端 Web 開發人員,能夠像制作漂亮的交互式網頁一樣多地可視化數據是一項很棒的技能。這些 JavaScript 庫使這項任務變得更容易,因為開發人員...

    粵嵌教育6562022-01-12
主站蜘蛛池模板: 午夜免费 | 国产午夜视频 | 欧美福利电影在线观看 | 伊人网在线视频免费观看 | 久久久精品综合 | 日韩欧美一级精品久久 | 国产精品久久一区二区三区 | 求av网址 | 欧美三区二区一区 | 精品视频一区二区三区四区 | 国产精品2区 | 亚洲国产精品久久久久久 | 香蕉久久夜色精品国产使用方法 | 亚洲毛片a | av手机在线电影 | 国产免费一区二区三区 | 国产欧美一区二区精品性色 | 日韩福利在线 | 欧美一区免费 | 国产欧美精品区一区二区三区 | 黄色成人在线视频 | 午夜视频一区 | 久久视频一区 | 亚洲激情在线观看 | 精品一二三四区 | 亚洲视频自拍 | 免费的av电影 | 黄a视频 | 四虎影视在线 | 亚洲精品久久久久久久久久久 | 成人看片免费 | 免费av大全| 三级在线不卡 | 视频一区在线观看 | 午夜精品一区二区三区在线视频 | 美日韩一区二区 | 亚洲 欧美 日韩在线 | 一级片在线观看 | 亚洲夜幕久久日韩精品一区 | 精品国产视频 | 久久与欧美 |