成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

大話javascript 6期:this深度解析

lsxiao / 2444人閱讀

摘要:在這次執(zhí)行期間,函數(shù)中的將指向。在剛剛的例子中,因?yàn)樵谡{(diào)用構(gòu)造函數(shù)的過程中,手動(dòng)的設(shè)置了返回對(duì)象,與綁定的默認(rèn)對(duì)象被丟棄了。在上面的例子中,一個(gè)賦值給了的函數(shù)稱為匿名函數(shù),返回了另一個(gè)箭頭函數(shù)稱為匿名函數(shù)。

一、引言

在執(zhí)行上下文的創(chuàng)建階段,會(huì)分別生成變量對(duì)象,建立作用域鏈,確定this指向。this的指向,是在函數(shù)被調(diào)用的時(shí)候確定的。也就是執(zhí)行上下文被創(chuàng)建時(shí)確定的。因此,一個(gè)函數(shù)中的this指向,可以是非常靈活的

二、this對(duì)象的定義

this對(duì)象代表函數(shù)運(yùn)行時(shí),自動(dòng)生成的一個(gè)內(nèi)部對(duì)象,只能在函數(shù)內(nèi)部使用
在全局執(zhí)行環(huán)境中(在任何函數(shù)體外部)this 都指向全局對(duì)象。
在函數(shù)內(nèi)部,this的值取決于函數(shù)被調(diào)用的方式。

關(guān)鍵點(diǎn):

this永遠(yuǎn)指向一個(gè)對(duì)象,并且擁有著個(gè)對(duì)象的值

在嚴(yán)格模式下,在全局作用域中和匿名函數(shù)中,this指向undefined

當(dāng)this在一個(gè)函數(shù)內(nèi)出現(xiàn)的時(shí)候,this指向調(diào)用這個(gè)函數(shù)的對(duì)象

三、this指向 全局環(huán)境
無論是否在嚴(yán)格模式下,在全局執(zhí)行環(huán)境中(在任何函數(shù)體外部)this 都指向全局對(duì)象。
// 在瀏覽器中, window 對(duì)象同時(shí)也是全局對(duì)象:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
函數(shù)(運(yùn)行)環(huán)境

在函數(shù)內(nèi)部,this的值取決于函數(shù)被調(diào)用的方式。

1.對(duì)象方法調(diào)用模式
當(dāng)函數(shù)作為對(duì)象里的方法被調(diào)用時(shí), this 指向調(diào)用該方法的對(duì)象

如果函數(shù)作為一個(gè)對(duì)象的屬性方法,并且被調(diào)用的時(shí)候,那么這個(gè)屬性方法中的this 就指向這個(gè)對(duì)象
下面的例子中,當(dāng) o.f()被調(diào)用時(shí),函數(shù)內(nèi)的this將綁定到o對(duì)象。

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

請(qǐng)注意,這樣的行為,根本不受函數(shù)定義方式或位置的影響。在前面的例子中,我們在定義對(duì)象o的同時(shí),將函數(shù)內(nèi)聯(lián)定義為成員 f 。但是,我們也可以先定義函數(shù),然后再將其附屬到o.f。這樣做會(huì)導(dǎo)致相同的行為:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

這表明函數(shù)是從o的f成員調(diào)用的才是重點(diǎn)。

同樣,this 的綁定只受最靠近的成員引用的影響。在下面的這個(gè)例子中,我們把一個(gè)方法g當(dāng)作對(duì)象o.b的函數(shù)調(diào)用。在這次執(zhí)行期間,函數(shù)中的this將指向o.b。事實(shí)證明,這與他是對(duì)象 o 的成員沒有多大關(guān)系,最靠近的引用才是最重要的。

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
2.函數(shù)調(diào)用模式
如果是普通函數(shù)調(diào)用方式。非嚴(yán)格模式下,this指向window,嚴(yán)格模式下,thisundefined;

非嚴(yán)格模式下,this 的值默認(rèn)指向全局對(duì)象。在瀏覽器中,全局對(duì)象是window

function f1(){
  return this;
}
//在瀏覽器中:
f1() === window;   //在瀏覽器中,全局對(duì)象是window

//在Node中:
f1() === global;

在嚴(yán)格模式下,this將保持他進(jìn)入執(zhí)行環(huán)境時(shí)的值,所以下面的this將會(huì)默認(rèn)為undefined。

function f2(){
  "use strict"; // 這里是嚴(yán)格模式
  return this;
}

f2() === undefined; // true

所以,在嚴(yán)格模式下,如果 this 沒有被執(zhí)行環(huán)境(execution context)定義,那它將保持為 undefined。

3.構(gòu)造函數(shù)調(diào)用模式

如果是構(gòu)造函數(shù)調(diào)用方式,this指向實(shí)例化出來的新對(duì)象

/*
 * 構(gòu)造函數(shù)這樣工作:
 *
 * function MyConstructor(){
 *   // 函數(shù)實(shí)體寫在這里
 *   // 根據(jù)需要在this上創(chuàng)建屬性,然后賦值給它們,比如:
 *   this.fum = "nom";
 *   // 等等...
 *
 *   // 如果函數(shù)具有返回對(duì)象的return語句,
 *   // 則該對(duì)象將是 new 表達(dá)式的結(jié)果。 
 *   // 否則,表達(dá)式的結(jié)果是當(dāng)前綁定到 this 的對(duì)象。
 *   //(即通??吹降某R娗闆r)。
 * }
 */


function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37

雖然構(gòu)造器返回的默認(rèn)值是this所指的那個(gè)對(duì)象,但它仍可以手動(dòng)返回其他的對(duì)象(如果返回值不是一個(gè)對(duì)象,則返回this對(duì)象)。

function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

在剛剛的例子中(C2),因?yàn)樵谡{(diào)用構(gòu)造函數(shù)的過程中,手動(dòng)的設(shè)置了返回對(duì)象,與this綁定的默認(rèn)對(duì)象被丟棄了。(這基本上使得語句 “this.a = 37;”成了“僵尸”代碼,實(shí)際上并不是真正的“僵尸”,這條語句執(zhí)行了,但是對(duì)于外部沒有任何影響,因此完全可以忽略它)。

4.call / apply 調(diào)用模式
call()、apply()方式調(diào)用,this指向被綁定的對(duì)象;

如果要想把 this 的值從一個(gè)環(huán)境傳到另一個(gè),就要用 call 或者apply 方法。

// 將一個(gè)對(duì)象作為call和apply的第一個(gè)參數(shù),this會(huì)被綁定到這個(gè)對(duì)象。
var obj = {a: "Custom"};

// 這個(gè)屬性是在global對(duì)象定義的。
var a = "Global";

function whatsThis(arg) {
  return this.a;  // this的值取決于函數(shù)的調(diào)用方式
}

whatsThis();          // "Global"
whatsThis.call(obj);  // "Custom"
whatsThis.apply(obj); // "Custom"

當(dāng)一個(gè)函數(shù)在其主體中使用 this 關(guān)鍵字時(shí),可以通過使用函數(shù)繼承自Function.prototypecallapply 方法將 this 值綁定到調(diào)用中的特定對(duì)象

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一個(gè)參數(shù)是作為‘this’使用的對(duì)象
// 后續(xù)參數(shù)作為參數(shù)傳遞給函數(shù)調(diào)用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// 第一個(gè)參數(shù)也是作為‘this’使用的對(duì)象
// 第二個(gè)參數(shù)是一個(gè)數(shù)組,數(shù)組里的元素用作函數(shù)調(diào)用中的參數(shù)
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

使用 call 和 apply 函數(shù)的時(shí)候要注意,如果傳遞給 this 的值不是一個(gè)對(duì)象,JavaScript 會(huì)嘗試使用內(nèi)部 ToObject 操作將其轉(zhuǎn)換為對(duì)象。因此,如果傳遞的值是一個(gè)原始值比如 7 或 "foo",那么就會(huì)使用相關(guān)構(gòu)造函數(shù)將它轉(zhuǎn)換為對(duì)象,所以原始值 7 會(huì)被轉(zhuǎn)換為對(duì)象,像 new Number(7) 這樣,而字符串 "foo" 轉(zhuǎn)化成 new String("foo") 這樣,例如:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隱式轉(zhuǎn)換為對(duì)象
bar.call(7); // [object Number]
5.bind方法調(diào)用
bind()方式調(diào)用,this指向被綁定的對(duì)象;

ECMAScript 5 引入了 Function.prototype.bind。調(diào)用f.bind(someObject)會(huì)創(chuàng)建一個(gè)與f具有相同函數(shù)體和作用域的函數(shù),但是在這個(gè)新函數(shù)中,this永久地被綁定到了bind的第一個(gè)參數(shù),無論這個(gè)函數(shù)是如何被調(diào)用的。

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:"yoo"}); // bind只生效一次!
console.log(h()); // azerty

var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
6.箭頭函數(shù)
在箭頭函數(shù)中,this與封閉詞法環(huán)境的this保持一致。在全局代碼中,它將被設(shè)置為全局對(duì)象:

如果是箭頭函數(shù),是根據(jù)當(dāng)前的詞法作用域來決定this, 具體來說,箭頭函數(shù)會(huì)繼承外層函數(shù)調(diào)用的this綁定。

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

注意:如果將this傳遞給call、bind、或者apply,它將被忽略。不過你仍然可以為調(diào)用添加參數(shù),不過第一個(gè)參數(shù)(thisArg)應(yīng)該設(shè)置為null。

// 接著上面的代碼
// 作為對(duì)象的一個(gè)方法調(diào)用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// 嘗試使用call來設(shè)定this
console.log(foo.call(obj) === globalObject); // true

// 嘗試使用bind來設(shè)定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

無論如何,foo 的 this 被設(shè)置為他被創(chuàng)建時(shí)的環(huán)境(在上面的例子中,就是全局對(duì)象)。這同樣適用于在其他函數(shù)內(nèi)創(chuàng)建的箭頭函數(shù):這些箭頭函數(shù)的this被設(shè)置為封閉的詞法環(huán)境的。

// 創(chuàng)建一個(gè)含有bar方法的obj對(duì)象,
// bar返回一個(gè)函數(shù),
// 這個(gè)函數(shù)返回this,
// 這個(gè)返回的函數(shù)是以箭頭函數(shù)創(chuàng)建的,
// 所以它的this被永久綁定到了它外層函數(shù)的this。
// bar的值可以在調(diào)用中設(shè)置,這反過來又設(shè)置了返回函數(shù)的值。
var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

// 作為obj對(duì)象的一個(gè)方法來調(diào)用bar,把它的this綁定到obj。
// 將返回的函數(shù)的引用賦值給fn。
var fn = obj.bar();

// 直接調(diào)用fn而不設(shè)置this,
// 通常(即不使用箭頭函數(shù)的情況)默認(rèn)為全局對(duì)象
// 若在嚴(yán)格模式則為undefined
console.log(fn() === obj); // true

// 但是注意,如果你只是引用obj的方法,
// 而沒有調(diào)用它
var fn2 = obj.bar;
// 那么調(diào)用箭頭函數(shù)后,this指向window,因?yàn)樗鼜?bar 繼承了this。
console.log(fn2()() == window); // true

在上面的例子中,一個(gè)賦值給了 obj.bar的函數(shù)(稱為匿名函數(shù) A),返回了另一個(gè)箭頭函數(shù)(稱為匿名函數(shù) B)。因此,在 A 調(diào)用時(shí),函數(shù)B的this被永久設(shè)置為obj.bar(函數(shù)A)的this。當(dāng)返回的函數(shù)(函數(shù)B)被調(diào)用時(shí),它this始終是最初設(shè)置的。在上面的代碼示例中,函數(shù)B的this被設(shè)置為函數(shù)A的this,即obj,所以即使被調(diào)用的方式通常將其設(shè)置為 undefined全局對(duì)象(或者如前面示例中的其他全局執(zhí)行環(huán)境中的方法),它的 this 也仍然是 obj

7.原型鏈的this
在對(duì)象原型鏈上某處定義的方法,this指向的是調(diào)用這個(gè)方法的對(duì)象

對(duì)于在對(duì)象原型鏈上某處定義的方法,同樣的概念也適用。如果該方法存在于一個(gè)對(duì)象的原型鏈上,那么this指向的是調(diào)用這個(gè)方法的對(duì)象,就像該方法在對(duì)象上一樣。

var o = {
  f: function() { 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

在這個(gè)例子中,對(duì)象p沒有屬于它自己的f屬性,它的f屬性繼承自它的原型。雖然在對(duì) f 的查找過程中,最終是在 o 中找到 f 屬性的,這并沒有關(guān)系;查找過程首先從 p.f的引用開始,所以函數(shù)中的 this 指向p。也就是說,因?yàn)?b>f是作為p的方法調(diào)用的,所以它的this指向了p。這是 JavaScript 的原型繼承中的一個(gè)有趣的特性。

8.getter 與 setter 中的 this
當(dāng)函數(shù)在一個(gè) getter 或者 setter 中被調(diào)用。用作 getter 或 setter 的函數(shù)都會(huì)把 this
綁定到設(shè)置或獲取屬性的對(duì)象
function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, "sum", {
    get: sum, enumerable: true, configurable: true});

console.log(o.average, o.sum); // logs 2, 6
9.作為一個(gè)DOM事件處理函數(shù)
當(dāng)函數(shù)被用作事件處理函數(shù)時(shí),它的this指向觸發(fā)事件的元素(一些瀏覽器在使用非addEventListener的函數(shù)動(dòng)態(tài)添加監(jiān)聽函數(shù)時(shí)不遵守這個(gè)約定)。
// 被調(diào)用時(shí),將關(guān)聯(lián)的元素變成藍(lán)色
function bluify(e){
  console.log(this === e.currentTarget); // 總是 true

  // 當(dāng) currentTarget 和 target 是同一個(gè)對(duì)象時(shí)為 true
  console.log(this === e.target);        
  this.style.backgroundColor = "#A5D9F3";
}

// 獲取文檔中的所有元素的列表
var elements = document.getElementsByTagName("*");

// 將bluify作為元素的點(diǎn)擊監(jiān)聽函數(shù),當(dāng)元素被點(diǎn)擊時(shí),就會(huì)變成藍(lán)色
for(var i=0 ; i
10.作為一個(gè)內(nèi)聯(lián)事件處理函數(shù)
當(dāng)代碼被內(nèi)聯(lián)on-event 處理函數(shù)調(diào)用時(shí),它的this指向監(jiān)聽器所在的DOM元素

上面的 alert 會(huì)顯示button。注意只有外層代碼中的this是這樣設(shè)置的:


在這種情況下,沒有設(shè)置內(nèi)部函數(shù)的this,所以它指向 global/window 對(duì)象(即非嚴(yán)格模式下調(diào)用的函數(shù)未設(shè)置this時(shí)指向的默認(rèn)對(duì)象)。

11.作為定時(shí)器的參數(shù)
作為定時(shí)器的參數(shù)時(shí), this 指向 window
setInterval(function() {
    console.log(this);
}, 1000);

如果你覺得這篇文章對(duì)你有所幫助,那就順便點(diǎn)個(gè)贊吧,點(diǎn)點(diǎn)關(guān)注不迷路~

黑芝麻哇,白芝麻發(fā),黑芝麻白芝麻哇發(fā)哈!

前端哇發(fā)哈

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103394.html

相關(guān)文章

  • 大話javascript 2:執(zhí)行上下文與執(zhí)行上下文棧

    摘要:在中,通過棧的存取方式來管理執(zhí)行上下文,我們可稱其為執(zhí)行棧,或函數(shù)調(diào)用棧。因?yàn)閳?zhí)行中最先進(jìn)入全局環(huán)境,所以處于棧底的永遠(yuǎn)是全局環(huán)境的執(zhí)行上下文。 一、什么是執(zhí)行上下文? 執(zhí)行上下文(Execution Context): 函數(shù)執(zhí)行前進(jìn)行的準(zhǔn)備工作(也稱執(zhí)行上下文環(huán)境) JavaScript在執(zhí)行一個(gè)代碼段之前,即解析(預(yù)處理)階段,會(huì)先進(jìn)行一些準(zhǔn)備工作,例如掃描JS中var定義的變量、...

    denson 評(píng)論0 收藏0
  • 大話javascript 3:閉包

    摘要:由此可知閉包是函數(shù)的執(zhí)行環(huán)境以及執(zhí)行環(huán)境中的函數(shù)組合而構(gòu)成的。此時(shí)產(chǎn)生了閉包。二閉包的作用閉包的特點(diǎn)是讀取函數(shù)內(nèi)部局部變量,并將局部變量保存在內(nèi)存,延長其生命周期。三閉包的問題使用閉包會(huì)將局部變量保持在內(nèi)存中,所以會(huì)占用大量內(nèi)存,影響性能。 一、什么是閉包 1.閉包的定義 閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境(包含自由變量)。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何...

    Freelander 評(píng)論0 收藏0
  • 大話javascript 4:事件循環(huán)(3)

    摘要:令人困惑的是,文檔中稱,指定的回調(diào)函數(shù),總是排在前面。另外,由于指定的回調(diào)函數(shù)是在本次事件循環(huán)觸發(fā),而指定的是在下次事件循環(huán)觸發(fā),所以很顯然,前者總是比后者發(fā)生得早,而且執(zhí)行效率也高因?yàn)椴挥脵z查任務(wù)隊(duì)列。 一、定時(shí)器 除了放置異步任務(wù)的事件,任務(wù)隊(duì)列還可以放置定時(shí)事件,即指定某些代碼在多少時(shí)間之后執(zhí)行。這叫做定時(shí)器(timer)功能,也就是定時(shí)執(zhí)行的代碼。 定時(shí)器功能主要由setTim...

    liujs 評(píng)論0 收藏0
  • 【進(jìn)階3-5深度解析 new 原理及模擬實(shí)現(xiàn)

    摘要:使用指定的參數(shù)調(diào)用構(gòu)造函數(shù),并將綁定到新創(chuàng)建的對(duì)象。由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。情況返回以外的基本類型實(shí)例中只能訪問到構(gòu)造函數(shù)中的屬性,和情況完全相反,結(jié)果相當(dāng)于沒有返回值。 定義 new 運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。 ——(來自于MDN) 舉個(gè)栗子 function Car(color) { this.color = co...

    Baaaan 評(píng)論0 收藏0
  • 大話javascript 4:事件循環(huán)(1)

    摘要:腳本執(zhí)行,事件處理等。引擎線程,也稱為內(nèi)核,負(fù)責(zé)處理腳本程序,例如引擎。事件觸發(fā)線程,用來控制事件循環(huán)可以理解為,引擎線程自己都忙不過來,需要瀏覽器另開線程協(xié)助。異步請(qǐng)求線程,也就是發(fā)出請(qǐng)求后,接收響應(yīng)檢測狀態(tài)變更等都是這個(gè)線程管理的。 一、進(jìn)程與線程 現(xiàn)代操作系統(tǒng)比如Mac OS X,UNIX,Linux,Windows等,都是支持多任務(wù)的操作系統(tǒng)。 什么叫多任務(wù)呢?簡單地說,就是操...

    codergarden 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<