2015-11-02 89 views
1

一个奇怪的问题:关于JavaScript的原型关于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); 

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

+1

因为'initChild'中的'TestJS'不是**'window.TestJS' ...和''TestJS()。data'中的'data',根据您的代码的定义,直到'initData'运行的对象 –

+0

顺便说一句,'(函数(窗口){...}(窗口))'是毫无意义的。如果你想明确地访问全局对象,使用* this *,如:(function(window){...}(this))'注意在非浏览器主机中,* window *将是全局对象而不是一个Window对象。 – RobG

+0

@JaromandaX thx,在第一个代码的initChild()方法中,我可以得到如下的数据:console.log(window.TestJS.data.val_name_1); –

回答

0

为什么'TestChildJS'无法获得'val_name_1'?当

TestJS.initData(); 

运行时,它增加了一个数据属性到TestJS对象(一个由window.TestJS = new TestJS()分配)。该属性不会被任何其他对象继承。

当:

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

运行,由new TestJS()返回的对象一直没有它的叫又initData方法,因此它不具有数据财产,并没有继承它从构造函数(因为属性直接在构造函数本身上,而不是它的原型)。

还要注意的是分配一个新的对象来this.data创建直接在实例属性,因此增加this.data被修改实例的数据对象,而不是在构造函数的原型之一。

代码中的模式(尤其是第二个模式)似乎不必要的复杂。

+0

我不认为OP的问题是。它似乎只是为了调试目的而添加的。紧接着的一行是检查'TestJS.data'并且仍然返回undefined。我认为这是一个范围界定问题。 –

+0

也许,我看不到OP发布的图像。这个问题构思不佳,因为它没有说明首先会有什么。也许是时候关闭了。 – RobG

0

它与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 

所以一个解决问题的方法是申报TestJS一次在IIFE之前。

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,因此将防止含糊不清。

+1

请注意,* window *被传递给* w *,所以不妨使用它(因为它是毫无意义的)。 'TestJS = function ...'应该是'w.TestJS = function ...'或'window.TestJS = new TestJS()'应该是'TestJS = new TestJS()'。即在任何地方使用* window * *的* w *别名或根本不使用* w *别名。 – RobG

+0

@RobG Yup,同意。 –