• [Effective JavaScript 笔记]第36条:只将实例状态存储在实例对象中


    理解原型对象与其实例之间是一对多的关系,对于实现正确的对象行为很重要。
    常见的错误是不小心将每个实例的数据存储到了其原型中。

    示例

    一个实现了树型数据结构的类可能将子节点存储在数组中。

    实例状态在原型中(错误)

    将存储子节点的数组放置在原型对象中将会导致实现被完全破坏。

    function Tree(x){
      this.value=x;
    }
    Tree.prototype={
      children:[],
      addChild:function(x){
         this.children.push(x);
      }
    }
    

    如果我们使用这个类构造一棵树,代码如下

    var left=new Tree(2);
    left.addChild(1);
    left.addChild(3);
    
    var right=new Tree(6);
    right.addChild(5);
    right.addChild(7);
    
    var main=new Tree(4);
    main.addChild(left);
    main.addChild(right);
    
    main.children;//[1,3,5,7,left,right]

    我们预想的main.children应该是只包括left,right两个Tree的实例的,为什么包括这些了呢?
    看一下下面这张图就明白了
    1466039875998
    这里面原有的实例都要可以访问和操作原型中children,然后都是对这个数组进行了添加,导致对应实例的children数据出现错误。

    实例状态在实例对象中(正确)

    实现Tree类的正确方式是为每个实例创建一个单独的children数组。

    function Tree(x){
      this.value=x;
      this.children=[];
    }
    Tree.prototype={
      addChild:function(){
        this.children.push(x);
      }
    }
    

    同样的我们看一张上面代码的图示
    1466039901118

    分析

    共享有状态的数据可能会导致错误。通常在一个类的多个实例之间共享方法是安全的,因为方法通常是无状态的,这不同于通过this来引用实例状态。(因为方法调用的语法确保了this被绑定到实例对象,即使该方法是从原型中继承来的,共享方法仍然可以访问实例状态)一般情况下,任何不可变的数据可以被存储在原型中从而被安全地共享。有状态的数据原则上也可以存储在原型中,只要你真正想共享它。在原型中最常见的数据是方法,而每个实例的状态都存储在实例对象中。

    提示

    • 共享可变数据可能会出现问题,因为原型是被其所有的实例共享的

    • 将可变的实例状态存储在实例对象中

  • 相关阅读:
    ASP.NET和PHP全面对比
    GridView事件DataBinding,DataBound,RowCreated,RowDataBound区别及执行顺序分析
    OA、CRM、ERP之间的区别和联系是什么?
    C#继承
    对软件项目管理的几点认识
    冒泡
    经典排序算法
    asp.net遍历页面中所有TextBox,并赋值为String.Empty的方法
    String.Format用法
    frame和iframe
  • 原文地址:https://www.cnblogs.com/wengxuesong/p/5589845.html
Copyright © 2020-2023  润新知