从嵌套对象函数调用JavaScript函数失败

时间:2017-02-17 19:27:02

标签: javascript

在下面的简单示例和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;
&#13;
&#13;

4 个答案:

答案 0 :(得分:2)

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

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

您可以存储对父对象的引用,并在嵌套函数中引用它:

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

nested.g();
&#13;
&#13;
&#13;

或者您可以使用Function.prototype.call(或something similar)来设置正确的上下文。

&#13;
&#13;
var obj = {
  f() {
    console.log('called');
  },
  g() {
    this.nested.nested_f.call(this);
  },
  nested: {
    nested_f() {
      this.f();
    }
  }
};

obj.g();
&#13;
&#13;
&#13;

将最后一个解决方案放入问题的上下文中:

&#13;
&#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;
&#13;
&#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();