最新公告
  • 欢迎您访问爱上源码网,分享精品整站源码,网站模板,游戏源码,APP小程序源码以及视频教程免费下载;服务永无止境!立即加入我们
  • 箭头函数的理解

    曾经我觉得我自己已经很了解箭头函数了,不可能再被坑了。可是前几天我遇到了一个很奇怪的问题,在苦恼了很久后,发现就是箭头函数带来的坑。因此,就有了这一篇文章~

    问题描述

    比如我有一个基类 Animal,它有一个基础方法 sayName。之后每一个继承于它的子类,都需要自己实现这个 sayName 方法来证明自己的身份。基类代码实现很简单:

    class Animal {
    	sayName = () => {
    		throw new Error('你应该自己实现这个方法');
      }
    }

    那么我现在要继承于 Animal 基类来实现一个 Pig 子类,实现也很简单:

    class Pig extends Animal {
    	sayName() {
    		console.log('I am a Pig');
    	}
    }

    诶,这么简单就搞定了吗?哪里有坑啊?然而,实际上跑起来你就会发现,结果不如预期:

    爱上源码网文章箭头函数的理解的内容插图

    诶,为什么会这样呢。到底哪里出现了问题呢?这短短的几行代码,为啥就能报错呢。

    发现问题

    经过一顿折腾之后,最后发现是箭头函数的坑。我们只需要把 Animal 基类的 sayName 改为 普通函数,或者把 Pig 子类的 sayName 改为箭头函数,就可以解决这个问题。那么,箭头函数到底搞了什么鬼呢?

    写到这里,我忽然想起来,这个问题我曾经被一个面试官面试过!当时面试官问的是对于类而言,箭头函数和类普通函数、constructor 里 bind 的函数有什么区别。当时回答的头头是道,结果遇到继承的情况下,就翻水水了。那么要解答上面这个问题,那就先来解答面试的这个问题吧。

    箭头函数和类普通函数、constructor 里 bind 的函数有什么区别

    为了比较直观的看这个问题,我们可以借助 babel的代码编译结果来更好的看出区别。

    首先我们先输入一段简单的代码

    class A {
      	constructor() {
    		this.b = this.b.bind(this);    	
        }
      
        a() {
        	console.log('a');
        }
    	  b() {
        	console.log('b')
        }
        c = () => {
        	console.log('c')
        }
    }

    我们来看看会babel编译成什么样子:

    "use strict";
    
    function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
    
    function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    
    function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
    
    function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
    
    function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
    
    var A = /*#__PURE__*/function () {
      function A() {
        _classCallCheck(this, A);
    
        _defineProperty(this, "c", function () {
          console.log('c');
        });
    
        this.b = this.b.bind(this);
      }
    
      _createClass(A, [{
        key: "a",
        value: function a() {
          console.log('a');
        }
      }, {
        key: "b",
        value: function b() {
          console.log('b');
        }
      }]);
    
      return A;
    }();

    编译后的代码有一大半都是辅助的函数,我们可以只看重点的一部分:

    var A = /*#__PURE__*/function () {
      function A() {
        _classCallCheck(this, A);
    
        _defineProperty(this, "c", function () {
          console.log('c');
        });
    
        this.b = this.b.bind(this);
      }
    
      _createClass(A, [{
        key: "a",
        value: function a() {
          console.log('a');
        }
      }, {
        key: "b",
        value: function b() {
          console.log('b');
        }
      }]);
    
      return A;
    }();

    从编译后的结果,我们可以看出彼此的区别:

    • 普通函数: 在 babel 编译后,会被放在函数的 prototype 上

    • constructor 里 bind 的函数: 在编译后,它不仅会被放在函数的 prototype 里,而且每一次实例化,都会产生一个绑定当前实例上下文的变量(this.b = this.b.bind(this))。

    • 箭头函数:在 babel 编译后,每一次实例化的时候,都会调用 defineProperty 将箭头函数内容绑定在当前实例上下文上。

    从编译后的结果来看的话,对于实际开发的时候,如果需要绑定上下文的话,最好还是用箭头函数。因为使用 bind 方式的话,不仅会产生一个 prototype 的函数,每一次实例化都会额外产生多一个函数。

    更新

    看了下余腾靖的评论,了解到了更本质的东西。

    class 对于 = 号声明的方法、变量,都会将其作为实例的属性,而对于非 = 号声明的属性,则是放在原型链上。比如

    class A {
        a() {
            
        }
        b = 2;
        c = () => {
        }
    }

    对于这个类, 在实例化的时候,b, c 会作为实例的属性,而 a 则是放在原型链上。

    那么为什么会这样实现呢?其实我们可以看 tc39 的规范里就说到了这一点: Field declarations

    对于直接写等号声明的实例,其实就是 Field declarations 的语法,等于直接声明了这样一个实例属性。

    回到主题

    在我们解决了上一个问题之后,让我们回到主题。了解了类的箭头函数在实际编译情况下的编译结果后,其实对于我们那个问题就比较好理解了。

    Q: 为什么子类使用普通函数的方式声明 sayName 的时候,执行就会出问题呢。

    A: 子类使用普通函数的方式声明 sayName 的话,子类声明的 sayName 会被放在构造函数的 prototype 上。可是由于基类的 sayName 是使用箭头函数的方式,因此每一个实例都会直接有一个 sayName 变量。根据 javascript 变量的访问规则,首先会在变量本身上找,找不到后才会在原型链上找。因此,在查找 sayName 的时候,就直接找到基类声明的 sayName 函数了,就不会再在原型链上找,因此就出现了问题。

    Q: 为什么子类使用箭头函数的方式声明 sayName,执行就没有问题。

    A: es6 的类在初始化的时候,会先执行基类的构造函数,之后再执行本身的构造函数。因此,在基类初始化之后,子类声明的箭头函数 sayName 覆盖了基类的,所以执行就没有问题。

    总结

    曾经我以为我自己很了解箭头函数了,没想到还是被坑了,果然还是学无止境啊!不过也对类内箭头函数有了更深刻的认识。

    但是经过评论区各位大佬的提醒,发现其实并不是箭头函数引起的问题,在 class 里用 = 号声明的变量属于 Field declarations 的语法。对于这种写法声明的变量,其实是会直接挂载到实例的属性上面,而不是挂载到原型链上。

    推荐教程:《JS教程》

    以上就是箭头函数的理解的详细内容,更多请关注爱上源码网其它相关文章!

  • 微信
  • 分享
  • 相关标签:js
  • 本文转载于:掘金社区,如有侵犯,请联系916990011@qq.com删除
    • 上一篇:javascript中的闭包中的闭包
    • 下一篇:JavaScript 复杂判断的优雅写法

    相关文章

    相关视频

    • 12种JavaScript数组去重方法(总结)
    • 解决JavaScript中数组排序sort不发生改…
    • javascript中的split方法详解
    • 实例详解javascript中split字符串分割…
    • 箭头函数的理解
    • JavaScript函数的调用(1)
    • JavaScript变量的作用域
    • JavaScript对象(1)

    本文有爱上源码下载完入驻作者发布,如果对您版权造成侵害,可以联系本站站长管理进行维权删除,本站收到维权24小时内进行处理,谢谢您关注23ym.cn!
    本站分享大量程序员技术文章以及对编程开发的初级入门教程,包括图文讲解笔记和高清视频下载~

    重要声明:
    1.本站视频教程,软件及网站源码版权均属于原作者所有,您必须在下载后的24个小时之内,从您的电脑中删除!非法商业用途,后果自负!
    2.本站不保证所提供下载资源的安全性和完整性,仅供下载学习之用!如链接失效或资源含外站广告,请联系客服处理!给予奖励!
    3.本站所有资源来源于用户上传和网络,因此不包含技术服务请大家谅解!本站提供有偿服务!如有侵权请联系在线客服!
    4.如您手中有优质资源或教程,可以自助投稿发布,成功分享后有奖励和额外收入!
    5.如您需要正版微擎模块可联系本站客服,我们有价值30w+商业微擎应用出售微擎坑位和招收代理!
    6.400电话/软著/ICP,EDI许可证/商标特价办理中!
    爱上源码下载网 » 箭头函数的理解

    常见问题FAQ

    从网站下载的源码都有安装教程么?不会安装怎么办?
    本站发布的网站源码和模板资源大部分在压缩包内都有教程,如您不会安装可以联系本站在线技术进行付费安装。
    爱上源码的所有源码都是亲测能正常运行的么?
    本站目前拥有资源10w+,包含整站源码,网站模板,游戏源码,小程序源码,视频教程,破解软件等,每天也在测试更新;因时间和精力有限我们无法对资源进行一一测试,只能保证所分享资源内容无误,希望理解。
    我手中的优质资源可以在你这换钱或者VIP么?
    爱上源码支持投稿,欢迎发布您手中的优质资源进行售卖;本站VIP支持免费获取,目前邀请10人注册爱上源码即可免费获取VIP。
    爱上源码除了资源分享还有其他业务没?
    【价值30W+微擎模块出售正版商业微擎坑位及招收代理,详情咨询本站客服!】我们团队目前运营并推广几套商业化saas智能小程序系统能满足大部分小程序开发需求,并由SaaS和独立部署版商城小程序系统;另外销售400电话,各种ICP/EDI资质证书办理,软著和商标注册服务等。

    发表评论

    • 32会员总数(位)
    • 35644资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 656稳定运行(天)

    提供最优质的资源集合

    开通VIP 源码下载