• (译文)掌握JavaScript基础理解this关键字的新思路


    普通函数

    下面这种就是普通函数

    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
    作者知乎/公众号:前端疯 (一群热爱前端的一线程序员维护,想要用前端改变世界。)

  • 相关阅读:
    [转]C# const和static readonly区别
    【整理】C#文件操作大全(SamWang)
    【类】C#计算器类(SamWang)
    [转]数据结构(C#版)概念整理
    【类】C# 文件操作类(SamWang)
    【原创】C# 实现拖拉控件改变位置与大小(SamWang)(附源代码下载)
    [转]关于release和debug的区别
    ASCII码值表
    Flex 4自定义皮肤的使用方法
    C++ 动态链接库 显式调用
  • 原文地址:https://www.cnblogs.com/xunxing/p/0257e43bb49e437e2fe3af88ee7ecef9.html
Copyright © 2020-2023  润新知