2017-02-17 111 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