js中this的指向問題


this指向性問題在開發過程中,可以說是時時刻刻都在,自己也知道一些this指向的區別,但是並沒有細致的研究過,今天看到https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this里面的解釋很詳細,摘錄一些留着自己以后復習復習。

函數的 this 關鍵字在 JavaScript 中的表現略有不同,此外,在嚴格模式和非嚴格模式之間也會有一些差別。

一、在全局環境中

在全局執行環境中(在任何函數體外部),this都是指向全局對象。在瀏覽器中,window對象即是全局對象:

console.log(this); //Window
var a = 1;
console.log(window.a);  //1
this.b = 3;
console.log(b); // 3
console.log(window.b) //3

二、在函數環境中

  在函數內容,this指向取決於函數調用的方式:

function f(){
"use strict"; //使用嚴格模式
console.log(this); } f(); // window ;使用嚴格模式時,輸出undefined
這里我理解為實際調用函數的是瀏覽器的window.f();實際並非如果,在嚴格模式下,返回值:false,因為f是被直接調用的,而不是作為對象的屬性或方法調用的(如 window.f())。瀏覽器可能在支持嚴格模式時沒有正確實現這個功能,於是它們錯誤地返回了window對象。
this指向如何發生改變?
1、一般想到的是call和apply方法:將一個對象作為call或者apply的第一個參數,this將會被綁定到這個參數對象上
var obj = {parent:'男'};
var parent = '28';
function child(obj){
    console.log(this.parent);
}
child(); // 28  
child.call(obj); //
child.apply(obj); //

2、bind方法,調用f.bind(someObject)會創建一個與f具有相同函數體和作用域的函數,但是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管函數是怎樣調用的。

function f(){
  return this.a;
}
var g = f.bind({a:"js"});
console.log(g()); // js

var h = g.bind({a:'html'}); // this已經被綁定bind的第一個參數,不會重復綁定,輸出的值還是js
console.log(h()); // js

var o = {a:css, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // css, js, js

3、箭頭函數

官方有解釋,箭頭函數引入的其中一個原因,就是其不綁定this;在箭頭函數中,箭頭函數的this被設置為封閉的詞法環境的,換句話說,箭頭函數中的this取決於該函數被創建時的環境。

var objProject = this;
var foo = (() => this);
console.log(foo());  // window
console.log(objProject);  // window
console.log(foo() === objProject ); // true
// 作為對象的一個方法調用
var obj = {foo: foo};
console.log(obj.foo() === objProject ); // true
// 嘗試使用call來設定this
console.log(foo.call(obj) === objProject ); // true
// 嘗試使用bind來設定this
foo = foo.bind(obj);
console.log(foo() === objProject ); // true

4、作為對象的方法調用時

當函數作為對象的方法被調用時,this指向調用的該函數的對象:

var obj = {
  a: 37,
  fn: function() {
    return this.a;
  }
};
console.log(obj.fn());  // 37

請注意,這樣的行為,根本不受函數定義方式或位置的影響。在前面的例子中,我們在定義對象obj的同時,將函數內聯定義為成員 fn。但是,我們也可以先定義函數,然后再將其附屬到obj.fn。這樣做會導致相同的行為:

var obj = {a: 47};
function independent() {
  return this.a;
}
obj.fn = independent;
console.log(obj);  //{a:47,fn:f}
console.log(obj.fn()); //  47

對於在對象原型鏈上某處定義的方法,this指向的是調用這個方法的對象,就像該方法在對象上一樣

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

在這個例子中,對象p沒有屬於它自己的f屬性,它的f屬性繼承自它的原型。雖然在對 f 的查找過程中,最終是在 o 中找到 f 屬性的,這並沒有關系;查找過程首先從 p.f 的引用開始,所以函數中的 this 指向p。也就是說,因為f是作為p的方法調用的,所以它的this指向了p

5、作為構造函數

當一個函數用作構造函數時(使用new關鍵字),它的this被綁定到正在構造的新對象。

雖然構造器返回的默認值是this所指的那個對象,但它仍可以手動返回其他的對象(如果返回值不是一個對象,則返回this對象)。

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

var o = new C();
console.log(o.a); //  37
function C2(){
  this.a = 37;
  return {a:38};
}
o = new C2();
console.log(o.a); //  38,手動設置了返回對象

6、作為DOM事件處理函數

當函數被用作事件處理函數時,它的this指向觸發事件的元素(一些瀏覽器在使用非addEventListener的函數動態添加監聽函數時不遵守這個約定)。

// 被調用時,將關聯的元素變成藍色
function bluify(e){
  console.log(this === e.currentTarget); // 總是 true
  // 當 currentTarget 和 target 是同一個對象時為 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}
// 獲取文檔中的所有元素的列表
var elements = document.getElementsByTagName('*');
// 將bluify作為元素的點擊監聽函數,當元素被點擊時,就會變成藍色
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

關於this問題的一道面試題:

var baz = 0;
let foo = {
    bar:function() {
        console.log(this,this.baz); 
        return this.baz;
    },
    baz:1
};
let foo2 = {
    baz:2
};

let a = foo.bar();  //作為對象的方法調用,this指向調用函數的對象,即foo
let b = foo.bar.call(foo2); //使用call方法將this綁定到第一個參數對象向,此時,this指向foo2
let fn = foo.bar;
console.log(fn);
let c = fn(); //let fn創建的對象,此時,fn = function(){...},此時函數執行時,默認指向全局window對象
let d;
(function test(){
  d = arguments[0]()
})(foo.bar);   // arguments.callee包括了一個函數的引用去創建一個arguments對象,它能讓一個匿名函數很方便的指向本身,即此時this指向arguments類數組對象
console.log(a,b,c,d);

結果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM