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

    正文概述 掘金(其枫)   2021-03-28   613

    前言

    相信很多同学在刚刚开始编写React的代码的时候, 都会在构造器中使用 bind 方法去绑定函数。可能刚刚开始大多人会以为这是在React中特有的操作, 其实不然, 这其实是跟JS函数的执行原理有关。随着时间的推移, 我们以前的写法已经不需要手动把函数去 bind this了, 这是为什么呢?

    class Toggle extends React.Component {
     constructor(props) {
       super(props);
       this.state = {isToggleOn: true};
       // 为了在回调中使用 `this`,这个绑定是必不可少的
       this.handleClick = this.handleClick.bind(this);
     }
    
     handleClick() {
       this.setState(state => ({
         isToggleOn: !state.isToggleOn
       }));
     }
    
     render() {
       return (
         <button onClick={this.handleClick}>
           {this.state.isToggleOn ? 'ON' : 'OFF'}
         </button>
       );
     }
    }
    

    这是因为babel已经内置 @babel/plugin-proposal-class-properties 来帮助我们自动绑定this, 也就是说我们无需编写 this.handleClick = this.handleClick.bind(this) 这行代码了。此插件的作用就是让我们的项目支持 public class fields语法。

    public class fields

    在TC39的官方仓库中我们可以看到在3年前就建立关于 public class fields 的提案了。

    探寻public class fields

    截止到目前为止该提案处于 stage-3阶段, 它表明提案的代码都已经实现, 但是需要等待实验验证、用户反馈以及验收测试通过。

    可能有的同学不清楚ECMA标准提案的几个阶段, ECMA标准提案可以分为5个阶段:

    • stage-0:还是一个设想,只能由TC39成员或TC39贡献者提出。
    • stage-1::提案阶段,比较正式的提议,只能由TC39成员发起,这个提案要解决的问题必须有正式的书面描述。
    • stage-2:草案,有了初始规范,必须对功能语法和语义进行正式描述,包括一些实验性的实现。
    • stage-3:候选,该提议基本已经实现,需要等待实验验证,用户反馈及验收测试通过。
    • stage-4:已完成,必须通过 Test262 验收测试,下一步就纳入ECMA标准。

    同时我们也可以通过在 此仓库 查看目前在各个阶段的提案情况。

    探寻public class fields

    虽然 public class fields 还没有被纳入ECMA标准, 但是浏览器对它的兼容性已经做得很棒了。

    探寻public class fields

    我们可以看到除了IE浏览器和三星浏览器表示明确不支持它以外, 其余的浏览器都支持了。细心的同学可能发现了它似乎在苹果浏览器中不支持 public static fields 语法。时至今日, 我们发现这个在webkit内核中的bug已经不存在了, 在 2020-11-17 01:01:06 PST 的时候, Xan Lopez 已经完成对其的修复工作。

    探寻public class fields

    聊完浏览器的兼容性之后, 我们来看一下 public class fields 的实现过程。

    请看以下代码转换:

    转化前:

     class Bork {
       static a = 'foo';
       static b;
    
       x = 'bar';
       y;
     }
    

    转换后:

    var Bork = function Bork() {
     babelHelpers.classCallCheck(this, Bork);
     Object.defineProperty(this, "x", {
       configurable: true,
       enumerable: true,
       writable: true,
       value: 'bar'
     });
     Object.defineProperty(this, "y", {
       configurable: true,
       enumerable: true,
       writable: true,
       value: void 0
     });
    };
    
    Object.defineProperty(Bork, "a", {
     configurable: true,
     enumerable: true,
     writable: true,
     value: 'foo'
    });
    Object.defineProperty(Bork, "b", {
     configurable: true,
     enumerable: true,
     writable: true,
     value: void 0
    });
    

    对于public的属性 我们使用了 Object.defineProperty 将它自己挂载在this上, 而对于静态的属性,则通过挂载在当前方法的属性上。

    当然上述的原始代码也可以转化成赋值型(上面那种我们称之为定义型)。

    var Bork = function Bork() {
      babelHelpers.classCallCheck(this, Bork);
      this.x = 'bar';
      this.y = void 0;
    };
    
    Bork.a = 'foo';
    Bork.b = void 0;
    

    可能有的同学会有疑问了, 浏览器到底是使用定义型还是赋值型的呀? 可能上面的例子不够简单, 我们来看简单的:

    var obj = {
        foo: 123
    };
    

    上面的代码按照我们之前的讨论, 可能会被转成以下两种代码:

    赋值型

    var obj = new Object();
    obj.foo = 123;
    

    定义型

    var obj = new Object();
    Object.defineProperties(obj, {
        foo: {
            value: 123,
            enumerable: true,
            configurable: true,
            writable: true
        }
    });
    

    事实上, 浏览器引擎会执行第二种操作, 因为定义型的操作能够更好地表达出对象字面量的语义。那么赋值型操作和定义型操作除了语义化上面有差异外, 还有什么不一样的地方呢?

    定义型和赋值型的主要差别

    • 赋值可能会调用原型上的setter,定义会创建一个自身属性

      给定一个空对象obj, 它的原型proto有一个foo的访问器属性。

      var proto = {
          get foo() {
              console.log("Getter");
              return "a";
          },
          set foo(x) {
              console.log("Setter: "+x);
          },
      };
      var obj = Object.create(proto);
      

      如果我们使用了定义型操作的话, 则会在obj上添加一个自身的属性foo

      探寻public class fields

      但是如果是赋值型操作的话, 则意味着我们想要改变某个已经存在的值。所以赋值操作会转交给原型proto的foo属性的setter访问器来处理。

      探寻public class fields

    • 原型链中的同名只读属性可能会阻止赋值操作,但不会阻止定义操作

      如果原型链中存在一个同名的只读属性,则无法通过赋值的方式在原对象上添加这个自身属性,必须使用定义操作才可以.这项限制是在ECMAScript 5.1中引入的:

      "use strict";
      var proto = Object.defineProperties(
          {},
          {
              foo: {  // foo属性的特性:
                  value: "a",
                  writable: false,  // 只读
                  configurable: true  // 可配置
              }
          });
      var obj = Object.create(proto);
      

      赋值操作会导致异常:

    探寻public class fields

    这貌似是个很奇怪的表现,原型上的属性居然可以影响到能否创建一个同名的自身属性。但是这样的表现是有道理的,因为另外一种形式的只读属性(只有getter的访问器属性)也是这样的表现,这样才能统一。

    通过定义的方式, 我们可以成功创建一个新的自身属性:

    探寻public class fields

    至于其他的差别大家可以查看这篇文章

    总结

    通过对 public class fields 的探寻, 我们可以总结出以下两点:

    1. 如果我们想创建一个新的属性, 那么就用定义型操作
    2. 如果我们想改变一个属性的值, 就用赋值型操作

    参考文献

      1. 2ality.com/2012/08/pro…
      1. github.com/tc39/propos…
      1. reactjs.org/docs/handli…
      1. github.com/tc39/propos…
      1. babeljs.io/docs/en/bab…

    起源地下载网 » 探寻public class fields

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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