当你通过“this”作为参数时
我试图了解this
,这让我感到困惑:
var randomFunction = function(callback) { var data = 10; callback(data); }; var obj = { initialData: 20, sumData: function(data) { var sum = this.initialData + data; console.log(sum); }, prepareRandomFunction: function() { randomFunction(this.sumData.bind(this)); } }; obj.prepareRandomFunction();
这是否被devise为自己在代码中第一次呈现? 例如,在我的例子中,我成功地使用它来引用obj
,并将函数绑定到obj
,但由于this
是作为callback函数传递,什么是阻止它被设置为randomFunction
(即什么阻止它从从字面上传递“this.sumData.bind(this)”,以便在从那里调用的时候将其设置为randomFunction
)?
我是一个试图学习的菜鸟。 谢谢。
更新我不完全问这是如何工作的(我不这么认为)。 我主要是想知道为什么this
被设置在我定义它作为我的randomFunction
调用的参数,而不是在randomFunction
调用callback
。 我可能是错的,但如果我将this.sumData.bind(this)
与我现在的callback(data)
交换,我想我会得到一个不同的结果。 这是因为callback
是一个引用this.sumData.bind(this)
时,它是第一次定义(和this
是obj
)?
我想我已经通过这个场景了解到this
是在执行时设置的。 它不会作为parameter passing,以后在参数被调用的时候被设置。
this
函数调用里面根据函数的调用方式来设置。 这有六个主要的方式来设置。
-
正常函数调用:在一个正常的函数调用中,例如
foo()
,this
被设置为全局对象(在浏览器中是window
)或undefined
(在Javascript的严格模式下)。 -
方法调用:如果一个方法被调用,比如
obj.foo()
,那么在函数内部设置为obj
。 -
.apply()或.call():如果使用
.apply()
或.apply()
,则根据传递给.apply()
或.apply()
.call()
。 例如,您可以执行foo.call(myObj)
并将其设置为foo()
针对该特定函数调用的myObj
。 -
使用new:如果用
new
new foo()
等new foo()
的函数调用函数,则会创build一个新的对象,并使用this
set调用构造函数foo
到新创build的对象。 -
使用.bind():当使用
.bind()
,内部使用.apply()
this
指针设置为传递给.bind()
那个调用返回一个新的存根函数。 仅供参考,这不是一个真正的情况,因为.bind()
可以用.apply()
。 -
使用ES6的箭头函数“通过ES6 +中的箭头语法定义一个函数将把当前的词法值绑定到它,所以,无论函数如何在其他地方调用,解释器都会将
this
值设置为这个值当函数被定义时,这与所有其他函数调用完全不同。
有一种第七种方法,通过callback函数 ,但它不是真正的自己的scheme,而是调用callback的函数使用上述scheme之一,并确定当调用callback时this
将是什么值。 您必须查阅文档或调用函数的代码,或者自行testing以确定在callback中将设置的内容。
在Javascript中理解的重要之处在于,JavaScript中的每个函数或方法调用this
设置了一个新的值。 而且,设置哪个值取决于函数的调用方式。
所以,如果你将一个方法作为一个普通的callbackobj.method()
传递,那么默认情况下,这个方法不会被调用为obj.method()
,因此不会为它设置正确的值。 你可以使用.bind()
来解决这个问题。
知道某些callback函数(如DOM事件处理函数)被调用时,也会很有用,这个函数的具体值由调用callback函数的基础结构设置。 在内部,它们都使用.apply()
.call()
或.apply()
所以这不是一个新的规则,而是要注意的事情。 callback函数的“契约”可能包括如何设置这个值。 如果没有明确地设置这个值,那么将按照规则#1进行设置。
在ES6中,通过箭头函数调用一个函数,保持当前的词汇值。 下面是一个数组函数从MDN维护词法的例子:
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();
你的例子obj.prepareRandomFunction();
是上面的规则#2,所以this
将被设置为obj
。
randomFunction(this.sumData.bind(this))
例子是上面的规则#1,所以randomFunction
里面的randomFunction
被设置为全局对象,或者是undefined
(如果是严格模式)。
由于randomFunction正在调用自身使用.bind()
的callback函数,因此在调用callback函数时,它的值将被设置为在this.sumData.bind(this)
传递给.bind()
的值的值this.sumData.bind(this)
通过上面的规则#5。 .bind()
实际上创build了一个新的函数,它是在调用原始函数之后设置一个自定义的值。
以下是有关该主题的其他参考资料:
如何避免“this”引用DOM元素,并引用该对象
对此有更好的理解
“this”这个关键字是如何工作的?
请注意,通过使用.apply()
或.apply()
或.bind()
,您可以创build各种有点奇怪的东西,有时甚至是非常有用的东西,而这些东西在C ++中是不可能的。 你可以采取世界上任何function或方法,并把它称为是其他对象的方法。
例如,这常常用于将arguments
对象中的项目复制到数组中:
var args = Array.prototype.slice.call(arguments, 0);
或类似地:
var args = [].slice.call(arguments, 0);
这需要数组的.slice()
方法并调用它,但是将它作为this
指针提供一个参数对象。 arguments
对象(虽然不是实际的数组)具有足够的类似于数组的function,而.slice()
方法可以对其进行操作,并且最终将arguments
项的副本转换为实际的数组,然后可以对其进行操作直接与真正的数组操作。 这种骗局是不能做的。 如果数组.slice()
方法依赖于arguments
对象中不存在的其他数组方法,那么这个技巧将不起作用,但由于它仅依赖于arguments
对象所具有的[]
和.length
,它确实工作。
所以,这个技巧可以用来从任何对象中“借用”方法,只要你应用它们的对象支持方法实际使用的任何方法或属性,就可以将它们应用到另一个对象。 这不能在C ++中完成,因为在编译时,方法和属性是“硬绑定的”(即使C ++中的虚拟方法绑定到在编译时build立的特定的v表位置),但是可以很容易地在Javascript中完成,因为属性并且通过实际的名字在运行时直接查找方法,因此任何包含正确的属性和方法的对象都可以使用任何对这些方法进行操作的方法。
一步步。
1) this
里面prepareRandomFunction
是obj
obj.prepareRandomFunction()
2) randomFunction
带一个函数:
randomFunction(this.sumData);
3)该函数被调用:
callback(data);
通知callback
被称为没有点,这意味着它没有this
值,这意味着this
是全局对象(或在严格模式下undefined
)。
4) sumData
被调用:
var sum = this.initialData + data;
this
是全局对象, initialData
不存在,你添加undefined
的data
。 意外的结果。
解决scheme:永久绑定:
randomFunction(this.sumData.bind(this));
4) sumData
运行, this
是obj
, obj.initialData
是20
。 有用。
这是否被devise为自己在代码中第一次呈现?
不可以。它是通过调用函数或使用bind来设置的 。
例如,在我的例子中,我成功地使用它来引用obj
因为这个函数被调用:
obj.prepareRandomFunction();
它将这个函数设置为obj 。
并将函数绑定到obj
在:
var obj = { ... prepareRandomFunction: function() { randomFunction(this.sumData.bind(this)); } };
因为prepareRandomFunction已经被obj调用,所以obj.sumData中的值被设置为obj ,并且对randomFunction的调用可以有效地parsing为:
randomFunction(obj.sumData.bind(obj));
但是因为这是作为callback函数传递的,所以阻止它被设置为randomFunction
事实上,你已经在通话中设置为obj 。 如果你想这是randomFunction ,你需要设置它。 randomFunction没有内在的价值,它是由如何调用函数(或使用绑定 )设置的。
(即什么是阻止它从字面上传递“this.sumData.bind(this)”,以便这被设置为randomFunction)?
因为这个代码执行时不是随机的 。
所以:
obj.prepareRandomFunction();
调用prepareRandomFunction与这个设置为obj ,然后(用objreplace这个 :
randomFunction(obj.sumData.bind(obj));
在randomFunction中 , 它没有被设置,所以它默认为全局对象(与这里没有使用的真正无关)。 然后:
var randomFunction = function(callback) { var data = 10; callback(data); };
它创build一个值为10的本地variables数据 ,然后调用sumData ,将其设置为obj并传递数据值。 然后:
sumData: function(data) { var sum = this.initialData + data; console.log(sum); },
而且由于这是obj ,所以赋值有效地解决了:
var sum = obj.initialData + 10;
这是30。
这是一个对象的自我引用。 当你创build一个对象时,或者使用new – 操作符,将它声明为一个对象 – literal或者
通过调用其中一个JS的内置,这将会被分配给它。
但是,由于JS的范围是dynamic的而非瞬态的,所以通常不能太过于依赖这个对象。 这就是为什么你经常会看到如oThis这样的结构:this or var o