在对象类声明中设置javascript原型函数

Tau*_*ren 23 javascript oop prototype

通常,我已经看到在类定义之外声明的原型函数,如下所示:

function Container(param) {
    this.member = param;
}
Container.prototype.stamp = function (string) {
    return this.member + string;
}

var container1 = new Container('A');
alert(container1.member);
alert(container1.stamp('X'));
Run Code Online (Sandbox Code Playgroud)

此代码生成两个值为"A"和"AX"的警报.

我想定义类定义的原型函数INSIDE.做这样的事情有什么不对吗?

function Container(param) {
    this.member = param;
    if (!Container.prototype.stamp) {
        Container.prototype.stamp = function() {
            return this.member + string;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试这样,以便我可以访问类中的私有变量.但是我发现如果我的原型函数引用了私有var,那么private var的值总是初始化函数初始化时使用的值,而不是对象实例中的值:

Container = function(param) {
    this.member = param;
    var privateVar = param;
    if (!Container.prototype.stamp) {
        Container.prototype.stamp = function(string) {
            return privateVar + this.member + string;
        }
    }
}
var container1 = new Container('A');
var container2 = new Container('B');
alert(container1.stamp('X'));
alert(container2.stamp('X'));
Run Code Online (Sandbox Code Playgroud)

此代码生成两个值为"AAX"和"ABX"的警报.我希望输出为"AAX"和"BBX".我很好奇为什么这不起作用,如果有其他模式我可以使用.

编辑:请注意,我完全理解,对于这个简单的例子,最好只使用一个闭包,this.stamp = function() {}而不是使用原型.我就是这样做的.但我正在尝试使用原型来了解更多相关内容,并希望了解一些事情:

  • 何时使用原型函数而不是闭包是有意义的?我只需要使用它们来扩展现有的对象,比如Date.我读过闭包更快.
  • 如果我出于某种原因需要使用原型函数,那么在类中定义它是否"OK",就像在我的例子中一样,或者它应该在外面定义?
  • 我想了解为什么原型函数无法访问每个实例的privateVar值,只有第一个实例的值.

CMS*_*CMS 22

何时使用原型函数而不是闭包是有意义的?

嗯,这是最轻量级的方法,假设你在prototype某个构造函数中有一个方法,并且你创建了1000个对象实例,所有这些对象都将在你的原型链中拥有你的方法,而且所有这些对象都只引用一个功能对象.

如果在构造函数中初始化该方法,例如(this.method = function () {};),则所有1000个对象实例都将具有一个函数对象作为自己的属性.

如果我出于某种原因需要使用原型函数,那么在类中定义它是否"OK",就像在我的例子中一样,或者它应该在外面定义?

在其自身内部定义构造函数原型的成员并没有多大意义,我将向您解释更多关于它的原因以及为什么您的代码不起作用.

我想了解为什么原型函数无法访问每个实例的privateVar值,只有第一个实例的值.

我们来看看你的代码:

var Container = function(param) {
    this.member = param;
    var privateVar = param;
    if (!Container.prototype.stamp) {  // <-- executed on the first call only
        Container.prototype.stamp = function(string) {
            return privateVar + this.member + string;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

关于代码行为的关键点是该Container.prototype.stamp函数在第一个方法调用时创建的.

在创建函数对象时,它会将当前封闭范围存储在名为的内部属性中[[Scope]].

当您通过使用var函数或FunctionDeclaration 在其中声明的标识符(变量)调用函数时,稍后会扩充此作用域.

[[Scope]]属性列表构成了作用域链,当您访问标识符(如privateVar变量)时,将检查这些对象.

并且由于您的函数是在第一个方法调用(new Container('A'))上创建的,privateVar因此绑定到第一个函数调用的Scope,无论您如何调用该方法,它都将保持绑定.

看看这个答案,第一部分是关于with声明,但在第二部分我讨论范围链如何为函数工作.


Mat*_*att 12

很抱歉复活了一个旧问题,但我想在SO上添加我最近在其他地方发现的东西(寻找链接,一旦找到它就会编辑/添加它):找到它.

我个人喜欢以下方法,因为我可以直观地将我的原型和'实例'定义与函数定义一起分组,同时避免多次评估它们.它还提供了使用原型方法进行闭包的机会,这对于创建由不同原型方法共享的"私有"变量非常有用.

var MyObject = (function () {
    // Note that this variable can be closured with the 'instance' and prototype methods below
    var outerScope = function(){};

    // This function will ultimately be the "constructor" for your object
    function MyObject() {
        var privateVariable = 1; // both of these private vars are really closures specific to each instance
        var privateFunction = function(){};
        this.PublicProtectedFunction = function(){ };
    }

    // "Static" like properties/functions, not specific to each instance but not a prototype either
    MyObject.Count = 0;

    // Prototype declarations
    MyObject.prototype.someFunction = function () { };
    MyObject.prototype.someValue = 1;

    return MyObject;
})(); 

// note we do automatic evalution of this function, which means the 'instance' and prototype definitions 
// will only be evaluated/defined once.  Now, everytime we do the following, we get a new instance
// as defined by the 'function MyObject' definition inside

var test = new MyObject();
Run Code Online (Sandbox Code Playgroud)