javascript - Prototype 构造器和私有(private)属性的区别

标签 javascript html

考虑第一种情况:

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

名词

  1. 某物(尤其是机器)的第一个、典型或初步模型,可以从中开发或复制其他形式。

动词

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

原型(prototype)是从中复制另一种形式的模型。

当您在 JavaScript 中创建一个新对象时,就会发生这种情况。

var obj = new MyObject();

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

  1. 原型(prototype)应用于新对象。
  2. 调用函数 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/

相关文章:

javascript - 点击任意位置打开关闭侧边栏

jquery - 向上滚动以突出显示验证失败时的 div

javascript - 在 Javascript 中调用带参数的函数和 OnClick 触发不带参数的函数之间的区别?

javascript - 如何处理 webelement is - not attribute id(!) in javascript from selenium-python?

javascript - 正则表达式奇怪地不起作用

javascript - Firefox 浏览器缓慢加载 AngularJS 应用程序

javascript - 通过单击另一个元素将类切换到一个元素

Javascript-创建元素作为另一个元素的子元素

javascript - 如何在 Angularjs 中给出 $this

javascript - Reactjs 中的嵌套注释