javascript中this的指向問題


使用 JavaScript 開發的時候,很多開發者多多少少會被 this 的指向搞蒙圈,但是實際上,關於 this 的指向,記住最核心的一句話: 

哪個對象調用函數,函數里面的this指向哪個對象。

分幾種情況談論下:

一、普通函數調用

二、對象函數調用

三、構造函數調用

四、apply和call調用

五、箭頭函數調用

文章同步交流社區地址:http://www.mwcxs.top/page/427.html

 

一、普通函數調用

這個情況沒特殊意外,就是指向全局對象-window。

1、使用let

/*普通函數調用*/
let username = "程新松";
function fn(){
    console.log(this.username);   //undefined
}
fn();

使用node輸出的是:undefined

使用谷歌瀏覽器console輸出的是:undefined

 

2、使用var

var name = "程新松";
function fn(){
    console.log(this.name);
}
fn();

使用node輸出的是:undefined

使用谷歌瀏覽器console輸出的是:程新松

 

3、使用window

window.username='程新松'
function fn(){
    console.log(this.username);
}
fn();

使用node輸出的是:報錯,window沒有定義

使用谷歌瀏覽器console輸出的是:

 

PS:為什么會出現這個錯誤呢,因為node里面沒有window 對象,瀏覽器中有window對象。

 

4、let和var區別:

(1)let 允許把變量的作用域限制在塊級域中;var 申明變量要么是全局的,要么是函數級的,而無法是塊級的。

let varClass = function(){
    var name='程新松';
    if(true){
        var name='saucxs';
        console.log(name);
    }
    console.log(name);
}
varClass();
// saucxs
// saucxs

let letClass = function(){
    let name='程新松';
    if(true){
        let name='saucxs';
        console.log(name);
    }
    console.log(name);
}
letClass(); 

上面的結果說明了let只在{}內使用。

(2)先let后var

let subClass = function(){
    let name='程新松';
    if(true){
        var name='saucxs';
        console.log(name);
    }
    console.log(name);
}
subClass();

var 是函數級作用域,相當於一個作用域中有兩個n的變量了

var 作用於整個 subClass ,和let沖突了,let不能重復聲明,already been declared=已經被聲明

 (3)先var后let

let subClass = function(){
    var name='程新松';
    if(true){
        let name='saucxs';
        console.log(name);
    }
    console.log(name);
}
subClass();

先申明var,再申明let,這個沒有問題。

 

二、對象函數調用

 這個相信不難理解,就是哪個函數調用,this指向哪里

/*對象函數調用*/
//window.name='程新松';
//var name='程新松';
let name='程新松';
let obj={
    id:201102304,
    fn:function(){
        console.log(this.name);  //undefined
        console.log(this.id);   //201102304
    }
}
obj.fn();

,,

很明顯,第一次就是輸出 obj.name ,但是沒有這個name屬性,輸出的結果undefined。而第二次輸出obj.id,有這個id屬性,輸出 201102304,因為 this 指向 obj 。

 有一種情況需要注意:

/*需要注意的情況*/
let obj1={
    a:111
}
let obj2={
    a:222,
    fn:function(){
        console.log(this.a);
    }
}
obj1.fn=obj2.fn;
obj1.fn();  //111

 

這個也不難理解,雖然 obj1.fn 是從 obj2.fn 賦值而來,但是調用函數的是 obj1 ,所以 this 指向 obj1 。

 

三、構造函數調用

/*構造函數調用*/
let structureClass=function(){
    this.name='程新松';
}
let subClass1=new structureClass();
console.log(subClass1.name);

let subClass=new structureClass();
subClass.name='成才';
console.log(subClass.name);

但是有一個坑,雖然一般不會出現,但是有必要提一下。

在構造函數里面返回一個對象,會直接返回這個對象,而不是執行構造函數后創建的對象

let structureClass=function(){
    this.name='程新松';
    return {
        username:'saucxs'
    }
}
let subClass1=new structureClass();
console.log(subClass1);
console.log(subClass1.name);

 

 四、apply和call調用

 1、apply和call簡單來說就是會改變傳入函數的this。

/*apply和call調用*/
let obj1={
    name:'程新松'
};
let obj2={
    name:'saucxs',
    fn:function(){
        console.log(this.name);
    }
}
obj2.fn.call(obj1);

此時雖然是 obj2 調用方法,但是使用 了 call ,動態的把 this 指向到 obj1 。相當於這個 obj2.fn 這個執行環境是 obj1 。

call 和 apply 兩個主要用途:

1.改變 this 的指向(把 this 從 obj2 指向到 obj1 )

2.方法借用( obj1 沒有 fn ,只是借用 obj2 方法)

 

2、call與apply區別

 call 和 apply 的作用,完全一樣,唯一的區別就是在參數上面。

call 接收的參數不固定,第一個參數是函數體內 this 的指向,第二個參數以下是依次傳入的參數。

apply接收兩個參數,第一個參數也是函數體內 this 的指向。第二個參數是一個集合對象(數組或者類數組)

/*apply和call區別*/
let fn=function(a,b,c){
    console.log(a,b,c);
}
let arrArray=[1,2,3];
fn.call(window,arrArray);
fn.apply(window,arrArray);

 

  五、箭頭函數調用

 首先不得不說,ES6 提供了箭頭函數,增加了我們的開發效率,但是在箭頭函數里面,沒有 this ,箭頭函數里面的 this 是繼承外面的環境

/*箭頭函數調用*/
let obj={
    name:'程新松',
    fn:function(){
        setTimeout(function(){console.log(this.name)})
    }
}
obj.fn();

不難發現,雖然 fn() 里面的 this 是指向 obj ,但是,傳給 setTimeout 的是普通函數, this 指向是 window , window 下面沒有 name ,所以這里輸出 underfind 。

 換成箭頭函數

//換成箭頭函數
let obj={
    name:"程新松",
    fn:function(){
        setTimeout(()=>{console.log(this.name)});
    }
}
obj.fn();

這次輸出 程新松 是因為,傳給 setTimeout 的是箭頭函數,然后箭頭函數里面沒有 this ,所以要向上層作用域查找,在這個例子上, setTimeout 的上層作用域是 fn 。而 fn 里面的 this 指向 obj ,所以 setTimeout 里面的箭頭函數的 this ,指向 obj 。所以輸出 程新松

 


免責聲明!

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



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