【问题标题】:Javascript Objects & PrototypesJavascript 对象和原型
【发布时间】:2016-06-23 18:24:08
【问题描述】:

我是 Javascript 新手,对以下语句的结果感到困惑。你能帮助澄清每个结果背后的原因吗?如果您还可以建议资源以清楚地解释这些情况下的预期行为,我们将不胜感激。

function Person(){
   this.a = function(){alert("a")};
}

Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};

var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error

Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)

Person.c(); //works

Person();
Person.a(); /* error (Person() call should have set this.a 
               on the Person object just like the c method, 
               why doesn’t it work?) */

Person.b();//error (why?)

【问题讨论】:

  • 只有函数有prototype对象,test是一个对象。 a 没有在Person.prototype 中定义,但b 是。
  • @JaredSmith 你错了,你链接的问题不涉及静态属性与实例属性。请删除您的评论
  • @frankies 他的评论确实说“可能”。更具建设性的方法可能是将差异编辑到问题本身中,以便它们明显不同。
  • @frankies 我有点同意你的观点(到我发布答案的地步),鉴于低质量的答案很吸引人,这需要 mod 的关注。

标签: javascript object prototype


【解决方案1】:

好的,我会试一试。我也马上去面试,所以这是个好习惯:)

function Person(){
   this.a = function(){alert("a")};
}

Person.prototype.b = function(){alert("b")};
Person.c=function(){alert("c")};

var test = new Person();
test.a(); // works
test.b(); // works
test.prototype.b(); //error

听起来你明白了,但test 是一个对象,而不是构造函数。它上面没有原型密钥。

Person.prototype.a(); // error (why?)
Person.prototype.b(); //works (why?)

这就是有趣的地方。看Person()函数;它确实引用了传递给它的参数并返回一个新对象。似乎没有比这更复杂的了。然而,这正是 JavaScript 疯狂的原型继承发挥作用的地方。

假设您在String 上编写了更高级别的原型方法,例如String.prototype.capitalize = function()...,并且该方法将字符串大写。您创建的每个新字符串都会有 capitalize() 方法,但它不像字符串是带有该方法键的对象。

这里Person.prototype.a()Person.prototype.b() 正在做的事情是一样的。通过Person() 函数运行一个对象会使用这些键创建一个对象。由于 Person() 构造函数只返回一个键为 a 的对象,这就是 test 到目前为止的样子:

console.log(test); // {a: [Function]}

但为什么test.b() 有效?这是因为构造函数创建的任何对象都会继承该构造函数的所有属性.prototype。向原型添加一些东西不会改变添加到构造对象的键,而是让其构造对象可以访问它。调用某事物的方法首先查看它的键,然后是构造函数的隐藏 [[prototype]] 值,然后是父对象,依此类推。您可以在 Chrome 中的 console.logs 中看到这一点。

Person();
Person.a(); /* error (Person() call should have set this.a 
               on the Person object just like the c method, 
               why doesn’t it work?) */

Person.b();//error (why?)

你的错误是说Person() 是一个对象。它不是;这是一个功能。构造函数中的this 引用指的是传递给它的对象;这意味着它被设置为的变量。由于我们只是调用 Person() 而没有将结果设置为任何值,this 是未定义的,Person() 的结果是未定义的,因为没有什么可以返回。函数不能有键或方法。

希望我能帮上忙。这对我来说也是个好习惯!

【讨论】:

  • 这可能是我写的以外最好的答案,但它在哪些方面比我的有所改进?
【解决方案2】:

对于这是否是重复的,或者是否不应该将其分解为几个不同的问题,我有两种看法。尽管如此,由于这会吸引质量可疑的答案,让我们逐行检查您的代码。

function Person(){
   this.a = function(){alert("a")};
}

定义函数 Person。还没有什么特别的。调用它Person() 将根据它是否在严格模式下运行,抛出错误'无法设置未定义的属性“a”',或者它将创建一个全局变量'a',其中 vaue 是一个警报的函数'一个'。

但是,按照惯例,Javascript 中的大写函数应该是构造函数,并使用 new 运算符调用。致电new Person() 可以为您带来一些魔力。它创建一个新对象并将其设置为构造函数中的this 值。新对象也被构造函数隐式返回,这就是它没有返回语句的原因。这意味着新人有一个方法 a 可以在调用时提醒“a”。

但这在实践中很少这样做,使用原型更为常见。 new 运算符还将新创建的对象的内部原型设置为构造函数的 .prototype 属性的值(该对象实际上并没有获得 .prototype 属性)。在构造函数 .prototype 对象上定义的任何内容都可用于通过使用 new 调用该构造函数创建的每个实例。

Person.prototype.b = function(){alert("b")};

这在 Person(构造函数)的 .prototype 对象上定义了一个函数 b。它将可用于通过调用new Person() 创建的所有 Person 实例。也可以直接调用Person.prototype.b()。这种方法比用于附加 'a' 方法的方法要好,因为所有的 Person 共享 'b' 的值,但都有自己的 'a' 副本。

Person.c=function(){alert("c")};

在 Javascript 中,一切都是一个对象,包括函数。对象可以具有分配给它们的属性。在这里,您将一个函数分配给 Person 函数本身的 c 属性。如果你习惯于基于类的语言,这类似于类的静态方法。

希望现在剩下的会变得更清楚。每个 Person 包括 'test' 都会有一个 'a' 方法,因为构造函数分配了它。但是 Person 的原型没有 'a' 方法,它只是在构造函数中赋值。 Person 的原型有一个“b”方法,这意味着所有 Person 实例都可以访问该共享的“b”方法。 Person 函数本身有一个 'c' 方法,但它不会传递给实例,因此 'test' 没有 'c' 方法。

【讨论】:

    【解决方案3】:

    class.prototype 就像是对象和你的类之间的链接。 class.prototype 您可以分配将在您的类的所有实例之间共享的函数和属性,以及何时调用函数将在classprototype 对象中查找

    //所以你可以在这里调用原型

    Person.prototype.fun;
    

    // 但是这里你直接调用func

    test.fun
    

    MDN

    【讨论】:

      【解决方案4】:

      当您执行Person.c = ... 时,您正在设置静态属性,因此它们不是原型的一部分。

      稍后,您尝试将原型方法调用到构造函数,但它们不存在,因为原型是该构造函数的实例的蓝图。

      【讨论】:

      • this.a 不创建静态属性。
      • 想解释一下那是什么?
      • 它为每个创建的实例添加一个属性。 Person.a() 会出错。我也不明白你的答案如何以任何方式改进我标记为欺骗的问题中的任何一个。
      • 现在我认为你是对的,a 不是函数的一部分。但你仍然没有回答我的问题。它以编程方式在构造函数上设置这个“类静态”属性。我们应该如何称呼这种属性?
      • this 在用new 调用的构造函数中指的是新创建的对象,它不会也不能指代函数本身,除非你做了像Person.call(Person) 这样的可怕事情。它是一个对象方法,每个 Person 实例都有自己的副本,并被调用(使用上面的代码)test.a()
      【解决方案5】:

      我会尝试向您解释,但英语不是我的主要语言。如果您有任何具体问题,请在 cmets 部分问我,我会详细说明。如需全面了解,请阅读more here

      test.a(); // works -> Yes because it accessing the property that exists in  Person it self
      test.b(); // works ->First It will look into test instance properties if it doesn't find it will look one level up into the Person prototype object and it will find it there.
      
      test.prototype.b(); //error because test is an instance and instances do not have a prototype property.
      
      Person.prototype.a(); // error (why?) Because you are going to look for a property a inside Person prototype which does not have it. Property lookup goes only forward not backward. 
      Person.prototype.b(); //works (why?) because b is a property of the Person prototype. 
      //typeof Person.prototype is object same as var prototype={} than prototype.b=function(){} so now you can call prototype.b();
      
      Person.c(); //works c is 'static' (more like object literal property assignment because every function in js still is an object) property of Person  same as var Person2={};Person2.c=function(){}; that is why you can access it without needing to initialize Person. 
      
      Person();
      Person.a(); /* error (Person() call should have set this.a 
                                 on the Person object just like the c method, 
                                 why doesn’t it work?) */ That property requires you to create an instance of Person.
      
      Person.b();//error (why?)  it is the same as a but b is a property of prototype of Person
      

      【讨论】:

      • 存在于 Person 函数中的属性”是错误的,或者至少是对 Person 实例属性的术语非常混乱
      • a 是 Person 对象/函数的属性。是的,每个 Person 实例也将具有该属性。为了减少混淆,我将删除该函数并替换它的实例。谢谢
      • cPerson 函数对象的属性。 atest 实例的属性
      • 是的,你是对的,但是假设你没有创建 Person 的实例。如果有人问你这个人有什么属性?你的答案是什么?
      • 取决于“Person”是指类还是构造函数对象。第一种情况是bastatic c,第二种情况是cprototypename
      猜你喜欢
      • 2020-04-24
      • 2012-10-10
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多