2017-02-17 79 views
1

下面的简单示例和JSFiddle在这里 - https://jsfiddle.net/jasondavis/dnLzytju/您可以看到我遇到的问题。从嵌套对象函数调用JavaScript函数失败

我可以看到它为什么会发生,但我不知道如何解决它,同时保持相同的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: { 
 
      
 
      \t \t // calling a function on the parent object fails here when called from this nested object function 
 
       nested_object_function: function() { 
 
       \t 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>

回答

2

您的评估是正确的。 this将被设置为嵌套对象而不是父对象,这就是为什么它说该函数为undefined

您需要的是一种引用父项的方法。对象通常不会携带引用引用它们的对象所需的任何信息。当你考虑到许多对象可以在内部引用同一个对象时,这是有道理的。

您可以存储对父对象和参考,在嵌套函数的引用:

var nested = { 
 
    g() { 
 
    this.parent.f(); 
 
    } 
 
}; 
 
var parent = { 
 
    f() { 
 
    console.log('called'); 
 
    } 
 
}; 
 
nested.parent = parent; 
 

 
nested.g();

,或者您可以使用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();

把最后解决您的问题的内容:

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(); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

+1

感谢多个演示,最后的解决方案似乎是我自己的最佳解决方案。此外,我现在有很多大JS应用程序正在使用这个相同的JS设计,所以你的答案将解决我有很多问题!谢谢! – JasonDavis

+0

@JasonDavis太棒了!我很高兴能够帮到你:) –

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

是啊,你是正确的,在你的JSLibTest.prototype.nestedObjectthis值功能指向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(); 
+0

你的'bar()''Object.assign'的例子会需要为对象的每个函数运行整个代码吗? – JasonDavis

1

您是正确的范围无权访问父项。简单的解决方法是,你通过父母像嵌套对象:

this.nestedObject.nested_object_function(this); 

然后在嵌套函数调用父为:

nested_object_function: function(self) { 
    self.normal_function(); 
    alert('this.nestedObject.nested_object_function() ran'); 
} 

,因为你通过这个(父)自我,你可以调用它来自嵌套的一个。

+0

这也似乎是一个很好的简单的解决方案,谢谢 – JasonDavis