" />

嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片

JavaScript必須掌握的基礎 ---> this

2020-5-30    seo達人

this

this是我們在書寫代碼時最常用的關鍵詞之一,即使如此,它也是JavaScript最容易被最頭疼的關鍵詞。那么this到底是什么呢?


如果你了解執行上下文,那么你就會知道,其實this是執行上下文對象的一個屬性:


executionContext = {

   scopeChain:[ ... ],

   VO:{

       ...

   },

   this:  ?

}

執行上下文中有三個重要的屬性,作用域鏈(scopeChain)、變量對象(VO)和this。


this是在進入執行上下文時確定的,也就是在函數執行時才確定,并且在運行期間不允許修改并且是永久不變的


在全局代碼中的this

在全局代碼中this 是不變的,this始終是全局對象本身。


var a = 10;

this.b = 20;

window.c = 30;


console.log(this.a);

console.log(b);

console.log(this.c);


console.log(this === window) // true

// 由于this就是全局對象window,所以上述 a ,b ,c 都相當于在全局對象上添加相應的屬性

如果我們在代碼運行期嘗試修改this的值,就會拋出錯誤:


this = { a : 1 } ; // Uncaught SyntaxError: Invalid left-hand side in assignment

console.log(this === window) // true

函數代碼中的this

在函數代碼中使用this,才是令我們最容易困惑的,這里我們主要是對函數代碼中的this進行分析。


我們在上面說過this的值是,進入當前執行上下文時確定的,也就是在函數執行時并且是執行前確定的。但是同一個函數,作用域中的this指向可能完全不同,但是不管怎樣,函數在運行時的this的指向是不變的,而且不能被賦值。


function foo() {

   console.log(this);

}


foo();  // window

var obj={

   a: 1,

   bar: foo,

}

obj.bar(); // obj

函數中this的指向豐富的多,它可以是全局對象、當前對象、或者是任意對象,當然這取決于函數的調用方式。在JavaScript中函數的調用方式有一下幾種方式:作為函數調用、作為對象屬性調用、作為構造函數調用、使用apply或call調用。下面我們將按照這幾種調用方式一一討論this的含義。


作為函數調用

什么是作為函數調用:就是獨立的函數調用,不加任何修飾符。


function foo(){

   console.log(this === window); // true

   this.a = 1;

   console.log(b); // 2

}

var b = 2;

foo();

console.log(a); // 1

上述代碼中this綁定到了全局對象window。this.a相當于在全局對象上添加一個屬性 a 。


在嚴格模式下,獨立函數調用,this的綁定不再是window,而是undefined。


function foo() {

   "use strict";

   console.log(this===window); // false

   console.log(this===undefined); // true

}

foo();

這里要注意,如果函數調用在嚴格模式下,而內部代碼執行在非嚴格模式下,this 還是會默認綁定為 window。


function foo() {

   console.log(this===window); // true

}



(function() {

   "use strict";

   foo();

})()

對于在函數內部的函數獨立調用 this 又指向了誰呢?


function foo() {

   function bar() {

       this.a=1;

       console.log(this===window); // true

   }

   bar()

}

foo();

console.log(a); // 1

上述代碼中,在函數內部的函數獨立調用,此時this還是被綁定到了window。


總結:當函數作為獨立函數被調用時,內部this被默認綁定為(指向)全局對象window,但是在嚴格模式下會有區別,在嚴格模式下this被綁定為undefined。


作為對象屬性調用

var a=1;

var obj={

   a: 2,

   foo: function() {

       console.log(this===obj); // true

       console.log(this.a); // 2

   }

}

obj.foo();

上述代碼中 foo屬性的值為一個函數。這里稱 foo 為 對象obj 的方法。foo的調用方式為 對象 . 方法 調用。此時 this 被綁定到當前調用方法的對象。在這里為 obj 對象。


再看一個例子:


var a=1;

var obj={

   a: 2,

   bar: {

       a: 3,

       foo: function() {

           console.log(this===bar); // true

           console.log(this.a); // 3

       }

   }

}

obj.bar.foo();

遵循上面說的規則 對象 . 屬性 。這里的對象為 obj.bar 。此時 foo 內部this被綁定到了 obj.bar 。 因此 this.a 即為 obj.bar.a 。


再來看一個例子:


var a=1;

var obj={

   a: 2,

   foo: function() {

       console.log(this===obj); // false

       console.log(this===window); // true

       console.log(this.a); // 1

   }

}


var baz=obj.foo;

baz();

這里 foo 函數雖然作為對象obj 的方法。但是它被賦值給變量 baz 。當baz調用時,相當于 foo 函數獨立調用,因此內部 this被綁定到 window。


使用apply或call調用

apply和call為函數原型上的方法。它可以更改函數內部this的指向。


var a=1;

function foo() {

   console.log(this.a);

}

var obj1={

   a: 2

}

var obj2={

   a: 3

}

var obj3={

   a: 4

}

var bar=foo.bind(obj1);

bar();// 2  this => obj1

foo(); // 1  this => window

foo.call(obj2); // 3  this => obj2

foo.call(obj3); // 4  this => obj3

當函數foo 作為獨立函數調用時,this被綁定到了全局對象window,當使用bind、call或者apply方法調用時,this 被分別綁定到了不同的對象。


作為構造函數調用

var a=1;

function Person() {

   this.a=2;  // this => p;

}

var p=new Person();

console.log(p.a); // 2

上述代碼中,構造函數 Person 內部的 this 被綁定為 Person的一個實例。


總結:


當我們要判斷當前函數內部的this綁定,可以依照下面的原則:


函數是否在是通過 new 操作符調用?如果是,this 綁定為新創建的對象

var bar = new foo();     // this => bar;

函數是否通過call或者apply調用?如果是,this 綁定為指定的對象

foo.call(obj1);  // this => obj1;

foo.apply(obj2);  // this => obj2;

函數是否通過 對象 . 方法調用?如果是,this 綁定為當前對象

obj.foo(); // this => obj;

函數是否獨立調用?如果是,this 綁定為全局對象。

foo(); // this => window

DOM事件處理函數中的this

1). 事件綁定


<button id="btn">點擊我</button>


// 事件綁定


function handleClick(e) {

   console.log(this); // <button id="btn">點擊我</button>

}

       document.getElementById('btn').addEventListener('click',handleClick,false);  //   <button id="btn">點擊我</button>

       

document.getElementById('btn').onclick= handleClick; //  <button id="btn">點擊我</button>

根據上述代碼我們可以得出:當通過事件綁定來給DOM元素添加事件,事件將被綁定為當前DOM對象。


2).內聯事件


<button onclick="handleClick()" id="btn1">點擊我</button>

<button onclick="console.log(this)" id="btn2">點擊我</button>


function handleClick(e) {

   console.log(this); // window

}


//第二個 button 打印的是   <button id="btn">點擊我</button>

我認為內聯事件可以這樣理解:


//偽代碼


<button onclick=function(){  handleClick() } id="btn1">點擊我</button>

<button onclick=function() { console.log(this) } id="btn2">點擊我</button>

這樣我們就能理解上述代碼中為什么內聯事件一個指向window,一個指向當前DOM元素。(當然瀏覽器處理內聯事件時并不是這樣的)


定時器中的this

定時器中的 this 指向哪里呢?


function foo() {

   setTimeout(function() {

       console.log(this); // window

   },1000)

}

foo();  

再來看一個例子


var name="chen";

var obj={

   name: "erdong",

   foo: function() {

       console.log(this.name); // erdong

       setTimeout(function() {

           console.log(this.name); // chen

       },1000)

   }

}

obj.foo();

到這里我們可以看到,函數 foo 內部this指向為調用它的對象,即:obj 。定時器中的this指向為 window。那么有什么辦法讓定時器中的this跟包裹它的函數綁定為同一個對象呢?


1). 利用閉包:


var name="chen";

var obj={

   name: "erdong",

   foo: function() {

       console.log(this.name) // erdong

       var that=this;

       setTimeout(function() {

           // that => obj

           console.log(that.name); // erdong

       },1000)

   }

}

obj.foo();

利用閉包的特性,函數內部的函數可以訪問含義訪問當前詞法作用域中的變量,此時定時器中的 that 即為包裹它的函數中的 this 綁定的對象。在下面我們會介紹利用 ES6的箭頭函數實現這一功能。


當然這里也可以適用bind來實現:


var name="chen";

var obj={

   name: "erdong",

   foo: function() {

       console.log(this.name); // erdong

       setTimeout(function() {

           // this => obj

           console.log(this.name); // erdong

       }.bind(this),1000)

   }

}

obj.foo();

被忽略的this

如果你把 null 或者 undefined 作為 this 的綁定對象傳入 call 、apply或者bind,這些值在調用時會被忽略,實例 this 被綁定為對應上述規則。


var a=1;

function foo() {

   console.log(this.a); // 1  this => window

}

var obj={

   a: 2

}

foo.call(null);

var a=1;

function foo() {

   console.log(this.a); // 1  this => window

}

var obj={

   a: 2

}

foo.apply(null);

var a=1;

function foo() {

   console.log(this.a); // 1  this => window

}

var obj={

   a: 2

}

var bar = foo.bind(null);

bar();

bind 也可以實現函數柯里化:


function foo(a,b) {

   console.log(a,b); // 2  3

}

var bar=foo.bind(null,2);

bar(3);

更復雜的例子:


var foo={

   bar: function() {

       console.log(this);

   }

};


foo.bar(); // foo

(foo.bar)(); // foo


(foo.bar=foo.bar)(); // window

(false||foo.bar)();  // window

(foo.bar,foo.bar)();  // window

上述代碼中:


foo.bar()為對象的方法調用,因此 this 綁定為 foo 對象。


(foo.bar)() 前一個() 中的內容不計算,因此還是 foo.bar()


(foo.bar=foo.bar)() 前一個 () 中的內容計算后為 function() { console.log(this); } 所以這里為匿名函數自執行,因此 this 綁定為 全局對象 window


后面兩個實例同上。


這樣理解會比較好:


(foo.bar=foo.bar)  括號中的表達式執行為 先計算,再賦值,再返回值。

(false||foo.bar)()    括號中的表達式執行為 判斷前者是否為 true ,若為true,不計算后者,若為false,計算后者并返回后者的值。

(foo.bar,foo.bar)   括號中的表達式之行為分別計算 “,” 操作符兩邊,然后返回  “,” 操作符后面的值。

箭頭函數中的this

箭頭函數時ES6新增的語法。


有兩個作用:


更簡潔的函數

本身不綁定this

代碼格式為:


// 普通函數

function foo(a){

   // ......

}

//箭頭函數

var foo = a => {

   // ......

}


//如果沒有參數或者參數為多個


var foo = (a,b,c,d) => {

   // ......

}

我們在使用普通函數之前對于函數的this綁定,需要根據這個函數如何被調用來確定其內部this的綁定對象。而且常常因為調用鏈的數量或者是找不到其真正的調用者對 this 的指向模糊不清。在箭頭函數出現后其內部的 this 指向不需要再依靠調用的方式來確定。


箭頭函數有幾個特點(與普通函數的區別)


箭頭函數不綁定 this 。它只會從作用域鏈的上一層繼承 this。

箭頭函數不綁定arguments,使用reset參數來獲取實參的數量。

箭頭函數是匿名函數,不能作為構造函數。

箭頭函數沒有prototype屬性。

不能使用 yield 關鍵字,因此箭頭函數不能作為函數生成器。

這里我們只討論箭頭函數中的this綁定。


用一個例子來對比普通函數與箭頭函數中的this綁定:


var obj={

   foo: function() {

       console.log(this); // obj

   },

   bar: () => {

       console.log(this); // window

   }

}

obj.foo();

obj.bar();

上述代碼中,同樣是通過對象 . 方法調用一個函數,但是函數內部this綁定確是不同,只因一個數普通函數一個是箭頭函數。


用一句話來總結箭頭函數中的this綁定:


個人上面說的它會從作用域鏈的上一層繼承 this ,說法并不是很正確。作用域中存放的是這個函數當前執行上下文與所有父級執行上下文的變量對象的集合。因此在作用域鏈中并不存在 this 。應該說是作用域鏈上一層對應的執行上下文中繼承 this 。


箭頭函數中的this繼承于作用域鏈上一層對應的執行上下文中的this


var obj={

   foo: function() {

       console.log(this); // obj

   },

   bar: () => {

       console.log(this); // window

   }

}

obj.bar();

上述代碼中obj.bar執行時的作用域鏈為:


scopeChain = [

   obj.bar.AO,

   global.VO

]

根據上面的規則,此時bar函數中的this指向為全局執行上下文中的this,即:window。


再來看一個例子:


var obj={

   foo: function() {

       console.log(this); // obj

       var bar=() => {

           console.log(this); // obj

       }

       bar();

   }

}

obj.foo();

在普通函數中,bar 執行時內部this被綁定為全局對象,因為它是作為獨立函數調用。但是在箭頭函數中呢,它卻綁定為 obj 。跟父級函數中的 this 綁定為同一對象。


此時它的作用域鏈為:


scopeChain = [

    bar.AO,

    obj.foo.AO,

    global.VO

]

這個時候我們就差不多知道了箭頭函數中的this綁定。


繼續看例子:


var obj={

   foo: () => {

       console.log(this); // window

       var bar=() => {

           console.log(this); // window

       }

       bar();

   }

}

obj.foo();

這個時候怎么又指向了window了呢?


我們還看當 bar 執行時的作用域鏈:


scopeChain = [

    bar.AO,

    obj.foo.AO,

    global.VO

]

當我們找bar函數中的this綁定時,就會去找foo函數中的this綁定。因為它是繼承于它的。這時 foo 函數也是箭頭函數,此時foo中的this綁定為window而不是調用它的obj對象。因此 bar函數中的this綁定也為全局對象window。


我們在回頭看上面關于定時器中的this的例子:


var name="chen";

var obj={

   name: "erdong",

   foo: function() {

       console.log(this.name); // erdong

       setTimeout(function() {

           console.log(this); // chen

       },1000)

   }

}

obj.foo();

這時我們就可以很簡單的讓定時器中的this與foo中的this綁定為同一對象:


var name="chen";

var obj={

   name: "erdong",

   foo: function() {

       // this => obj

       console.log(this.name); // erdong

       setTimeout(() =>  {

           // this => foo中的this => obj

           console.log(this.name); // erdong

       },1000)

   }

}

obj.foo();

日歷

鏈接

個人資料

藍藍設計的小編 http://www.sdgs6788.com

存檔

嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片
<em id="09ttv"></em>
    <sup id="09ttv"><pre id="09ttv"></pre></sup>
    <dd id="09ttv"></dd>

        • 久久久久久久一区二区三区| 尤物九九久久国产精品的分类| 亚洲精品欧美日韩| 久久国产福利| 性欧美1819sex性高清| 99在线观看免费视频精品观看| 亚洲福利视频一区二区| 激情久久五月| 狠狠色综合日日| 国产亚洲一二三区| 亚洲第一视频网站| 亚洲一区三区视频在线观看 | 国产精品久久久久久久久婷婷 | 欧美日韩国产美女| 国产精品视频999| 激情欧美日韩| 在线视频中文亚洲| 久久亚洲精品中文字幕冲田杏梨| 欧美成人激情视频免费观看| 日韩视频三区| 久久国产天堂福利天堂| 欧美日韩一区视频| 精品99一区二区| 中文欧美日韩| 久久影院午夜论| 亚洲视频1区| 麻豆精品网站| 国产精品午夜春色av| 亚洲精品久久久久中文字幕欢迎你| 亚洲天堂av高清| 欧美电影打屁股sp| 亚洲欧美在线高清| 欧美日韩视频在线观看一区二区三区| 黄色日韩网站| 久久精品亚洲乱码伦伦中文| 夜夜嗨一区二区| 欧美精品国产精品| 亚洲国产裸拍裸体视频在线观看乱了中文 | 亚洲免费网站| 亚洲国产一区二区在线| 欧美在线首页| 国产精品影音先锋| 亚洲一区二区高清| 亚洲人成亚洲人成在线观看图片| 久久激情一区| 国产一区二区高清| 午夜精品久久久久久久久久久久久 | 久久国产精品一区二区三区四区| 亚洲精品韩国| 欧美国产日本| 久久久www成人免费精品| 欧美视频在线视频| 一区二区电影免费在线观看| 欧美寡妇偷汉性猛交| 久久精品在线观看| 精品999在线播放| 老牛影视一区二区三区| 久久成人精品无人区| 国产一区二区三区免费观看| 久久成人精品电影| 久久精品99| 在线精品视频免费观看| 欧美www在线| 欧美成人在线免费观看| 亚洲免费观看视频| 亚洲免费高清| 国产精品久久9| 亚洲影视在线| 香蕉视频成人在线观看| 国内视频精品| 欧美高清免费| 国产精品xxxxx| 午夜精品久久| 欧美亚洲网站| 亚洲日本久久| 一个色综合av| 午夜精品在线| 亚洲香蕉成视频在线观看| 欧美视频中文一区二区三区在线观看 | 欧美高清在线一区二区| 欧美久久婷婷综合色| 亚洲欧美电影院| 欧美中文字幕精品| 亚洲精品欧洲精品| 国产精品99久久久久久有的能看| 国产精品制服诱惑| 欧美凹凸一区二区三区视频| 欧美精品久久一区二区| 性做久久久久久久免费看| 久久人人97超碰精品888| 正在播放欧美一区| 久久成人这里只有精品| 一区二区三区日韩精品| 欧美在线亚洲在线| 中国亚洲黄色| 葵司免费一区二区三区四区五区| 中文在线不卡| 久久综合精品国产一区二区三区| 一区二区三区你懂的| 久久九九精品| 小嫩嫩精品导航| 欧美精品一区二区三区高清aⅴ| 欧美一级片一区| 欧美激情视频一区二区三区在线播放| 午夜视频在线观看一区二区| 蜜臀久久久99精品久久久久久 | 亚洲国产99精品国自产| 亚洲女同性videos| 日韩亚洲欧美成人| 久久人人爽爽爽人久久久| 欧美亚洲色图校园春色| 欧美日本韩国在线| 欧美激情第1页| 国产视频一区欧美| aa级大片欧美| 亚洲伦理在线免费看| 久久久久国产精品www| 亚洲欧美国产另类| 欧美日韩国产精品一区二区亚洲| 免费观看日韩| 国内自拍视频一区二区三区 | 欧美aⅴ一区二区三区视频| 国产九区一区在线| av72成人在线| 亚洲在线观看免费视频| 欧美日韩一区二区三区免费看| 欧美不卡一卡二卡免费版| 国产在线观看精品一区二区三区| 亚洲一区中文字幕在线观看| 亚洲自拍偷拍色片视频| 欧美日韩国产在线看| 亚洲国产日韩精品| 亚洲精品激情| 欧美成在线观看| 亚洲经典在线看| 亚洲日本无吗高清不卡| 欧美华人在线视频| 亚洲精品欧美专区| 亚洲午夜在线| 国产精品亚洲人在线观看| 亚洲综合电影一区二区三区| 西瓜成人精品人成网站| 国产日本欧美一区二区三区在线| 亚洲欧美日韩在线观看a三区| 欧美一级免费视频| 黄色亚洲网站| 女主播福利一区| 亚洲精品欧美日韩| 性欧美长视频| 极品尤物av久久免费看| 久久人人精品| 亚洲毛片在线看| 性欧美超级视频| 国内揄拍国内精品久久| 免费欧美高清视频| 亚洲精选久久| 性8sex亚洲区入口| 伊人一区二区三区久久精品| 欧美v日韩v国产v| 日韩系列欧美系列| 欧美中文字幕在线| 亚洲二区在线观看| 欧美日韩亚洲综合一区| 亚洲一区二区三区在线视频| 麻豆精品网站| 一区二区av在线| 国产精品美女久久久免费| 久久福利电影| 亚洲日本va午夜在线影院| 午夜亚洲福利| 亚洲人体1000| 国产午夜精品美女视频明星a级 | 亚洲人成高清| 欧美综合二区| 亚洲伦理在线免费看| 国产亚洲精品aa| 欧美精品在线一区| 欧美中文在线观看国产| 99在线精品免费视频九九视| 久久综合免费视频影院| 亚洲一区二区不卡免费| 亚洲高清久久| 国产日产高清欧美一区二区三区| 久久婷婷丁香| 一区二区三区日韩在线观看| 欧美国产精品日韩| 久久久久国内| 亚洲尤物在线| 日韩一级黄色大片| 激情综合网激情| 国产精品大片| 欧美激情aaaa| 久久一区二区三区国产精品| 亚洲一区二区成人| 亚洲精品国产精品国产自| 久久夜色精品国产| 欧美一区二区三区视频免费播放| 一区二区冒白浆视频| 亚洲激情视频在线| 国产综合视频|