为什么javascript函数每次调用都有实例?

时间:2016-07-14 02:57:22

标签: javascript function object instance

javascript介绍说: 当我有如下代码时:

var Person=function(name){ 
     this.name=name; 
     this.sayHello=function(){return 'Hello '+name;} 
} 

每当我实例化一个" Person"时,都会有一个" sayHello"的副本。功能在内存中。为了减少这种内存消耗,我可以改变代码如下:

var Person=(function(){ 
     var sayHello=function(){return 'Hello '+name} 
     return function(name){ 
         this.name=name 
         this.sayHello=sayHello 
     } 
})() 

通过这种方式,不会有sayHello()的多个副本

我的问题是:

  1. 对于第一类代码,除了浪费更多内存之外还有什么好处?
  2. 我们应该以第二种方式编写代码,还是javascript应该为每个实例避免一个函数的一个副本?
  3. 非常感谢。

3 个答案:

答案 0 :(得分:1)

您目睹的行为是两件事的结果:

  1. 作为第一类对象的功能。这意味着函数的处理方式与字符串,数字,数组等相同。

  2. 如何在函数中处理局部变量。每次调用函数时都会创建局部变量(通常在堆栈上)。这允许以递归方式调用函数。

  3. 这种行为存在于许多不同的语言中,这些语言具有Go,Perl,Lisp等匿名函数。

    上述两条规则意味着每次调用函数时都会创建内部函数并将其赋值给变量。

    这有什么好处?

    从语言的角度来看,这一点的主要优点是行为的一致性。这意味着函数实际上被视为一等对象,就像数字,字符串等一样。一直对待它意味着尝试使用匿名函数的人不会对行为感到惊讶。

    人们如何使用此功能?

    有时您会发现自己编写了几个看起来相似的函数:

    function double (x) {return x * 2};
    function quadruple (x) {return x * 4};
    

    能够对类似的函数“系列”进行分类并以某种方式将它们写入一次不是很好吗?

    嗯,在像C这样的语言中,您可以使用宏系统基本上剪切并粘贴您键入的文本,以生成多个不同的代码。

    在具有第一类函数的语言中,您可以编写一个函数来生成函数:

    function makeMultiplier (factor) {
        return function (x) { return x * factor }
    }
    

    现在你可以这样做:

    var double = makeMultiplier(2);
    var quadruple = makeMultiplier(4);
    

    现在显然为此工作makeMultiplier()函数必须返回两个不同的函数。它不能只修改单个函数,以便在每次调用时执行不同的操作。否则double()quadruple()函数在第二次调用makeMultiplier()后将乘以4。

    实施细节

    可以创建一个系统,通过该系统只能编译一次内部函数体,并通过闭包捕获差异。因此,所有函数只占用RAM一次,但函数的不同版本可能占用多个闭包。这可能是大多数js引擎实现的方式,但我真的不知道。如果是这样,则内部函数执行每次定义时都会占用额外的RAM,但不会占用太多(通常由一个堆栈帧 - 因此每个函数定义占用与函数调用相同的空间)。

    从程序员的角度来看,内部函数似乎必须像每个调用创建它们一样工作,因为这就是你期望它们工作的方式。

答案 1 :(得分:0)

  

对于第一类代码,除了浪费更多内存之外有什么好处?

我唯一一次使用这样的东西就是快速测试一个匿名对象。这方面的一个例子是某种 factory 实现:

getWidget = function(){
    return {
        foo: 'bar',
        test: function(){ ... }
    }
}

老实说,在我确认初步测试后,这很快就会被正确的编码约定所取代。

  

我们应该以第二种方式编写代码,还是javascript应该为每个实例避免一个函数的一个副本?

我会说不。不要写这样的代码。这是不必要的复杂,似乎不能从我所知道的方面发挥作用。我建议只在函数原型上创建方法:

var Person = function(name){
    this.name = name;
}

Person.prototype.sayHello = function(){
    return 'Hello ' + this.name;
}

<强>优点 - 易于阅读 - 易于管理 - this在调用方法的上下文中正确定位

<强>缺点 - 代码增加的名义上的增加 - 根据对问题的评论,您将无法访问专门用于构造函数的变量

答案 2 :(得分:0)

  

对于第一类代码,除了浪费更多内存之外,还有什么好处?

这可用于访问控制(如某些其他语言中的private)。

考虑:

var Person=function(name){ 
   this.sayHello = function(){return 'Hello '+name;}
};

name只能由sayHello访问,this.sayHello是一个不透明的函数。

其他代码可能会替换sayHello,但无法让此name实例使用其他class Item { protected: template <typename T> Field<T>& getField(const String& fieldName); template <typename T> const Field<T>& getField(const String& fieldName) const; }; template <typename T> class Field { public: using data_t = T; const String& getName() const; data_t getValue() const; void setValue(data_t&); }; class File : public Item{ public: // There are also setters String getFileName() const { return getField<String>("file_name").getValue(); } Integer getFileSize() const { return getField<Integer>("file_size").getValue(); } } class Folder : public Item{ public: String getFolderName() const { return getField<String>("folder_name").getValue(); } }