在下面的简单示例和JSFiddle这里 - https://jsfiddle.net/jasondavis/dnLzytju/,您可以看到我遇到的问题。
我可以看到它为什么会发生,但我不确定如何在保持相同的JS结构的同时修复它。
问题是当我定义JavaScript对象原型函数时,我有一个具有函数的第二级嵌套对象,在该函数中,我调用父/根级别的函数失败。
以下代码this.nestedObject.nested_object_function()
中的此函数尝试调用函数this.normal_function()
,但它失败并说:
Uncaught TypeError: this.normal_function is not a function
at Object.nested_object_function (VM2493:79)
我认为原因是this
引用this.nestedObject
而不是父对象。
如果是这种情况,那么如何调用该函数,就像我试图从嵌套对象函数中调用父函数一样?
我也试过从JsLibTest.normal_function()
函数调用this.nestedObject.nested_object_function()
作为测试,但我得到了同样的错误。
var JsLibTest = (function (document) {
"use strict";
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
};
/**
* JsLibTest prototype functions
*/
JsLibTest.prototype = {
init: function() {
// as expected this function runs fine
this.normal_function();
// nested level objects functions run fune from parent level object function
this.nestedObject.nested_object_function();
},
normal_function: function() {
console.log('this.normal_function() ran');
},
nestedObject: {
// calling a function on the parent object fails here when called from this nested object function
nested_object_function: function() {
this.normal_function();
console.log('this.nestedObject.nested_object_function() ran');
},
}
};
return JsLibTest;
})(document);
// run it
$(document).ready(function(){
var Sidebar2 = new JsLibTest();
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
答案 0 :(得分:2)
您的评估是正确的。 this
将设置为嵌套对象而不是父对象,这就是为什么它表示函数为undefined
。
您需要的是一种引用父母的方式。对象通常不携带引用引用它们的对象所需的任何信息。当你考虑到许多对象可以在内部引用同一个对象时,这是有道理的。
您可以存储对父对象的引用,并在嵌套函数中引用它:
var nested = {
g() {
this.parent.f();
}
};
var parent = {
f() {
console.log('called');
}
};
nested.parent = parent;
nested.g();
&#13;
或者您可以使用Function.prototype.call
(或something similar)来设置正确的上下文。
var obj = {
f() {
console.log('called');
},
g() {
this.nested.nested_f.call(this);
},
nested: {
nested_f() {
this.f();
}
}
};
obj.g();
&#13;
将最后一个解决方案放入问题的上下文中:
var JsLibTest = (function(document) {
"use strict";
var JsLibTest = function() {
this.init();
};
JsLibTest.prototype = {
init: function() {
this.normal_function();
// NOTICE: Using .call here to set the context
this.nestedObject.nested_object_function.call(this);
},
normal_function: function() {
console.log('this.normal_function() ran');
},
nestedObject: {
nested_object_function: function() {
this.normal_function();
console.log('this.nestedObject.nested_object_function() ran');
}
}
};
return JsLibTest;
})(document);
// run it
$(document).ready(function() {
var Sidebar2 = new JsLibTest();
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
答案 1 :(得分:1)
您的范围无法访问父级,这是正确的。简单的解决方案是将父级传递给嵌套对象,如:
this.nestedObject.nested_object_function(this);
然后在你的嵌套函数中调用parent as:
nested_object_function: function(self) {
self.normal_function();
alert('this.nestedObject.nested_object_function() ran');
}
因为您将此(父)传递为self,然后您可以从嵌套的那个中调用它。
答案 2 :(得分:0)
首先,对象必须是唯一的,具有原型:
this.nestedObject=Object.create(this.nestedObject);
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
//bind to childs:
this.nestedObject.parent=this;
};
现在你可以在你的内部函数中使用this.parent ......
this.parent.normal_function();
如果您希望这是父母,请绑定:
var JsLibTest = function (){
// run init() function on initiation of a new JsLibTest object
this.init();
//bind to childs:
for(i in this.nestedObject){
var el=this.nestedObject[i];
if(typeof el==="function"){
this.nestedObject[i]=el.bind(this);
}
}
};
为了方便起见,可以使用类似的东西(辅助函数):
getfunc:function(...a){
a.reduce((obj,key)=>obj[key],this).bind(this);
}
像这样使用:
JsLibTestInstance("nestedObject","nestedobject_function")();
答案 3 :(得分:0)
是的,您this
函数中的JSLibTest.prototype.nestedObject
值指向nestedObject
而不是JSLibTest,这是正确的。
如果您想保持相同的呼叫签名,可以将nestedObject
声明为IIFE:
nestedObject: (function() {
var that = this;
return {
nested_object_function: function() {
console.log(that);
// this.normal_function();
alert('this.nestedObject.nested_object_function() ran');
}
}
}())
https://jsfiddle.net/dnLzytju/1/
注意:您可能不希望以这种方式声明prototype
它是否有效地删除了对象的所有本机原型方法。
要以类似的方式编写代码,请考虑使用Object.assign
来帮助您。
var foo = Object.assign({}, Function.prototype, {
bar() {
console.log("Hello!")
}
});
foo.bar();