繁体   English   中英

Prototype构造函数和私有属性之间的区别

[英]difference between Prototype constructor and private property

考虑第一种情况:

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功能不可用? 如果它存储在对象原型中,则应该可以在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

因此,如果我在不使用原型的情况下设置属性,则它不应该在实例化对象中可用。 但如果我像这样编写脚本,它会产生一个奇怪的结果:

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”存放在哪里? 那个变量是什么? 我很困惑上面所有场景之间有什么区别。 非常感谢完整的carification。

编辑:

主要问题是我不知道这究竟是什么意思:

function f(){}
f.someVar = someValue;

因为在其他语言中,函数是一个抽象概念,实际上在调用之前不存在。 现在在JS中,默认情况下,函数是对象。 好的,我应该通过上面的脚本得到这样的对象:

{someVar : sameValue}

事实上,我认为这应该与:

function f(){this.someVar = someValue;} //should create {someVar : someValue}

如果是这种情况,通过调用“new f()”实例化的每个对象必须包含此“someVar”,但它们不包含。

首先检查单词原型的定义。 在考虑如何在JavaScript中创建新对象时,我认为记住这一点非常重要。

原型

名词

  1. 某种东西的典型或初步模型,特别是机器,从中开发或复制其他形式。

动词

  1. 制作(产品)的原型。

原型是一个模型,将从中复制另一个表单。

当您在JavaScript中创建新对象时,这正是发生的事情。

var obj = new MyObject();

在上面的代码中,有很多事情会发生,但在问题的上下文中,有两件事情是相关的:

  1. 原型应用于新对象。
  2. 调用MyObject函数,将this设置为新对象。

有了这些知识,让我们来看看你所描述的不同形式的设置变量:

function MyObject() {}
MyObject.myProperty = 'MyProperty';

了解函数本身是JavaScript中的对象非常重要。 因此, function MyObject是自身的对象实例。 在第二行,我们在此函数对象上设置了属性myProperty

请参阅上面的创建步骤,您会注意到它不包括将函数对象的属性应用于新的实例对象。 它仅应用函数对象原型中的属性,然后使用this set将函数体运行到新实例。

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.';

上面的示例显示了如何首先从原型应用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> 


在上面的示例中,您将看到如何引用每个。 现在仔细研究一下。 看看从两个不同的对象实例设置时'Function属性'会发生什么:

 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> 

为什么myVar没有功能? 如果它存储在对象原型中,则应该可以在f()中访问它。

它可以在函数中访问,但不能像f.myVar那样f.myVar ,而是作为this.myVarf.prototype.myVar

为什么我会得到不同的结果? 如果'this'指的是对象没有f.myVar意味着在myObject中访问myVar?

函数f与对象实例不同。 该函数是对象的构造函数,将其与new关键字一起使用会创建一个与函数分离的实例。

使用f.var ,这是函数对象的属性var 在函数中使用this.var时,即使用new关键字创建的对象实例中的属性var

如果使用f.var ,这是构造函数对象的属性,那么即使您创建了对象的多个实例,它也将是同一个变量,并且只能使用f.var访问f.var

如果使用f.prototype.var ,那么它也将是对象的所有实例都相同的变量,但是也可以使用this.var访问该变量,因为对象继承了原型的成员。

例:

function f() {
  console.log(f.var); // shows "42"
  console.log(f.prototype.var); // shows "0.01"
  console.log(this.var); shows "0.01";
}

f.var = 42;
f.prototype.var = 0.01;

如果您想要一个对象的每个实例都是本地变量,那么您应该不使用这些变量。 您应该为this.var分配一个值,这将使它成为对象实例中的属性。

例:

function f(value) {
    this.var = value;
}

f.prototype.getValue = function(){
  return this.var;
};

var instance1 = new f(42);
var instance2 = new f(0.01);

// now you have two instances with separate values:

console.log(instance1.getValue()); // shows "42"
console.log(instance2.getValue()); // shows "0.01"

至于编辑中的问题,真的很简单:-)

你有一个函数对象function f(){}

你添加到这个对象属性,就像你可以添加属性到javascript f.someVar = 1任何其他对象

这与function f(){this.someVar = someValue;}因为this在javascript中取决于函数调用的方式,如果使用callapply函数调用,则function f(){this.someVar = someValue;}创建的对象,全局对象或其他内容。

使用new运算符创建对象时 - 将f作为构造函数调用,在这种情况下, this内部函数引用创建的对象,并且函数内添加的所有属性作为this.something = val添加到创建的对象。

注意:您不直接使用函数中的任何属性,因此不会将其添加到创建的对象中。

至于prototype :当你创建对象时 - 你只需将创建对象的prototype属性设置为f.prototype对象。 所以在你创建对象的最后,你不要使用任何直接添加到函数对象的属性,只是原型和属性中的属性,在构造函数中手动添加this属性

似乎你对功能和对象的原型感到困惑。

以下是Eloquent Javascript解释其差异的一句话:

重要的是要注意原型与构造函数关联的方式(通过其原型属性)与对象具有原型的方式(可以使用Object.getPrototypeOf检索)之间的区别。 构造函数的实际原型是Function.prototype,因为构造函数是函数。 它的原型属性将是通过它创建的实例的原型,但不是它自己的原型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM