Bas*_*sit 2 javascript reference function object this
我有一个对象,它有另一个内部对象.如何从内部对象调用父对象?
var test = {
init: function () {
var instance = this;
},
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
this.call(); //*** dont work
instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
}
}
};
Run Code Online (Sandbox Code Playgroud)
我正在使用一个可以正常工作的实例,但如果我或其他人在另一个对象中编写了一个实例(同名)var,它会不会冲突并覆盖这个实例呢?
埃里克的回答为你提供了一个如何做你想做的事情的合理例子,但并没有真正说明原因.
在JavaScript中,this完全由函数的调用方式设置(现在 ;请参阅下面的详细信息),而不是定义函数的位置,因为它在其他一些具有相同关键字的语言中(Java,C++,C#,. ..).
编码员,你决定this每次调用函数时会发生什么.主要有两种方式:通过调用通过对象属性的函数(在同一个表达式),或明确使用功能的内置call和apply功能.
使用对象属性:
obj.foo(); // or
obj["foo"](); // both work
Run Code Online (Sandbox Code Playgroud)
这样做有两个非常不同的东西,但它们协作设置this值:首先,通过查找foo对象的属性找到函数引用obj.然后,调用该函数.因为您将其称为检索属性值的同一整体表达式的一部分,所以JavaScript引擎将设置this为obj在调用内.
所以在你的例子中test.parseText.load(),在load调用 this中将是parseText,而不是test因为那load是被查找的对象.
请注意,setting- this-via-property-lookup仅在它们同时完成时才有效.这并不能正常工作:
var f = obj.foo;
f(); // `this` will not be `obj` within the call
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为它们不是同时完成的.属性查找和函数调用是分开的.
call或apply第二种设置this方式更明确:所有函数都有call和apply属性,它们本身就是使用您提供的信息调用函数的函数引用.在这两种情况下,第一个参数是this在调用期间使用的对象.因此,如果我们想修复上面那个不起作用的例子,我们可以这样做:
var f = obj.foo;
f.call(obj); // `this` will be `obj` within the call
f.apply(obj); // same
Run Code Online (Sandbox Code Playgroud)
call和之间的唯一区别apply是你如何提供函数参数.使用call,您将它们作为函数的进一步离散参数提供; 用apply,你传入一个参数数组.
所以这些都做同样的事情:
// 1 - Directly via property
obj.foo("a", "b", "c");
// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");
// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements
Run Code Online (Sandbox Code Playgroud)
您可以看到如何call以及如何apply使用现有结构:
test.parseText.load.call(test.parseText);
Run Code Online (Sandbox Code Playgroud)
这要求test.parseText.load,使得this= test.parseText通话中.
Eric在他的回答中所做的是使用一个闭包来让你更容易调用你期望parseText的this值.
进一步阅读(披露:来自我的博客):
我说:
在JavaScript中,
this完全由函数的调用方式设置 (目前 ...
我说"现在"的原因是,在ES6中,JavaScript正在获得"箭头函数",与其他函数不同,this箭头函数的值是根据它们的创建位置设置的,而不是它们的调用方式:它们得到this从您创建它们的上下文中.
假设您在对象方法中编写代码,并希望使用该对象的另一种方法,我不知道,从数组输出信息(是的,这是设计的).在ES5中,您可能会这样做:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback
Run Code Online (Sandbox Code Playgroud)
如果你没有参与论证,那你就有一个错误:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry); // <== Bug, `this` is either
// `undefined` (strict) or
// the global object (loose)
});
Run Code Online (Sandbox Code Playgroud)
但是由于箭头函数继承this自它们的创建位置而不是基于它们的调用方式来获取它,因此箭头函数版本不需要第二个参数:
this.output("Entries:");
theArray.forEach((entry, index) => {
this.output(index + ": " + entry);
});
Run Code Online (Sandbox Code Playgroud)
如果你担心的只是test改变,那就这样做:
var test = (function() {
var object = {}
object.call = function() {
this.stop(); // works
};
object.stop = function() {
this.parseText(); // apparently works, even though parseText is not a function
};
object.parseText = {
load: function() {
object.call(); // works
}
};
return object;
})();
Run Code Online (Sandbox Code Playgroud)
如果您不知道名称test,可以使用自调用匿名函数来创建包装器,并参考如下所示的对象.
请注意,test它不是对函数的引用,而是对匿名函数的返回值.因为对象名称(obj)包含在函数内部,所以无法从外部读取或修改它
下面的解决方案很整洁,不会污染范围test,并且像魅力一样工作.如前所述,test指的是同一个对象obj.但是,无法obj从外部操纵变量,因此函数内部的代码会中断.
var test = (function(){ //Self-executing function
var obj = {
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
obj.call(); // obj refers to the main object
}
}
};
return obj; //Return the object, which is assigned to `test`.
})(); //Invoke function
Run Code Online (Sandbox Code Playgroud)
在不包装对象的情况下self,不可能可靠地引用this,或对对象内的对象的任何引用.
您当前的解决方案不起作用,请参阅以下代码中的注释:
var obj = {
init: function(){
var instance = this; //`instance` is declared using `var` inside a function
}, // This variable cannot read from "the outside"
parseText: {
load: function(){
instance.call(); //Does NOT work! instance is not defined
}
}
}
Run Code Online (Sandbox Code Playgroud)