【问题标题】:What's the difference between 2 JavaScript objects?2个JavaScript对象有什么区别?
【发布时间】:2011-07-20 07:13:33
【问题描述】:

我尝试提高我的 JavaScript 技能。 我不明白为什么(5)有效并且(2)返回错误。不一样吗?

  1. B.fn() //OK
  2. B.fn2() //TypeError: Object # has no method 'fn2'
  3. var a = new A()
  4. a.fn() //OK
  5. a.fn2() //OK

    var A = function () {
        this.fn = function () { alert(3); }
    }
    A.prototype = {
        fn2: function () { alert(4); }
    };
    
    var B =
        {
            fn: function () { alert(1); }
        }
    B.prototype = {
        fn2: function () { alert(2); }
    };
    

【问题讨论】:

    标签: javascript javascript-framework


    【解决方案1】:

    aA 类的一个实例,其中B 是类本身。由于fn2 没有被定义为静态函数,它只能用于B 类的实例,而不是B 本身。

    如果你想直接使用B,你可以使用:

    new B().fn2()

    如果您将B 定义为function()

    或者,您可以像定义 fn 一样定义 fn2

    【讨论】:

    • 实际上new B().fn2() 不起作用,因为在任何地方都没有定义B() 函数。
    【解决方案2】:

    您所展示的内容是由我认为 JavaScript 中 OO 的最大问题引起的:原型必须是构造函数的属性,而不是对象本身。这意味着如果您有一个可以轻松定义为对象字面量的单个对象,那么您仍然需要一个无用的构造函数来定义对象的原型。

    阅读这篇文章:Prototypal Inheritance in JavaScript 由 Douglas Crockford 撰写。以下是相关部分:

    [...] JavaScript 本身有冲突 关于它的原型性质。在一个 原型系统,对象继承 从物体。然而,JavaScript 缺少执行该操作的运算符 手术。相反,它有一个new 运算符,使得new f() 产生 继承自的新对象 f.prototype 这个间接是 旨在使语言看起来 对受过经典训练的人更熟悉 程序员,但没有做到这一点,因为 我们可以从非常低的意见中看出 Java 程序员有 JavaScript。 JavaScript 的构造函数模式做到了 不吸引古典人群。它 也掩盖了 JavaScript 的真实 原型性质。结果,有 很少有程序员知道如何 有效地使用语言。 幸运的是,很容易创建一个 实现 true 的运算符 原型继承。它是一个 我的工具包中的标准功能,我 强烈推荐给你。

    阅读这篇文章,了解一些关于如何有效解决您正在尝试做的事情的想法。

    【讨论】:

      【解决方案3】:

      (简单的解释) prototype 属性仅在使用 function 作为构造函数时适用(通过使用 new 运算符)。 function 创建它的 prototype 的克隆,并且函数内的 this 关键字设置为克隆。克隆上的属性是对prototypes 属性的直接引用/指针。

      对象字面量{}new Object() 的更强大的替代表达式,因此“继承”Object.prototype 的属性。

      所以:

      function ClassLike() {}
      ClassLike.prototype = {
          foo : "bar"
      }
      
      var instance = new ClassLike();
      alert( instance.foo ); // bar
      

      之所以有效,是因为 new 运算符会启动一些操作以创建一个新对象,而:

      var instance = {
          foo : "bar"
      }
      instance.prototype = {
          baz : "foobar"
      }
      

      仅向已创建的对象添加另一个属性(原型),并没有启动任何过程来实际分配/更改对象的原始原型。

      现在 Mozilla 已经添加了一种非标准(IE 不支持)方式来通过__proto__ 更改已经实例化的对象原型,并且有一些请求将其添加到 ES5(EcmaScript 5)。我不会在自动取款机上使用它。但它的工作原理是这样的:

      var instance = {};
      var parent = {
          foo : "bar"
      }
      instance.__proto__ = parent;
      
      alert( instance.foo ); // bar
      

      另一种更改已实例化对象原型的方法是添加到Object 构造函数原型(由于许多原因不建议这样做)。因此:

      var instance = {}; // a more powerful alternative to `new Object()`
      
      Object.prototype.foo = "bar";
      
      alert( instance.foo ); // bar
      

      这一切皆有可能,尽管这样做是否明智……我会说不,但意见各不相同,我宁愿避免争论;)

      无论如何,只要记住prototype 属性在newfunction 上起作用,否则它只会成为实例上的属性。

      【讨论】:

      • 感谢您的回答。我有相对的问题。我需要特权功能来访问私人成员,对吧?如果是,那为什么当我调用“new C().fn()”时,“this”没有看到“m”成员?var C = function(){var m; this.fn=function(){返回 this.m;}}
      • var m 创建一个局部变量,而不是一个属性。 this.m 尝试引用公共属性。 this 关键字的工作方式与其他语言不同,它只是一个“注入”变量,指向函数的拥有对象。这会起作用:var C = function(){var m=1; this.fn=function(){return m;}}
      • __proto__ 不会被添加到 ES5 中:ES5 已经是最终不变的标准。然而,Object.getPrototypeOf(o) 给出了o 的原型。同样,说“现在 Mozilla 已添加”也不正确;它已经存在了很长时间,并且在 Carakan (Opera)、JSC (Safari) 和 V8 (Chrome) 中也存在。
      【解决方案4】:

      嗯,你的答案很简单。在 JavaScript 中,只有构造函数具有“原型”,即原型属性。对象文字,例如“{}”没有。因此,除非您按以下方式更改,否则您的 2 号将永远无法工作:

      var B = function(){ // the B constructor
                return this;
              }
      B.prototype = {
      fn2: function(){ alert(2); }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-09-28
        • 2011-09-23
        • 1970-01-01
        • 1970-01-01
        • 2017-05-12
        • 2014-01-26
        • 2011-04-27
        相关资源
        最近更新 更多