简体   繁体   English

关于JavaScript原型

[英]About javascript prototype

A strange problems about javascript prototype : 有关javascript原型的一个奇怪的问题:

(function(w){
  if(!w)
    return;

  var TestJS = function(){
  };

  TestJS.prototype = {

    data:{},
    initData:function(){
      this.data={
        val_name_1 : 1,
        val_name_2 : 2,
        val_name_3 : "hello-3"
      };
      console.log(this.data);
      return this;
    },

    TestChildJS:{
      initChild:function(){
        console.log(TestJS);
        console.log(TestJS.data);
        console.log(new TestJS().data.val_name_1);
        console.log(TestJS.data.val_name_1);
      }
    }
  };
  window.TestJS =  new TestJS();
})(window);

why 'TestChildJS' can not get 'val_name_1'? 为什么'TestChildJS'无法获得'val_name_1'?

TestJS.initData();
console.log(TestJS.TestChildJS.initChild());

console pic 控制台图片

so I have to write my code like that: 所以我必须这样写我的代码:

(function(w){
  if(!w)
    return;

  var TestJS = function(){
  };
  TestJS.prototype = {

    data:{},

    initData:function(){
      this.data={
        val_name_1 : 1,
        val_name_2 : 2,
        val_name_3 : "hello-3"
      };
      console.log(this.data);
      this.TestChildJS.initParentData(this);
      return this;
    },

    TestChildJS:{
      parentData:{},

      initParentData:function(parent){
        this.parentData = parent.data;
        return this;
      },

      initChild:function(){
        console.log(this.parentData);
      }
    }
  };

  window.TestJS =  new TestJS();
})(window);

How to use the first way can get the content of the second way? 如何使用第一种方式可以获得第二种方式的内容?

why 'TestChildJS' can not get 'val_name_1'? 为什么'TestChildJS'无法获得'val_name_1'?

when: 什么时候:

TestJS.initData();

is run, it adds a data property to the TestJS object (the one assigned by window.TestJS = new TestJS() ). 运行时,它将数据属性添加到TestJS对象( window.TestJS = new TestJS()分配的window.TestJS = new TestJS() )。 That property isn't inherited by any other object. 该属性不会被任何其他对象继承。

When: 什么时候:

console.log(new TestJS().data.val_name_1);

is run, the object returned by new TestJS() has not had it's initData method called yet, so it doesn't have a data property and it doesn't inherit it from the constructor (because the property is directly on the constructor itself, not its prototype). 运行时,由new TestJS()返回的对象尚未调用过initData方法,因此它没有数据属性,也不会从构造函数继承它(因为该属性直接在构造函数本身上,而不是其原型)。

Note also that assigning a new object to this.data creates a property directly on the instance, so adding to this.data is modifying the instance's data object, not the one on the constructor's prototype. 还要注意,为this.data分配一个新对象会直接在实例上创建一个属性,因此添加到this.data就是在修改实例的数据对象,而不是构造函数原型上的对象。

The patterns in your code (especially the second one) seem unnecessarily convoluted. 代码中的模式(尤其是第二个模式)似乎不必要地复杂。

It has to do with the scope of the IIFE. 它与IIFE的范围有关。 A variable declared inside a closure shadows any outer variable with the same name. 在闭包内部声明的变量会遮盖任何同名外部变量。 Since after the IIFE executes you no longer have access to its scope, TempJS inside it will always be a function constructor -- not an instantiated object. 由于执行IIFE之后,您将无法再访问其作用域,因此其中的TempJS将始终是函数构造函数-而不是实例化的对象。

Consider this example: 考虑以下示例:

var i; 
var func = (function(){
   i = 1; 
   return function() { 
        console.log(i) 
   }; 
})(); 

func(i); // 1

i = 2; 
func(i); // 2

If I re-declare the i variable inside the closure, look what happens: 如果我在闭包内部重新声明i变量,请看会发生什么:

var i = 1; 
var func = (function(){
   var i = 1; 
   return function() { 
        console.log(i) 
   }; 
})(); 

func(i); // 1

i = 2; 
func(i); // 1

So one solution to your problem would be to declare TestJS once before the IIFE. 因此,解决您的问题的一种方法是在TestJS之前声明一次TestJS。

var TestJS;

(function(w){
  if(!w)
    return;

  TestJS = function(){
  };

// ...

    TestChildJS:{
      initChild:function(){
        console.log(TestJS.data.val_name_1);
      }
// ...

    window.TestJS =  new TestJS();
})(window);

TestJS.initData(); 
console.log(TestJS.TestChildJS.initChild()); // 1

Notice that I removed console.log(new TestJS().data.val_name_1); 注意,我删除了console.log(new TestJS().data.val_name_1); . TestJS is no longer a constructor function, so that line will throw. TestJS不再是构造函数,因此该行将抛出。

Another solution is to assign the empty function expression to window.TestJS inside the closure, instead of var TestJS . 另一种解决方案是将空函数表达式分配给闭包内的window.TestJS ,而不是var TestJS Doing so will not create a local TestJS name and will therefore prevent the ambiguity. 这样做不会创建本地TestJS名称,因此可以避免歧义。

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

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