我刚开始学习Javascript。
根据我的理解,到目前为止,您可以通过两种方式声明类/静态变量。第一种方式:
Blog.prototype.signature = "By Blogger-Name";
第二种方式:
Blog.signature = "By Blogger-Name";
通过使用第一种方法,变量签名可用于所有Blog实例。
但是,对于类的所有实例保持相同值的变量实际上不应该是实例变量。我认为,类/静态变量只能使用第二种方法声明。
因此,我的问题是,是否存在需要/被迫以第一种方式声明变量的情况?或者我对这一切的理解是否缺乏?请告诉我。
编辑:在哪种情况下,第一种方法是首选方法,同样,在哪种情况下,第二种方法是首选?
编辑2:所以我已经知道第一种方法实际上添加了一个默认值的实例属性。这也可以通过在构造函数本身中设置默认值来实现。那么何时以这种方式添加属性(即使用原型)是首选的?
答案 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;
对于&#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.signature
或blog.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)
}
自己的属性。您可以将其称为实例变量,但实际上,它只是一个哈希映射键。