前端js中this指向及改變this指向的方法


js中this指向是一個難點,花了很長時間來整理和學習相關的知識點。

一、 this

this是JS中的關鍵字, 它始終指向了一個對象, this是一個指針;

參考博文:

  1. JavaScript函數中的this四種綁定形式
  2. this指向及改變this指向的方法

二、 this顯示綁定和隱式綁定

1. this顯示綁定

 含義: 當一個函數沒有明確的調用對象的時候, 也就是單純作為獨立函數調用的時候, 將對函數的this使用默認綁定: 綁定到全局的window對象

 在顯式綁定下: 函數將取得在“ 包含對象“ 里的永久居住權, 一直都會” 住在這里“
在這里插入圖片描述

1.1 全局函數

function fire() {
    console.log(this === window); //fire此時是全局的方法,this指向window
}
fire(); // 輸出true

1.2 函數內嵌套函數

function fire() {
    // 我是被定義在函數內部的函數哦!
    function innerFire() {
        console.log(this === window); //未明確調用對象,this指向window
    }
    innerFire(); // 獨立函數調用
}
fire(); // 輸出true
innerFire();

示例:

var a = 1;
console.log(this.a); //1 因為此時this指向了window,因而調用1
function fire() {
    var a = 2;
    console.log(this.a); //1 因為此時this指向了window,因而調用1

    function innerFire() {
        var a = 3;
        console.log(this.a); //1 因為此時this指向了window,因而調用1
    }
    innerFire();
}
fire(); //輸出1

 與作用域的區別: 全局作用域和局部作用域, 去掉this可發現區別

var a = 1;
console.log(a); //1 a在全局作用域
function fire() {
    var a = 2;
    console.log(a); // 2 fire函數作用域
    function innerFire() {
        var a = 3;
        console.log(a); //3 此時打印輸出a,a在innerFIre作用域。從自身作用域查找變量,未找到才網上查找
    }
    innerFire();
}
fire();

1.3 對象內層函數內部函數

var obj = {
    fire: function () { //此時的fire函數其實用到了隱式綁定
        function innerFire() {
            console.log(this === window); //未明確調用對象,this指向window
        }
        innerFire();
    }
}
obj.fire(); //輸出 true

示例:

var a = 1;
console.log(this.a); //1 this指向全局變量window
var obj = {
    a: 2,
    fire: function () {
        var a = 3;
        console.log(this.a); //2 因為是obj.fire(),調用了fire函數,因為this指向了obj,輸出了obj下的a=2
        function innerFire() {
            var a = 4;
            console.log(this.a); //1 未明確調用對象,this指向window
        }
        innerFire(); //沒有明確調用的對象
        console.log(this.a); //2 this指向obj
    }
}
obj.fire();

2、 this隱式綁定

a.隱式綁定

 當函數被一個對象“ 包含” 的時候, 我們稱函數的this被隱式綁定到這個對象里面, 這時候, 通過this可以直接訪問所綁定的對象里面的其他屬性, 比如下面的a屬性

 在隱式綁定下: 函數和只是暫時住在“ 包含對象“ 的旅館里面, 可能過幾天就又到另一家旅館住了
在這里插入圖片描述

var obj = {
    a: 1,
    fire: function () { //此時函數的this被隱式綁定到了對象obj
        console.log(this == obj); // obj中有fire函數,因而默認this指向obj
        console.log(this.a); // 1 this.a 相當於obj.a =1
    }
}
obj.fire(); // 輸出1 

 相同的方法:
 fire函數並不會因為它被定義在obj對象的內部和外部而有任何區別,

function fire() {
    console.log(this.a)
}

var obj = {
    a: 1,
    fire: fire
}
obj.fire(); // 輸出1

b.動態綁定:
 this實在代碼運行期綁定而不是在書寫期

var obj = {
    a: 1, // a是定義在對象obj中的屬性 1
    fire: function () {
        console.log(this.a)
    }
}
var a = 2; // a是定義在全局環境中的變量 2
obj.fire(); //1  此時fire的指向時obj
var fireInGrobal = obj.fire; //因為fireInGrobal是全局變量,this對於obj的綁定丟失,綁定到了全局window
fireInGrobal(); // 輸出 2 輸出全局變量啊
var a = 2;
var obj = {
    a: 1, // a是定義在對象obj中的屬性
    fire: function () {
        console.log(this.a)
    }
}

function otherFire(fn) { //全局函數,this綁定window
    fn();
}
otherFire(obj.fire); // 輸出2   this對於obj的綁定丟失,綁定到了全局this上面
var obj = {
    a: 1,
    obj2: {
        a: 2,
        obj3: {
            a: 3,
            getA: function () { //obj3.getA()   this綁定到了obj3當中
                console.log(this.a)
            }
        }
    }
}
obj.obj2.obj3.getA(); // 輸出3

三、 this指向

 this的指向不是由定義this決定的, 而是隨腳本解析自動賦值的。

1. 全局環境作用域: this在全局環境始終指向window


 變量形式

console.log(this === window) // true
console.log(window.alert === this.alert) // true
console.log(this.parseInt("021", 10)) // 21
var fruit = "banana"; // 定義一個全局變量,等同於window.fruit = "banana"

2. 函數環境 作用域: 函數由誰調用, this就指向誰

2.1 非嚴格模式

function fn() {
    console.log(this); //window
}
fn() === window; // true;window.fn(),此處默認省略window

2.2 嚴格模式

  a 全局環境下, this指向window

"use strict";
this.b = "MDN";
console.log(this == window) // "MDN"
console.log(b) // "MDN"

  b 函數環境下, this為undefined

function fn() {
    "use strict"; // 這里是嚴格模式
    console.log(this); //window
}
fn() === undefined //true

3 對象中的方法函數調用: 指向 該方法所屬的對象
 隱式調用

var obj = {
    a: 1,
    fn: function () {
        return this;
    }
}
console.log(obj.fn() == obj); //true  函數被obj調用,指向obj

 this動態綁定

var obj = {
    a: 1,
    fn: function () {
        return this;
    }
}
console.log(obj.fn()); //1  函數被obj調用,指向obj,輸出obj的a=1
var a = 2;
var newfun = obj.fn; //此時更改this指向為全局變量newfun
newfun(); //2 ,this訪問全局變量a=2

4 在構造函數中: this始終指向新對象
在這里插入圖片描述

function Person(age, name) {
    this.age = age;
    this.name = name
    console.log(this) // 此處 this 分別指向 Person 的實例對象 p1 p2
}
var p1 = new Person(18, 'zs')
var p2 = new Person(18, 'ww')

在這里插入圖片描述
5 通過事件綁定的方法: this 指向 綁定事件的對象

oBtn.onclick = function () {
        console.log(this); // btn
    }

    <
    button id = "btn" > hh < /button>

6 定時器函數: 因為是異步操作, this 指向 window

 延時函數內部的回調函數的this指向全局對象window( 當然我們可以通過bind方法改變其內部函數的this指向)

 我們常見的window屬性和方法有alter, document, parseInt, setTimeout, setInterval, location等等, 這些在默認的情況下是省略了window前綴的。( window.alter = alter)。

6.1 普通定時器

setInterval(function () {
    console.log(this); // window
}, 1000);

在這里插入圖片描述
6.2 定時器嵌套

function Person() {
    this.age = 0;
    setTimeout(function () {
        console.log(this);
    }, 3000);
}

var p = new Person(); //3秒后返回 window 對象

6.3 可以改變this指向 - 想見三方法

function Person() {
    this.age = 0;
    setTimeout((function () {
        console.log(this);
    }).bind(this), 3000);
}
var p = new Person(); //3秒后返回構造函數新生成的對象 Person{...}

7 自執行函數(匿名函數): 指向全局變量window

(function inner() {
    console.log(this); //this ==> window
})();

8 箭頭函數

要點:

a. 箭頭函數的this是在定義函數時綁定的, 不是在執行過程中綁定的
b. 箭頭函數中的this始終指向父級對象
c. 所有 call() / apply() / bind() 方法對於箭頭函數來說只是傳入參數, 對它的 this 毫無影響。
var obj = {
    a: 1,
    fn: () => {
        //箭頭函數中的this始終指向定義時的環境
        //箭頭函數中的this始終指向父級對象
        console.log(this); //對象內的this調用時一般指向obj,而箭頭函數在創建時就指向了obj的父級對象window
    }
}
obj.fn(); //window

四、 更改this指向

 每個Function構造函數的原型prototype, 都有方法
call(), apply(), bind()

總結:
a call(), apply()
在特定作用域調用函數
b bind()
會創建一個函數的實例, this會被綁定到bind() 函數
bing() 綁定this, bind()() 調用函數

1. call() 方法

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa(4, 5); //this指向window--4,5  window  空

aa.call(Person, 4, 5); //this指向Person--4,5  Person{}對象  zhangsan

在這里插入圖片描述
2. apply() 方法

 apply() 與call() 非常相似, 不同之處在於提供參數的方式, apply() 使用參數數組, 而不是參數列表

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa.apply(Person, [4, 5]); //this指向Person--4,5  Person{}對象  zhangsan

在這里插入圖片描述

3. bind() 方法
 bind() 創建的是一個新的函數( 稱為綁定函數), 與被調用函數有相同的函數體, 當目標函數被調用時this的值綁定到 bind() 的第一個參數上
在這里插入圖片描述

var Person = {
    name: "zhangsan",
    age: 19
}

function aa(x, y) {
    console.log(x + "," + y);
    console.log(this);
    console.log(this.name);

}

aa.bind(Person, 4, 5); //只是更改了this指向,沒有輸出
aa.bind(Person, 4, 5)(); //this指向Person--4,5  Person{}對象  zhangsan

在這里插入圖片描述
4. 存儲this指向到變量中

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    var _this = this; //將this儲存在變量中,而且不改變定時器的指向
    setTimeout(function () {
        console.log(_this); //注意這里是_this,而不是this-- <div id="div1">點擊</div>
        console.log(this); //定時器的指向沒有被改變--仍然是window
    }, 1000)
}

在這里插入圖片描述

在這里插入圖片描述

五、 改變this指向綜合案例**

1、 為更改this指向

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
        setTimeout(function () {
            console.log(this); //點擊時輸出 window對象
        }, 1000)
    }

    <
    div id = "div1" > 點擊 < /div>

在這里插入圖片描述
2、 更改this指向 - bing, call, apply
 在定時器外, 在綁定事件中的this肯定指向綁定事件的對象div啊, 用call和apply都行

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    setTimeout(function () {
        console.log(this); // 更改this指向為 <div id="div1">點擊</div>
    }.bind(this), 1000)
}

在這里插入圖片描述
3、 存儲this指向到變量中

var oDiv1 = document.getElementById("div1");
oDiv1.onclick = function () {
    var _this = this; //將this儲存在變量中,而且不改變定時器的指向
    setTimeout(function () {
        console.log(_this); //注意這里是_this,而不是this-- <div id="div1">點擊</div>
        console.log(this); //定時器的指向沒有被改變--仍然是window
    }, 1000)
}

在這里插入圖片描述
在這里插入圖片描述


免責聲明!

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



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