zoukankan      html  css  js  c++  java
  • 箭头函数与普通函数的区别

    本文链接:https://lienjack.github.io/Blog/knowledge/js/3.this.html#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0

    本篇我们重点比较一下箭头函数与普通函数。

    主要区别包括:

    1.没有 this

    箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。

    这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。

    模拟一个实际开发中的例子:

    我们的需求是点击一个按钮,改变该按钮的背景色。

    为了方便开发,我们抽离一个 Button 组件,当需要使用的时候,直接:

    // 传入元素 id 值即可绑定该元素点击时改变背景色的事件
    new Button("button")
    
    

    HTML 代码如下:

    <button id="button">点击变色</button>
    
    

    JavaScript 代码如下:

    function Button(id) {
        this.element = document.querySelector("#" + id);
        this.bindEvent();
    }
    
    Button.prototype.bindEvent = function() {
        this.element.addEventListener("click", this.setBgColor, false);
    };
    
    Button.prototype.setBgColor = function() {
        this.element.style.backgroundColor = '#1abc9c'
    };
    
    var button = new Button("button");

    看着好像没有问题,结果却是报错 Uncaught TypeError: Cannot read property 'style' of undefined

    这是因为当使用 addEventListener() 为一个元素注册事件的时候,事件函数里的 this 值是该元素的引用。

    所以如果我们在 setBgColor 中 console.log(this),this 指向的是按钮元素,那 this.element 就是 undefined,报错自然就理所当然了。

    也许你会问,既然 this 都指向了按钮元素,那我们直接修改 setBgColor 函数为:

    Button.prototype.setBgColor = function() {
        this.style.backgroundColor = '#1abc9c'
    };

    所以我们还是希望 setBgColor 中的 this 是指向实例对象的,这样就可以调用其他的函数。

    利用 ES5,我们一般会这样做:

    Button.prototype.bindEvent = function() {
        this.element.addEventListener("click", this.setBgColor.bind(this), false);
    };

    为避免 addEventListener 的影响,使用 bind 强制绑定 setBgColor() 的 this 为实例对象

    使用 ES6,我们可以更好的解决这个问题:

    Button.prototype.bindEvent = function() {
        this.element.addEventListener("click", event => this.setBgColor(event), false);
    };

    由于箭头函数没有 this,所以会向外层查找 this 的值,即 bindEvent 中的 this,此时 this 指向实例对象,所以可以正确的调用 this.setBgColor 方法, 而 this.setBgColor 中的 this 也会正确指向实例对象。

    在这里再额外提一点,就是注意 bindEvent 和 setBgColor

    在这里使用的是普通函数的形式,而非箭头函数,如果我们改成箭头函数,会导致函数里的 this 指向 window 对象 (非严格模式下)。

    最后,因为箭头函数没有 this,所以也不能用 call()、apply()、bind() 这些方法改变 this 的指向,可以看一个例子:

    var value = 1;
    var result = (() => this.value).bind({value: 2})();
    console.log(result); // 1

    没有 arguments

    箭头函数没有自己的 arguments 对象,这不一定是件坏事,因为箭头函数可以访问外围函数的 arguments 对象:

    function constant() {
        return () => arguments[0]
    }
    
    var result = constant(1);
    console.log(result()); // 1

    那如果我们就是要访问箭头函数的参数呢?

    你可以通过命名参数或者 rest 参数的形式访问参数:

    不能通过 new 关键字调用

    JavaScript 函数有两个内部方法:[[Call]] 和 [[Construct]]。

    当通过 new 调用函数时,执行 [[Construct]] 方法,创建一个实例对象,然后再执行函数体,将 this 绑定到实例上。

    当直接调用的时候,执行 [[Call]] 方法,直接执行函数体。

    箭头函数并没有 [[Construct]] 方法,不能被用作构造函数,如果通过 new 的方式调用,会报错。

    var Foo = () => {};
    var foo = new Foo(); // TypeError: Foo is not a constructor

    没有 new.target

    因为不能使用 new 调用,所以也没有 new.target 值。

    没有原型

    由于不能使用 new 调用箭头函数,所以也没有构建原型的需求,于是箭头函数也不存在 prototype 这个属性。

    var Foo = () => {};
    console.log(Foo.prototype); // undefined

    没有 super

    连原型都没有,自然也不能通过 super 来访问原型的属性,所以箭头函数也是没有 super 的,不过跟 this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。

    不积跬步无以至千里
  • 相关阅读:
    顾问和注解
    正则
    GitHub 的简单使用
    JavaScript变态题目
    常用的Javascript设计模式
    HTML5 本地裁剪上传图片
    webpack 打包
    详解js闭包
    常用的Javascript设计模式
    call appiy
  • 原文地址:https://www.cnblogs.com/lyt0207/p/12083643.html
Copyright © 2011-2022 走看看