JavaScript中的this

JavaScript中的this

// this是什麼
// 全局環境中的this
// 函數中的this
// 方法中的this
// 事件中的函數中的this
// 構造函數中this
// call和apply
// bind
// 箭頭函數中的this
// 嚴格模式下的一些狀況數組

this是什麼

js中的this關鍵字是包含它的函數做爲方法被調用時所屬的對象。瀏覽器

看似很抽象的一句話,但實際理解起來比較困難,咱們能夠分3部分來理解它!
一、包含它的函數。二、做爲方法被調用時。三、所屬的對象。app

首先咱們先來看一下js中非嚴格模式下的this分別都是什麼函數

全局環境中的this

在全局執行上下文中(在任何函數體外部)this 都指代全局對象。this

// 在瀏覽器中, window 對象同時也是全局對象:
console.log(this === window); // true

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

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

函數中的this

絕大多數狀況下,函數的調用方式決定了this的值。prototype

在嚴格模式和非嚴格模式之間也會有一些差異。code

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

然而,在嚴格模式下,this將保持他進入執行上下文時的值,因此下面的this將會默認爲undefined。對象

function f2(){
  "use strict"; // 這裏是嚴格模式
  return this;
}

f2() === undefined; // true

自執行函數執行,方法中的this通常都是window繼承

var obj = {
    fn: (function() {
        // this -> window
    })()
};

~function() {
    // this -> window
}()

方法中的this

咱們說定義在對象內的函數叫作方法,而這個方法執行的時候,它的this就是它的調用者事件

var obj = {
    fn: function () {
        console.log(this);
    }
};

obj.fn();

此時fn方法的調用者爲obj,因此fn中的this就是obj對象;

但咱們把這個方法賦值給一個自由變量的時候

var f1 = obj.fn;

f1();

此時f1執行,實際是obj.fn執行,但f1的調用者其實是 window, window.f1() 因此fn中的this是window

下面再看一個例子,
咱們調用數組上的slice方法,

[].slice(); // this -> []

[].__proto__.slice(); // this -> [].__proto__

Array.prototype.slice();  // this -> Array.prototype

三種調用的slice方法是同樣的,但調用的方式不一樣,裏面的this也不一樣

事件中的函數中的this

給元素的某個事件綁定了一個方法,當事件觸發,函數執行的時候,綁定的這個方法中的this通常是當前操做的這個DOM元素

'二般'狀況下

IE6~8下,若是咱們使用DOM2事件綁定,方法執行的時候,裏面的this不是當前元素,而是window

ele.attachEvent('onclick', function() {
    console.log(this);  // window
});

構造函數中的this

構造函數執行的時候,函數體中的this都是當前實例;

function Fn() {
    // this -> 當前Fn的實例
    // this.name 是給當前實例設置私有屬性
    this.name = '1000phone'
}

var f = new Fn();

call和apply

當一個函數在其主體中使用 this 關鍵字時,能夠經過使用函數繼承自Function.prototype 的 call 或 apply 方法將 this 值綁定到調用中的特定對象。

var school = {name: '1000phone'};

function sum(num1, num2) {
    this.total = num1 + num2;
}

sum(20, 30); // this -> window

sum.call(school, 20, 30);

首先讓 sum 中的this指向call方法中的第一個參數,而後執行sum這個函數

此時 sum 中的 this -> school num1 -> 20 num2 -> 30

參數位置是固定的,若是第一個參數不是 school

sum.call(20, 30);

這時候 sum 的this 是 20,num1 -> 30 num2 -> undefined

若是咱們一個參數都不傳

sum.call();

sum 的 this -> window num1 = num2 = undefined

至關於 sum 直接執行,不傳參

sum();

但若是第一個參數爲null或者undefined
那麼就表明沒有this,函數中的this依然是window

apply語法與做用,和call相似,只有一個區別,apply傳入一組參數

sum.call(school, 20, 30);

sum.apply(school, [20, 30]);

apply的語法要求寫成一個數組,但實際和call同樣,也是一項一項的給形參賦值的

~function () {
    console.log(this);
}.call(school);

此時 自執行函數中的this被call指向爲 school

Array.prototype.slice.call(arguments);

此時slice方法執行的時候中的this將再也不是 Array.prototype,而是arguments

call和apply以前的規則,遇到call/apply時,都將以用戶自主指向的this爲主

bind

ECMAScript 5 引入了 Function.prototype.bind。調用f.bind(someObject)會建立一個與f具備相同函數體和做用域的函數,可是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管這個函數是如何被調用的。

var school = {name: '1000phone'};

function sum(num1, num2) {
    this.total = num1 + num2;
}

sum.call(school, 20, 30);

this -> school 而且執行sum

sum.bind(school, 20, 30);

雖然改變了this指向,但並無執行sum,它是預先處理this和實參,不會當即執行,

一般咱們讓它在某個特定條件,纔會被觸發 IE6~8不兼容

例如咱們有個需求,一秒後執行sum,此時須要定時器,執行sum時,sum中this指向school,而且傳參。

setTimeout(sum, 1000);

咱們一秒後執行sum函數

但此時sum中的this是window

setTimeout(sum.call(school, 20, 30), 1000);

此時實現了this的指向而且傳了參數,但sum當即執行了,不是一秒後

setTimeout(function() {
    sum.call(school, 20, 30);
}, 1000);

咱們能夠達到一秒後執行sum,this指向爲shool,而且傳參,執行,但代碼並不理想,咱們能夠使用bind預處理可以達到咱們的目的

setTimeout(sum.bind(school, 20, 30), 1000);

箭頭函數中的this

var obj = {
    fn: function() {

        setTimeout(function() {
            // this -> window
        }, 1000);

        var that = this;
        setTimeout(function() {
            // that -> obj
        }, 1000);

        setTimeout(function() {
            // this -> obj
        }.bind(this), 1000);

        setTimeout(() => {
            // this -> obj
        }, 1000);
    }
};

在箭頭函數中,this與封閉詞法上下文的this保持一致,也就是說箭頭函數中繼承了詞法做用域的this

嚴格模式下

非嚴格模式下,不明確執行主體,瀏覽器認爲執行主體默認爲window,因此this是window

嚴格模式下,執行主體不明確,this是undefined

'use strict'

~function(){
    // this -> undefined
}();

fn() // undefined

window.fn()  // window

fn.call() // undefined

fn.call(window) // window

fn.call(null) // null

fn.call(undefined) // undefined

apply同call

能夠理解爲含有this的函數的調用者。而且this和函數在哪執行的,以及定義的位置沒有直接關係。

歡迎來噴!

相關文章
相關標籤/搜索