【问题标题】:About javascript prototype关于 javascript 原型
【发布时间】:2015-11-02 03:28:54
【问题描述】:

一个关于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);

为什么'TestChildJS'不能得到'val_name_1'?

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

console pic

所以我必须这样写我的代码:

(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);

如何使用第一种方式可以得到第二种方式的内容?

【问题讨论】:

  • 因为initChild 中的TestJS 不是不是 window.TestJS ... 和new TestJS().data 中的data 根据您的代码定义,将是在运行 initData 之前为空对象
  • 顺便说一句,(function (window){...}(window)) 毫无意义。如果您想明确访问全局对象,请使用 this,如:(function(window){...}(this)) 注意在非浏览器主机中,window 将是全局对象,而不是窗口对象。
  • @JaromandaX thx ,在第一个代码 initChild() 方法中,我可以得到这样的数据:console.log(window.TestJS.data.val_name_1);
  • @JaromandaX 我认为指出 为什么 TestJS 和 window.TestJS 在这种特殊情况下不同是很重要的。这是因为 var TestJS 在闭包内创建了一个新的本地绑定。
  • 这就是你发布答案而我只是发表评论的原因

标签: javascript prototype


【解决方案1】:

为什么'TestChildJS'不能得到'val_name_1'?

何时:

TestJS.initData();

运行时,它为 TestJS 对象(由window.TestJS = new TestJS() 分配的对象)添加了一个 data 属性。该属性不被任何其他对象继承。

时间:

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

运行时,new TestJS() 返回的对象还没有调用它的 initData 方法,所以它没有 data 属性,也没有从构造函数继承它(因为属性直接在构造函数本身上,而不是它的原型上)。

还要注意,将新对象分配给 this.data 会直接在实例上创建一个属性,因此添加到 this.data 会修改实例的 data 对象,而不是构造函数原型上的对象。

您的代码(尤其是第二个)中的模式看起来过于复杂。

【讨论】:

  • 我认为 OP 的问题不在于那条特定的行。它似乎只是为了调试目的而添加的。紧随其后的行正在检查 TestJS.data 并且仍然返回未定义。我认为这是一个范围界定问题。
  • 也许,我看不到 OP 发布的图像。这个问题的框架很差,因为它没有首先说明预期的内容。也许是时候关闭了。
【解决方案2】:

这与 IIFE 的范围有关。在闭包内声明的变量会隐藏任何具有相同名称的外部变量。由于在 IIFE 执行后您不再可以访问它的作用域,因此其中的 TempJS 将始终是函数构造函数——而不是实例化对象。

考虑这个例子:

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

func(i); // 1

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

如果我在闭包内重新声明 i 变量,看看会发生什么:

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

func(i); // 1

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

因此,解决您的问题的一种方法是在 IIFE 之前声明一次 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

请注意,我删除了 console.log(new TestJS().data.val_name_1);TestJS 不再是构造函数,所以该行会抛出。

另一种解决方案是将空函数表达式分配给闭包内的window.TestJS,而不是var TestJS。这样做不会创建本地 TestJS 名称,因此会防止歧义。

【讨论】:

  • 请注意,window 被传递给 w,所以不妨使用它(尽管它毫无意义)。 TestJS = function... 应该是 w.TestJS = function...window.TestJS = new TestJS() 应该是 TestJS = new TestJS()。即,要么在任何地方使用 w 别名作为 window,要么根本不使用。
猜你喜欢
  • 2016-06-19
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 2011-01-07
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多