最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • ES6 class 该注意的细节

    正文概述 掘金(mttt)   2021-04-05   744

    ES6class该注意的细节

    区分函数的多种的角色

    // 函数/构造函数
    function Fn(name) {
        this.x = 100;
        this.name = name;
    }
    // 作为原型,和「类/实例」有关
    Fn.prototype.y = 200;
    Fn.prototype.getX = function () {};
    Fn.prototype.getName = function () {};
    // 作为对象,和前面没有直接的关系
    Fn.x = 1000;
    Fn.getX = function () {};
    
    Fn.getX();//对象的成员访问
    new Fn().getX();//实例上的getX()方法
    Fn(); //当做普通函数执行,返回undefined
    

    上面是依据ES5的形式创造一个类

    ES6中可以使用class关键字创建类

    class Fn {}
    Fn();
    

    报错,Uncaught TypeError: Class constructor Fn cannot be invoked without 'new'
    基于class声明的构造函数必须基于new执行,不允许当做普通函数执行

    如何在es5中模拟这种判断?

    如果是new执行,那么当前this一定是当前构造函数的实例,如果不是构造函数的实例,就说明不是new执行,就抛出错误

    function Sum() {
        if (!(this instanceof Sum)) throw new TypeError('constructor Sum cannot be invoked without new');
        console.log('OK');
    }
    // Sum();//报错
    new Sum();
    

    构造函数

    class Fn {
        // 构造函数体
        constructor(name) {
            // this -> 创造的实例对象 「this.xxx=xxx设置的私有属性」
            // this.x = 100;
            this.name = name;
            //如果返回对象,以返回的为主,否则返回实例对象
        }
     }
    

    constructor就是其构造函数体

    私有属性简易写法

    class Fn {
        constructor(name) {
            this.name = name;
        }
        x = 100; //等价于构造函数体中的“this.x=100”
    }
    

    但是构造函数中如果有了this.x=xxx,那么以构造函数中的最终赋值为准

    原型上的内容设置

    class不能在原型上设置属性,只能设置函数,为什么会有这个特性,一会再说

    class Fn {
        constructor() {}
        y = 200; //等价于构造函数体中的“this.x=100”,并不是在原型上设置属性y
        getX() {}//这里的方法是设置在原型上的
        getName() {}
    }
    Fn.prototype.y = 200
    

    用这种方法设置在原型上的函数是没有prototype的,类似于:obj={fn(){}}

    如果想在原型上设置属性,只能用原来的方法写:Fn.prototype.y = 200

    ES6 class 该注意的细节

    将类看做普通对象,设置私有属性

    将类看做普通对象添加属性和方法,在class中,叫做静态私有属性和方法

    class Fn {
        constructor() {}
        y = 200; //等价于构造函数体中的“this.x=100”,并不是在原型上设置属性y
        getX() {}//这里的方法是设置在原型上的
        getName() {}
        
        static x = 1000
        static getX() {} 
    }
    

    ES6 class 该注意的细节

    以上就是如何通过es6创造一个类的过程

    区分原型上和实例上的方法

    class Fn {
        x = 100;
        getX = function () {}
        getY = ()=>{}
        
        getZ(){
            console.log(this)
        }
    }
    
    

    注意:x,getXgetY都属于一类,最后在实例的私有属性上,没有不同。而getZ这种写法是声明在原型上的

    const f = new Fn()
    f.getZ()
    Fn.prototype.getZ()
    f.getZ.call(10)
    

    所以getZ函数有可能f.getZ()执行,或者Fn.prototype.getZ()这样执行,或者call执行,其this的指向会根据不同情况改变

    ES6 class 该注意的细节

    那么如何让其中的this不随便被改变而永远指向当前实例呢?答案是使用箭头函数的写法

    class Fn {
        getX1 =  ()=>{console.log(this)}
    }
    const f = new Fn()
    f.getX1()
    f.getX1.call(10)
    

    因为箭头函数没有this,其中的this是函数上下文中的this,这个this都是Fn的实例,因为在 new 的时候,都将构造函数内部this指向了返回的实例对象。

    ES6 class 该注意的细节

    class Fn {
        getX : function () {}
        getY : ()=>{}
    }
    
    

    以上写法将报语法错误。不支持:写法。

    在react,以上特性有这样的应用: ES6 class 该注意的细节 点击按钮,输出的是undefined,因为这是react 事件中,合成事件处理的,那我想让handlethis永远是实例,如何写呢? 使用箭头函数即可

    handle = ()=>{
        console.log(this)
    }
    

    此时handle并不是原型上的函数了,而是私有属性,并且是箭头函数,所以this永远是当前实例

    使用Babel查看class到底做了什么

    我们打开Babel,将下面calss关键字语法糖代码转化为ES5,看看class语法糖到底是如何写的

    class Fn{
     constructor(){
         this.name=1
        }
      name = 2
     static name = 3
    }
    

    结果为:

    "use strict";
    
    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    
    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 Fn = function Fn() {
      _classCallCheck(this, Fn);//判断是否用new执行,如果没有用new ,那就报错
    
      _defineProperty(this, "name", 2);//先执行name=2,给实例赋值为2,并且有重名,会覆盖赋值
    
      this.name = 1;//在执行构造函数
    };
    
    _defineProperty(Fn, "name", 3);//给构造函数添加属性,相当于静态属性
    

    所以,构造函数中的this.name=1后执行,name = 2先执行

    
    class Fn{
     constructor(){
         this.name=1
        }
      name = 2
      name = 4
     static name = 3
      
      getName(){
       return this.name
      }
      getX(){
       return this.x
      }
      static getY(){
        return 'static getY'
      }
    }
    

    转化后:

    "use strict";
    
    function _classCallCheck(instance, Constructor) { if (!(instance instanceof 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 Fn = /*#__PURE__*/function () {
      function Fn() {
        _classCallCheck(this, Fn);
    
        _defineProperty(this, "name", 2);
    
        _defineProperty(this, "name", 4);
    
        this.name = 1;
      }
    
      _createClass(Fn, [{
        key: "getName",
        value: function getName() {
          return this.name;
        }
      }, {
        key: "getX",
        value: function getX() {
          return this.x;
        }
      }], [{
        key: "getY",
        value: function getY() {
          return 'static getY';
        }
      }]);
    
      return Fn;
    }();
    
    _defineProperty(Fn, "name", 3);
    

    加入实例方法和静态方法后,发现其多了一个_createClass函数,其中的逻辑是按照传入的参数的顺序不同 ,只是简单的分别向原型对象构造函数上添加方法,分别成为实例的共有方法和构造函数上的方法。

    注意:

    看了转换后就解释一个我思考过的疑问:为啥没法向原型上绑定静态的变量,而只能区分原型上的共有方法和构造函数上的静态方法呢?

    因为在转换代码里constructor(){this.name=1}和直接写name = 1是一样的作用,最终被转换成了相同意义的代码,而getName(){return this.name}getName=()=>{return this.name}则是不同逻辑,不同意义的代码

    举例如下:

    class Fn{
        constructor(){
            this.name=1
        }
      name = 2
      name = 3
        static name = 4
      
      getName(){
        return this.name
      }
      static getStaticName(){
        console.log(this)
        return this.name
      }
    }
    
    const x = new Fn()
    x.getName()//返回1
    x.getStaticName()//报错,x.getStaticName is not a function
    Fn.getStaticName()//打印class Fn ,返回4
    

    ES6 class 该注意的细节


    起源地下载网 » ES6 class 该注意的细节

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元