zoukankan      html  css  js  c++  java
  • [Effective JavaScript 笔记]第40条:避免继承标准类

    ECMAScript标准库里配备了许多重要的类,如Array,function,以及Date等。扩展这些类生成子类可以方便完成很多工作,但它们的定义具有很多特殊的行为,所以很难写出行为正确的类。

    Array示例

    一个操作文件系统的库可能希望创建一个对象的目录,该目录继承了数组的所有行为。

    function Dir(path,entries){
      this.path=path;
      for(var i=0,n=entries.length;i < n;i++){
        this[i]=entries[i];
      }
    }
    Dir.prototype=Object.create(Array.prototype);
    

    运行下面这段代码,并没有得到预期的行为。

    var dir=new Dir('/tmp/mysite',['index.html','script.js','style.css']);
    dir.length;//0

    失败的原因

    length属性只对在内部被标记为“真正的”数组的特殊对象起作用。ECMAScript标准规定它是一个不可见的内部属性,称为[[Class]]。它的值只是一个简单的标签,并不是js真正有内部类系统。数组对象的[[Class]]值是"Array",函数对应的[[Class]]是"Function"。下面这个表是ECMAScript中定义的完整的[[Class]]属性值集合。

    image

    解密length

    那么神奇的[[Class]]属性对length做了什么呢?事实上,length的行为只被定义在内部属性[[Class]]的值为"Array"的特殊对象中。对于这些对象,js保持length属性与该对象的索引属性的数量同步。如果给该对象添加了更多的索引属性,length属性会自动增加。如果减少了length属性,也会自动删除任何索引大于该新值的索引属性。
    当我们扩展Array类时,子类的实例并不是通过new Array()或字面量[]语法创建的。所以Dir实例的[[Class]]属性值为"Object"。
    使用默认的Object.prototype.toString()方法可以通过查询其接收者的内部[[Class]]属性来创建对象的通用描述。可以传递任何给定的对象来显式地调用它。

    var dir=new Dir('/',[]);
    Object.prototype.toString.call(dir);//"[Object Object]"
    Object.prototype.toString.call([]);//"[Object Array]"

    结果Dir的实例未继承数组的length属性所期望的特殊行为。

    更好的实现

    定义一个entries数组的实例属性。

    function Dir(path,entries){
      this.path=path;
      this.entries=entries;
    }
    

    在原型中重新定义Array的方法,将这些相应的方法委托给entries属性来实现。

    Dir.prototype.forEach=function(f,thisArg){
      if(typeof thisArg==='undefined'){
        thisArg=this;
      }
      this.entries.forEach(f,thisArg);
    }
    

    ECMAScript标准库中的大多数构造函数都有类似的问题。某些属性或方法期望具有正确的[[Class]]属性或其他特殊的内部属性,然而子类却无法提供。基于这个原因,最好避免继承以下的标准类:Array,Boolean,Date,Function,RegExp,String。

    提示

    • 继承标准类往往会由于一些特殊的内部属性(如[[Class]])而被破坏

    • 使用属性委托优于继承标准类

  • 相关阅读:
    C# 中Async 和 Await 的用法,异步等待执行结果
    C# 事件发布和订阅
    C# 多线程使用信号量控制处理效率,统计活动中的线程
    C# 委托和泛型委托示例
    C# 数据库批量插入数据之 —— SqlBulkCopy、表值参数
    WinRar DOS命令大全带详细参数rar/zip/7z压缩文件解密
    Magic.Orm 基于C#的ORM框架,支持Sql Server/MySql/Oracle/Access/Sqlite等数据库,支持Lambda表达式快速上手0难度
    SqlServer使用SqlBulkCopy批量新增和更新数据,快速高效
    Flink内存模型
    Linux 查找替换
  • 原文地址:https://www.cnblogs.com/wengxuesong/p/5602793.html
Copyright © 2011-2022 走看看