Javascript:是否有人希望使用原型声明对象属性?

时间:2015-05-01 09:11:29

标签: javascript

我刚开始学习Javascript。

根据我的理解,到目前为止,您可以通过两种方式声明类/静态变量。第一种方式:

    Blog.prototype.signature = "By Blogger-Name";

第二种方式:

    Blog.signature = "By Blogger-Name";

通过使用第一种方法,变量签名可用于所有Blog实例。

但是,对于类的所有实例保持相同值的变量实际上不应该是实例变量。我认为,类/静态变量只能使用第二种方法声明。

因此,我的问题是,是否存在需要/被迫以第一种方式声明变量的情况?或者我对这一切的理解是否缺乏?请告诉我。

编辑:在哪种情况下,第一种方法是首选方法,同样,在哪种情况下,第二种方法是首选?

编辑2:所以我已经知道第一种方法实际上添加了一个默认值的实例属性。这也可以通过在构造函数本身中设置默认值来实现。那么何时以这种方式添加属性(即使用原型)是首选的?

4 个答案:

答案 0 :(得分:2)

  

因此,我的问题是,是否存在需要/被迫以第一种方式声明变量的情况?

唯一想到的是,如果您需要允许使用通过new Blog创建的对象的代码来访问属性而不知道构造函数的名称。 E.g:

function useABlogInstance(blog) {
    // Here, assume I don't know that `blog` was created via `new Blog`
    console.log(blog.signature);
}

虽然精明的用户可以

console.log(blog.constructor.signature);

访问Blog.signature(假设您保持constructor反向链接),这不会很干净。 : - )

重要的是要注意Blog.prototype 上的财产不是 a" class"或者"静态" property,它是一个实例属性(在Blog.prototype对象上)。虽然读取,但通过new Blog创建的对象的属性会在原型上找到它(如果实例没有自己的{{1} }属性),的结果非常非常不同。考虑:



signature

function A() {}
A.prototype.prop = "prototype prop";
var a1 = new A();
var a2 = new A();
snippet.log(a1.prop); // "prototype prop"
snippet.log(a2.prop); // "prototype prop"
a1.prop = "updated";
snippet.log(a1.prop); // "updated" -- because `a1` has its own `prop` property
                      // now and no longer uses the prototype's
snippet.log(a2.prop); // "prototype prop"




与之对比:



<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
&#13;
function B() {}
B.prop = "B prop";
var b1 = new B();
var b2 = new B();
snippet.log(b1.constructor.prop); // "B prop"
snippet.log(b2.constructor.prop); // "B prop"
snippet.log(B.prop);              // "B prop"
b1.constructor.prop = "updated";
snippet.log(b1.constructor.prop); // "updated"
snippet.log(b2.constructor.prop); // "updated"
snippet.log(B.prop);              // "updated"
&#13;
&#13;
&#13;

对于&#34; class&#34; -wide信息,我总是使用<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>,而不是Blog.signature。我将Blog.prototype.signature用于特定于实例的默认属性,其中值是基元或函数(但不是非函数对象或数组,我将它们设置为构造函数)。

附注:您未在任何代码段中声明变量。您正在向对象添加属性。在第一个代码段中,您将属性添加到将被指定为通过Blog.prototype.signature创建的对象原型的对象。在第二种情况下,您要向new Blog对象添加属性(函数是对象)。两者都不是变量,在这两种情况下它都是属性。

答案 1 :(得分:1)

Javascript中没有类变量。实际上,Javascript中没有。根据类和静态变量进行思考(你是Java开发人员吗?)不会让你知道发生了什么。即使“a class”的概念在某种程度上独立于编程语言,重要的是要理解它不是一个基本的编程结构 - 实际上有些语言没有类,比如Javascript

Javascript是一种非常简单的语言:它具有函数和字典,并且具有结合两者的语法并支持面向对象的编程方式。举个例子:

var johnSnow = { first: "John", last: "Snow" };

function fullName(character) {
  return character.first + " " + character.last;
}

console.log(fullName(johnSnow));

现在是OO版本:

var Character = function(first, last) {
  this.first = first;
  this.last = last;
}

Character.prototype.fullName = function() {
  return this.first + " " + this.last;
}

console.log(new Character("John", "Snow").fullName());

最后,我们可以回答您的问题:何时应该在构造函数上设置属性以及何时应该使用实例?

  • 设置实例的属性,不应与其他实例共享(显然)。您可以识别这些属性,因为它们通常在实例方法中使用,并使用this.$name

  • 进行读取
  • 在构造函数上设置属性...从不!在构造函数上设置的属性只是全局变量。所以只需使用全局变量,可能会命名它们(但显然你在某些时候需要一个全局变量!)

答案 2 :(得分:0)

我想这一切都取决于你想如何访问签名变量。 如果您希望从Blog实例轻松访问它,请使用prototype版本。然后你可以这样做:

var blog = new Blog;
console.log(blog.signature);

否则,您必须使用Blog.signatureblog.constructor.signature

当您将signature放入原型时,我不会担心instance variable Blog.prototype因为那不是您正在做的事情。

blog并未被复制 - 并非每个实例都拥有自己的私有副本。它是new Blog个对象(=使用__proto__创建的对象)将设置为Object.getPrototypeOf(blog)(= __proto__)的共享对象。 __proto__将用于搜索不是实例的直接属性的属性(包括函数)。

可以通过设置实际的实例变量来覆盖var Blog = function () {}; Blog.prototype.signature = "Original sig"; var blog = new Blog(); blog.signature === "Original sig" //^looked up in Blog.prototype === Object.getPrototypeOf(blog) === blog.__proto__ blog.signature = "New sig" //^set as an instance property blog.signature === "New sig" Blog.prototype.signature !== "New sig" //actual instance properties override prototype properties, but they don't over-write them var blog2 = new Blog() blog2.signature === "Original sig"

prototype

实际上,经典的面向对象编程语言(如C ++ / Java)的功能非常相似。 C ++ / Java中的对象具有属性和方法,并且方法的行为就像它们是实例的函数指针属性一样,但它们并非如此。方法不要向实例添加任何大小。他们都在一个共享的地方抬头 - 如果你愿意的话,你的班级原型。不同的是,在C ++ / Java中,链接在运行时不存在(它由编译器维护),并且仅用于方法。在JavaScript中,每个对象都有一个指向类共享查找位置的真实链接(对象的构造函数__proto__属性),该链接可通过objet&#39; s {{{{{ 1}}属性或更标准地通过Object.getPrototypeOf(someobject)获得的属性,它不仅适用于方法(如C ++ / Java),也适用于属性。

答案 3 :(得分:0)

foo1 = {}foo2 = new Bar之间的唯一区别在于foo1.__proto__ == Object.prototype,而foo2.__proto__ == Bar.prototype。在JavaScript中,没有类,也没有实例,只有计划对象。

现在,如果您设置Bar.prototype.property = "value",然后查找foo2.property首先检查,foo2是否有自己的属性property。如果没有,则继续foo2.__proto__,直到找到具有名为property的自有属性的对象,或者直到找到其__proto__null的对象为止(通常是Object.prototype)。

现在显而易见的是,通过声明Bar.prototype.property,当您没有自己的属性foo2.property时,您正在设置默认值,查找property解析为foo2.property 。在构造函数中设置foo2定义node <Person*> * findoldest (node <Person*> * n) { if n->right != null : right_oldest = findoldest(n->right) if n->left != null: left_oldest = findoldest(n->left) return the node that has max value in (right_oldest.data.birthday, left_oldest.data.birthday, n.data.birthday) } 自己的属性。您可以将其称为实例变量,但实际上,它只是一个哈希映射键。