代码之家  ›  专栏  ›  技术社区  ›  Max Millington

在JavaScript[duplicate]中声明函数内的原型与函数外的原型

  •  0
  • Max Millington  · 技术社区  · 6 年前

    在风格上,我更喜欢这种结构:

    var Filter = function( category, value ){
      this.category = category;
      this.value = value;
    
      // product is a JSON object
      Filter.prototype.checkProduct = function( product ){
        // run some checks
        return is_match;
      }
    
    };
    

    var Filter = function( category, value ){
      this.category = category;
      this.value = value;
    };// var Filter = function(){...}
    
    Filter.prototype.checkProduct = function( product ){
      // run some checks
      return is_match;
    }
    

    我以前成功地使用过第一种结构,但我要确保我自己不会因为糟糕的编码实践而陷入调试难题,或者引起其他开发人员的悲伤和恼怒。

    0 回复  |  直到 10 年前
        1
  •  11
  •   jfriend00    10 年前

    在功能上,这样构造代码有什么缺点吗? 将原型方法添加到 表达式语句关闭)是否导致意外的作用域问题?

    是的,存在缺点和意外的范围界定问题。

    1. 将原型一次又一次地分配给一个本地定义的函数,每次都会重复该分配并创建一个新的函数对象。前面的赋值将被垃圾收集,因为它们不再被引用,但是与第二个代码块相比,在构造函数的运行时执行和垃圾收集方面都是不必要的工作。

    2. 在某些情况下会出现意外的范围界定问题。看到了吗 Counter 在我的答案的最后的例子为一个明确的例子。如果从prototype方法中引用构造函数的局部变量,那么第一个示例将在代码中创建一个潜在的讨厌的bug。

    还有其他一些(更细微的)区别。您的第一个方案禁止在构造函数之外使用原型,如:

    Filter.prototype.checkProduct.apply(someFilterLikeObject, ...)
    

    当然,如果有人用过:

    Object.create(Filter.prototype) 
    

    Filter 构造函数,这也会创建一个不同的结果,这可能不太可能,因为使用 过滤器 原型应该运行 过滤器


    var Filter = function( category, value ){
      this.category = category;
      this.value = value;
    
      // product is a JSON object
      this.checkProduct = function( product ){
        // run some checks
        return is_match;
      }
    
    };
    

    有一些Javascript“专家”声称不再需要使用原型节省的内存(我几天前看了一个关于这个的视频讲座),所以是时候开始直接在对象上而不是原型上使用性能更好的方法了。我不知道我自己是否已经准备好提倡这一点,但这是一个值得思考的有趣的观点。


    var Counter = function(initialValue){
      var value = initialValue;
    
      // product is a JSON object
      Counter.prototype.get = function() {
          return value++;
      }
    
    };
    
    var c1 = new Counter(0);
    var c2 = new Counter(10);
    console.log(c1.get());    // outputs 10, should output 0
    

    http://jsfiddle.net/jfriend00/c7natr3d/

    这是因为 get 方法形成一个闭包,并且可以访问作为构造函数的局部变量的实例变量,但在实践中它不是这样工作的。因为所有实例共享相同的原型对象,所以 计数器 得到 方法,该方法访问上次创建的实例的构造函数的局部变量。这是一场编程灾难,因为这可能永远不会是我们的初衷,很容易让人摸不着头脑,弄不清哪里出了问题,为什么出了问题。

        2
  •  3
  •   Bergi    10 年前

    风格上,我更喜欢这种结构

    encapsulation 这个符号提供了-所有属于类的东西都被 {} 阻止。(当然,谬论是 范围 运行 构造函数)。

    module patterns JavaScript提供的。您可以得到更显式的结构、独立的构造函数声明、类范围的私有变量,以及正确封装在块中的所有内容:

    var Filter = (function() {
    
        function Filter(category, value) { // the constructor
            this.category = category;
            this.value = value;
        }
    
        // product is a JSON object
        Filter.prototype.checkProduct = function(product) {
            // run some checks
            return is_match;
        };
    
        return Filter;
    }());
    
        3
  •  2
  •   Aviv Shaked    10 年前

    如果希望封装类,可以在声明checkProduct方法之前检查该方法是否存在:

    if(!Filter.prototype.checkProduct) {
      Filter.prototype.checkProduct = function( product ){
        // run some checks
        return is_match;
      }
    }
    

    还有一件事你应该考虑。匿名函数的闭包现在可以访问构造函数中的所有变量,因此访问它们可能很有诱惑力,但这会让您陷入一个兔子洞,因为该函数将只对单个实例的闭包具有隐私权。在你的例子中,它将是最后一个实例,在我的例子中,它将是第一个实例。

        4
  •  1
  •   lujcon    10 年前

    代码的最大缺点是关闭重写方法的可能性。

    如果我写:

    Filter.prototype.checkProduct = function( product ){
        // run some checks
        return different_result;
    }
    
    var a = new Filter(p1,p2);
    
    a.checkProduct(product);
    

    结果将不同于预期,因为原始函数将被调用,而不是我的。

        5
  •  0
  •   Kuba Wyrostek    10 年前

    Filter 原型直到 原型?使用任一节点

    function ExtendedFilter() {};
    util.inherit(ExtendedFilter, Filter);
    

    Object.create

    function ExtendedFilter() {};
    ExtendedFilter.prototype = Object.create(Filter.prototype);
    

    如果忘记或不知道调用,则在原型链中总是以空原型结束 第一。

        6
  •  0
  •   Alexander Mills    8 年前

    仅供参考,这样做也不安全:

     function Constr(){
    
        const privateVar = 'this var is private';
    
        this.__proto__.getPrivateVar = function(){
           return privateVar;
        };
    
     }
    

    Constr.prototype === this.__proto__ 所以你也会有同样的不良行为。