1. 程式人生 > >掌握JavaScript基礎--理解this關鍵字的新思路

掌握JavaScript基礎--理解this關鍵字的新思路

handle 無法 公眾號 post tom image gpo alter IT

普通函數

下面這種就是普通函數

function add(x, y) {
    return x + y;
}

每個普通函數被調用的時候,都相當於有一個this參數傳進來。
內部函數this不會是外部函數傳入的this,相當於和外部的this隔離開了。

function outer() {
    function inner() {
        console.log(this); // window
    }
    console.log(this); // ‘outer‘
    inner();
}
outer.call(‘outer‘);

相當於:

function outer(_this) {
    function inner(_this) {
        console.log(_this); // undefined
    }
    console.log(_this); // ‘outer‘
    inner(undefined);
}
outer(‘outer‘);

箭頭函數

const add = (x, y) => {
    return x + y;
};

如果你用箭頭函數,內部函數的this和外部是一致的:

function outer() {
    const inner = () => {
        console.log(this); // ‘outer‘
    };
    console.log(this); // ‘outer‘
    inner();
}
outer.call(‘outer‘);

箭頭函數的this不會被call方法影響,它總是和箭頭函數所在的位置有關:
它所在的位置(也就是作用域)的this指向誰,箭頭函數裏面的this就指向誰。

function ordinary() {
    const arrow = () => this;
    console.log(arrow.call(‘goodbye‘)); // ‘hello‘
}
ordinary.call(‘hello‘);

普通函數作為方法

如果一個函數賦值給了屬性,就變成了方法:

const obj = {
    prop: function () {}
};

調用方法的方式是:

obj.prop(x, y)

相當於:

obj.prop.call(obj, x, y)

陷阱

1 回調函數裏面用this

回調裏面執行(A),你發現logStatus訪問不了。這個是因為this被阻隔了。

performCleanup() {
    cleanupAsync()
    .then(function () {
        this.logStatus(‘Done‘); // (A)
    });
}

你應該采用箭頭函數:

performCleanup() {
    cleanupAsync()
    .then(() => {
        this.logStatus(‘Done‘);
    });
}

2 map方法裏面用this
同理,this也是訪問不了company和name的

prefixNames(names) {
    return names.map(function (name) {
        return this.company + ‘: ‘ + name; // (A)
    });
}

采用箭頭函數:

// Inside a class or an object literal:
prefixNames(names) {
    return names.map(
        name => this.company + ‘: ‘ + name);
}

3 用函數作為回調

class UiComponent {
    constructor(name) {
        this.name = name;
        const button = document.getElementById(‘myButton‘);
        button.addEventListener(‘click‘, this.handleClick); // (A)
    }
    handleClick() {
        console.log(‘Clicked ‘+this.name); // (B)
    }
}

改為:

class UiComponent {
    constructor(name) {
        this.name = name;
        const button = document.getElementById(‘myButton‘);
        button.addEventListener(
            ‘click‘, this.handleClick.bind(this)); // (A)
    }
    handleClick() {
        console.log(‘Clicked ‘+this.name);
    }
}

bind函數能讓普通的函數調用無法修改this:

function returnThis() {
    return this;
}
const bound = returnThis.bind(‘hello‘);
bound(); // ‘hello‘
bound.call(undefined); // ‘hello‘

保持正確的做法

1 用ESlint的rules: no-invalid-this
避免普通函數內部有this,一般在方法內使用this或者箭頭函數內使用

2 不要把this當做參數
因為這樣你就不能用箭頭函數了

beforeEach(function () {
    this.addMatchers({ // access API object
        toBeInRange: function (start, end) {
            ···
        }
    });
});

可以很容易被改寫:

beforeEach(api => {
    api.addMatchers({
        toBeInRange(start, end) {
            ···
        }
    });
});

原文鏈接:http://2ality.com/2017/12/alternate-this.html
作者知乎/公眾號:前端瘋 (一群熱愛前端的一線程序員維護,想要用前端改變世界。)
技術分享圖片



來自為知筆記(Wiz)

掌握JavaScript基礎--理解this關鍵字的新思路