考虑第一种情况:
function f(){
console.log("inside the function : " + f.myVar);
}
f.prototype.myVar = 1;
var myObject = new f();
console.log("from the object : " + myObject.myVar);
这是输出:
inside the function : undefined
from the object : 1
问题:为什么myVar在函数中不可用?如果它存储在对象原型(prototype)中,它应该可以在 f() 中访问。
现在这个场景:
function f(){
console.log("inside the function : " + this.myVar);
}
f.prototype.myVar = 1;
var myObject = new f();
console.log("from the object : " + myObject.myVar);
输出:
inside the function : 1
from the object : 1
问题:为什么我得到不同的结果?如果 'this' 指的是对象 f.myVar 不意味着访问 myObject 中的 myVar 吗?
现在这个场景:
function f(){
console.log("inside the function : " + f.myVar);
console.log("inside the function using 'this' : " + this.myVar);
}
f.myVar = 1;
var myObject = new f();
console.log("from the object : " + myObject.myVar);
输出:
inside the function : 1
inside the function using 'this' : undefined
from the object : undefined
因此,如果我在不使用原型(prototype)的情况下设置一个属性,那么它不应该在实例化对象中可用。但是如果我这样写脚本,它会产生一个奇怪的结果:
function f(){
console.log("inside the function : " + f.myVar);
}
f.myVar = 1;
var myObject = new f();
console.log("from the first object : " + myObject.myVar);
var strangeObject = myObject.constructor;
console.log("from the strange object : " + strangeObject.myVar);
输出:
inside the function : 1
from the first object : undefined
from the strange object : 1
“f.myVar”存储在哪里?那是谁的变量?我很困惑上面所有场景之间的区别是什么。非常感谢完整的说明。
编辑:
主要问题是我不知道这到底是什么意思:
function f(){}
f.someVar = someValue;
因为在其他语言中,函数是一个抽象概念,实际上在调用它之前并不存在。现在在 JS 中据说函数默认是对象。好的,我应该通过上面的脚本得到一个这样的对象:
{someVar : sameValue}
事实上我认为这应该与:
function f(){this.someVar = someValue;} //should create {someVar : someValue}
如果是这种情况,则通过调用“new f()”实例化的每个对象都必须包含此“someVar”,但它们不包含。
最佳答案
首先检查单词原型(prototype) 的定义。我认为在考虑如何在 JavaScript 中创建新对象时牢记这一点很重要。
pro·to·type
名词
- 某物(尤其是机器)的第一个、典型或初步模型,可以从中开发或复制其他形式。
动词
- 制作(产品)原型(prototype)。
原型(prototype)是从中复制另一种形式的模型。
当您在 JavaScript 中创建一个新对象时,就会发生这种情况。
var obj = new MyObject();
在上面的代码中,发生了很多事情,但是在问题的上下文中,发生了两件相关的事情:
- 原型(prototype)应用于新对象。
- 调用函数 MyObject,并将
this
设置为新对象。
了解这些知识后,让我们看一下您描述的不同形式的设置变量:
function MyObject() {}
MyObject.myProperty = 'MyProperty';
了解函数本身是 JavaScript 中的对象这一点很重要。因此,function MyObject
是其自身的一个对象实例。在第二行,我们在这个函数对象上设置了属性 myProperty
。
回到上面的创建步骤,您会注意到它不包括将函数对象的属性应用到新的实例对象。它仅应用函数对象原型(prototype)中的属性,然后运行将 this
设置为新实例的函数主体。
function MyObject() {
this.myProperty = 'MyProperty';
}
在这里,属性 myProperty
是在单个实例上设置的。
function MyObject() {}
MyObject.prototype.myProperty = 'MyProperty';
在此示例中,MyObject
的每个新实例都将被赋予其自己的名为 myProperty
的属性,并将值设置为 'MyProperty'
。从那里,每个实例都可以将自己的 myProperty
更改为它需要的任何值,而不会影响另一个实例。
function MyObject() {
console.log('myProperty', this.myProperty); //Will output 'Outside constructor.'
this.myProperty = 'Inside constructor.';
console.log('myProperty', this.myProperty); //Will output 'Inside constructor.
}
MyObject.prototype.myProperty = 'Outside constructor.';
上面的示例展示了如何首先从原型(prototype)应用 myProperty
,然后在运行的函数中应用值覆盖它。
让我们来看一个包含您提到的所有形式的示例:
var output1 = document.getElementById('output1'),
output2 = document.getElementById('output2'),
output3 = document.getElementById('output3');
function MyObject(myProperty) {
this.myProperty = myProperty;
}
MyObject.myProperty = 'Function property.';
MyObject.prototype.myProperty = 'Prototype property.';
var obj = new MyObject('Constructor property');
output1.innerHTML = obj.myProperty;
output2.innerHTML = MyObject.myProperty;
output3.innerHTML = MyObject.prototype.myProperty;
<div id="output1"></div>
<div id="output2"></div>
<div id="output3"></div>
在上面的示例中,您将看到如何引用每个。现在仔细检查一下。看看从两个不同的对象实例设置“函数属性”时会发生什么:
var output1 = document.getElementById('output1'),
output2 = document.getElementById('output2');
function MyObject() {
//We are concatenating a string to the end of the property on each function call.
MyObject.myProperty += ' test ';
}
MyObject.myProperty = 'Function property.';
var obj1 = new MyObject();
var obj2 = new MyObject();
output1.innerHTML = MyObject.myProperty;
output2.innerHTML = MyObject.myProperty;
<div id="output1"></div>
<div id="output2"></div>
以上代码演示了函数级属性是如何有效共享的。那是因为它不是每个实例的一部分。它是函数对象的一部分。
在这里,我将向您展示使用 new
运算符发生的过程,而不实际使用 new
运算符:
var output = document.getElementById('output');
//Let's have an object that has a prototype property with some properties:
var MyPrototypeObject = {
prototype: {
myPrototypeProperty: 'Prototype property'
}
};
//Let's specify a function that will be used as a constructor:
function MyConstructorFunction() {
this.myInstanceProperty = 'Instance property';
}
//First, new creates an object
var obj = {};
//Next, it applies all the properties from the prototype. We are using the MyPrototypeObject's prototype property for this example
for (var key in MyPrototypeObject.prototype) {
var val = MyPrototypeObject.prototype[key];
//Set the same property on the new object.
obj[key] = val;
}
//Now the prototype has been applied, let's apply the constructor function that was called.
MyConstructorFunction.call(obj); //This calls MyConstructorFunction with this set to obj.
output.innerHTML = 'myPrototypeProperty: ' + obj.myPrototypeProperty + '<br>' + 'myInstanceProperty: ' + obj.myInstanceProperty;
<div id="output"></div>
关于javascript - Prototype 构造器和私有(private)属性的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31744586/