【问题标题】:Declaring a member function in JS在 JS 中声明一个成员函数
【发布时间】:2012-11-21 22:10:00
【问题描述】:

我尝试了两种在 JS 中声明成员函数的方法:

function init() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
}
a = new init();
a.displayName()

function init() {
    var name = "Mozilla";
    displayName = function() {
        alert(name);
    }
}
a = new init();
a.displayName()

第一种方法告诉我displayName()undefined。我看到它的方式是创建一个名为displayNameFunction 类型的变量,因此它应该可以工作。 有人愿意解释为什么它不起作用吗?

【问题讨论】:

    标签: javascript function member


    【解决方案1】:

    它不起作用,因为这就是 JavaScript 现在的工作方式。只是在构造函数中声明一个函数并不会在构造函数创建的对象上设置它,您必须显式地在对象和函数之间建立链接(直接通过将其分配给对象,或者更常见的是间接通过原型)。

    执行此操作的典型方式是通过原型继承,尽管您也可以直接将函数分配给单个对象(更多内容如下 - 但您谈到了“成员函数”,而在 JavaScript 中执行此类操作的典型方式是通过原型)。

    有几种方法可以设置原型继承。即使在旧版浏览器中也与广泛的 JavaScript 引擎兼容的经典方法是通过构造函数上的 prototype 属性,它引用一个对象。该对象成为通过new FunctionName 创建的实例的原型。您向该对象添加属性,以便在该函数创建的实例之间共享它们。

    所以,使用原型继承:

    function Init(name) {
        this.name = name;
    }
    Init.prototype.displayName = function() {
        alert(this.name);
    };
    
    var i = new Init("Mozilla");
    i.displayName();
    

    以上注意事项:

    1. 在 JavaScript 中,压倒性的约定是构造函数以大写字母开头。所以我称它为Init 而不是init

    2. 所有函数都自动有一个prototype属性,这是一个空白对象。

    3. 我向该对象添加了一个名为displayName 的属性,它引用了一个函数。

    4. 我没有对名称进行硬编码,而是将其作为参数传递给Init

    5. 请注意,我将名称存储在新构造实例的属性中;在对Init 的调用中,该实例以this 的形式提供。

    6. 同样,因为 displayName 是作为从对象检索函数引用的表达式的一部分调用的,所以 this 是对 displayName 的调用中的对象,因此 this.name 具有名称。

    7. 为了简单起见,我为displayName 分配了一个匿名函数。 (属性有名称,函数没有。)我倾向于在实际代码中不这样做。

    8. 通过new Init 构造的所有实例将通过原型共享displayName 函数的同一副本。

    更多探索(在我的博客上):

    如果您对在 JavaScript(和层次结构)中构建对象类感兴趣,您可能还对我的 Lineage toolkit 感兴趣。

    从 ES5 开始,还有另一个选项:Object.create。这允许您直接创建对象并为其分配原型,而无需使用构造函数。但是因为你使用了new,这意味着你正在使用构造函数,我不会详细说明。

    现在,如果您不想使用 JavaScript 的原型功能,则没有。例如,您可以这样做:

    function Init(name) {
        var name = name;
    
        this.displayName = function() {
            alert(name);
        };
    }
    var i = new Init("Mozilla");
    i.displayName();
    

    它没有使用 JavaScript 的原型特性,而是在每次调用 Init 时创建一个新的 displayName 函数并将其直接分配给对象。 (任何质量合理的 JavaScript 引擎都足够聪明,可以重用函数的代码,但每个实例都会有不同的函数对象)。以上也使name 属性完全私有,因为我们在每次调用时创建的函数是局部变量name 上的闭包。 (更多:Closures are not complicated

    【讨论】:

    • 在不使用原型的情况下分配属性值是完全合理的。
    • @Rob:是的。但是 OP 谈论“成员函数”,上面是你这样做的典型方式。我必须对反对者(无论是你还是其他人)说,我认为将上述答案称为“无用”(正如反对者按钮所说的那样)是非常苛刻的。
    • 您的帖子具有误导性。 “它不起作用,因为这就是 JavaScript 现在的工作方式。”实际上,您几乎可以做 OP 试图做的事情,这就是您创建私有变量的方式。有使用原型继承的情况,但也有使用私有变量的情况。
    • @Rob:OP 期望在构造函数中声明一个函数会以某种方式使其成为成员函数。 JavaScript 不是这样工作的,所以我是这么说的。一点也不误导。我在答案中添加了一个非原型部分,以防他们不想使用原型,尽管我同时注意到答案已被接受——使用原型。
    • 谢谢。我没有对你投反对票,因为你在其中添加了它。我会说,对于来自 C# 或 Java 的人来说,关于 JavaScript 最不清楚的事情之一是“this”不是隐式存在的。这就是为什么我说 OP 试图创建一个成员。这是 经常遇到的一个错误,我已经写 JS 多年了。很容易被忽视。
    【解决方案2】:

    以下应该有效:

    function Init() {
        var name = "Mozilla";
        this.displayName = function() {
            alert(name);
        }
    }
    a = new Init();
    a.displayName()
    

    【讨论】:

    • 它为每个实例一次又一次地创建方法。
    • 是的。 JS 中的每种面向对象模式都有自己的优点和缺点。上述方法更具可读性,并且可以在创建一个/几个对象实例时使用。 @ThiefMaster 给出的 MDN 文章是一个很好的起点
    【解决方案3】:

    您可以使用的标准之一是

    var init = (function() {
    
        var name = "Mozilla"; // Shared by all instances
    
        function init() {
            this.name = "IE"; // Spesific to the created instance                  
        }    
    
        init.prototype = {
            displayName: function() {
                alert(name);
                alert(this.name);
            }        
        }
    
        return init;
    
    })();
    
    var a = new init();
    a.displayName();​
    

    【讨论】:

      【解决方案4】:

      在您的第一种方法中:

      函数初始化(){ var name = "Mozilla"; 功能显示名称(){ 警报(名称); } } a = 新的初始化(); a.displayName()

      函数 displayName(){} 只能在 init() 中调用,类似私有函数,不能作为对象的公共函数(init())

      【讨论】:

        【解决方案5】:

        要创建类似成员函数的东西,您需要将其添加到构造函数的原型中:

        function init() {
            this.name = 'Mozilla';
        }
        init.prototype.displayName = function() {
            alert(this.name);
        }
        

        我还强烈建议您阅读有关 JavaScript 中的对象系统如何工作的内容。 MDN 上有一篇不错的文章:https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript

        【讨论】:

          猜你喜欢
          • 2011-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多