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

时间:2015-07-31 11:01:37

标签: 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在功能上无法使用?如果它存储在对象原型中,则应该可以在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

问题:为什么我会得到不同的结果?如果'这个'是指对象并不是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"但他们没有。

4 个答案:

答案 0 :(得分:2)

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

<强>亲·到·类型

名词

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

    1. 制作(产品)的原型。
    2. 原型是一个模型,将从中复制另一个表单。

      在JavaScript中创建新对象时,情况正是如此。

      var obj = new MyObject();
      

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

      1. 原型应用于新对象。
      2. 调用MyObject函数,this设置为新对象。
      3. 考虑到这些知识,让我们来看看你所描述的不同形式的设置变量:

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

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

        请参阅上面的创建步骤,您会注意到它不包括将函数对象的属性应用于新的实例对象。它仅应用函数对象原型中的属性,然后运行函数体,并将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.';
        

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

答案 1 :(得分:1)

  

为什么myVar在功能上无法使用?如果它存储在对象中   原型应该可以在f()中访问。

可以在函数中访问,但不能f.myVar,而是this.myVarf.prototype.myVar

  

为什么我会得到不同的结果?如果&#39;这个&#39;是指对象   不知道f.myVar意味着在myObject中访问myVar吗?

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

使用f.var时,即函数对象的属性var。在函数中使用this.var时,对象实例中的属性var表示使用了new关键字。

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

如果使用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

答案 2 :(得分:0)

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

你有一个功能对象function f(){}

您添加到此对象属性,就像您可以在javascript f.someVar = 1

中向任何其他对象添加属性

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

当您使用apply运算符创建对象时 - 您将new作为构造函数调用,在这种情况下,f内部函数将引用创建的对象,并且所有属性在函数内添加为{{ 1}}添加到创建的对象。

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

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

答案 3 :(得分:0)

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

以下是Eloquent Javascript解释差异的书的引用:

  

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