为了建立一个scope chain, 每个JavaScript的代码执行上下文都提供了this关键字。In its most common usage, this
serves as an identity function, providing our neighborhoods a way of referring to themselves. We can’t always rely on that behavior, however: Depending on how we get into a particular neighborhood, this
might mean something else entirely. In fact, how we get into the neighborhood is itself exactly what this
generally refers to. 需要注意特殊的四种情况:
-
Calling an Object’s Method
在典型的面向对象编程时,我们需要一种方式去指向和引用我们调用的对象.
this
serves the purpose admirably, providing our objects the ability to examine themselves, and point at their own properties.var deep_thought = {
the_answer: 42,
ask_question: function () {
return this.the_answer;
}
};
var the_meaning = deep_thought.ask_question();
This example builds an object named
deep_thought
, sets itsthe_answer
property to 42, and creates anask_question
method. Whendeep_thought.ask_question()
is executed, JavaScript establishes an execution context for the function call, settingthis
to the object referenced by whatever came before the last ”.”, in this case:deep_thought
. The method can then look in the mirror viathis
to examine its own properties, returning the value stored inthis.the_answer
: 42. -
Constructor
Likewise, when defining a function to be used as a constructor with the
new
keyword,this
can be used to refer to the object being created. Let’s rewrite the example above to reflect that scenario:<mce:script type="text/javascript"><!--
function BigComputer(answer) {
this.the_answer = answer;
this.ask_question = function () {
return this.the_answer;
}
}
var deep_thought = new BigComputer(42);
var the_meaning = deep_thought.ask_question();
// --></mce:script>
Instead of explicitly creating the
deep_thought
object, we’ll write a function to createBigComputer
objects, and instantiatedeep_thought
as an instance variable via thenew
keyword. Whennew BigComputer()
is executed, a completely new object is created transparently in the background.BigComputer
is called, and itsthis
keyword is set to reference that new object. The function can set properties and methods onthis
, which is transparently returned at the end ofBigComputer
’s execution.Notice, though, that
deep_thought.the_question()
still works just as it did before. What’s going on there? Why doesthis
mean something different insidethe_question
than it does insideBigComputer
? Put simply, we enteredBigComputer
vianew
, sothis
meant “the new object.” On the other hand, we enteredthe_question
viadeep_thought
, so while we’re executing that method,this
means “whateverdeep_thought
refers to”.this
is not read from the scope chain as other variables are, but instead is reset on a context by context basis. -
Function Call
What if we just call a normal, everyday function without any of this fancy object stuff? What does
this
mean in that scenario?- <mce:script type="text/javascript"><!--
- function test_this() {
- return this;
- }
- var i_wonder_what_this_is = test_this();
- // --></mce:script>
In this case, we weren’t provided a context by
new
, nor were we given a context in the form of an object to piggyback off of. Here,this
defaults to reference the most global thing it can: for web pages, this is thewindow
object. -
Event Handler
For a more complicated twist on the normal function call, let’s say that we’re using a function to handle an
onclick
event. What doesthis
mean when the event triggers our function’s execution? Unfortunately, there’s not a simple answer to this question.If we write the event handler inline,
this
refers to the globalwindow
object:<mce:script type="text/javascript"><!--
function click_handler() {
alert(this); // alerts the window object
}
// --></mce:script>
...
- <button id='thebutton' onclick='click_handler()'>Click me!</button>
However, when we add an event handler via JavaScript,
this
refers to the DOM element that generated the event. (Note: The event handling shown here is short and readable, but otherwise poor. Please use a real addEvent function instead.):<script type="text/javascript">
<mce:script type="text/javascript"><!--
function click_handler() {
alert(this); // alerts the button DOM node
}
function addhandler() {
document.getElementById('thebutton').onclick = click_handler;
}
window.onload = addhandler;
// --></mce:script>
...
- <button id='thebutton'>Click me!</button>
Complications
Let’s run with that last example for a moment longer. What if instead of running click_handler
, we wanted to ask deep_thought
a question every time we clicked the button? The code for that seems pretty straightforward; we might try this:
<mce:script type="text/javascript"><!--
function BigComputer(answer) {
this.the_answer = answer;
this.ask_question = function () {
alert(this.the_answer);
}
}
function addhandler() {
var deep_thought = new BigComputer(42),
the_button = document.getElementById('thebutton');
the_button.onclick = deep_thought.ask_question;
}
window.onload = addhandler;
// --></mce:script>
对上面的代码,我们期望点击按钮, deep_thought.ask_question被执行,我们得到返回结果
“42.” 但为什么得到的结果反而是undefined?哪里错了
?
The problem is simply this: We’ve passed off a reference to the ask_question
method, which, when executed as an event handler, runs in a different context than when it’s executed as an object method. 简而言之,ask_question 中的this关键字是指向产生事件的DOM元素节点,而不是BigComputer对象
. DOM元素节点并没有the_answer属性,所以返回结果是
undefined而不是
“42.” setTimeout
exhibits similar behavior, delaying the execution of a function while at the same time moving it out into a global context.
This issue crops up all over the place in our programs, and it’s a terribly difficult problem to debug without keeping careful track of what’s going on in all the corners of your program, especially if your object has properties that do exist on DOM elements or the window
object.
Manipulating Context With .apply()
and .call()
We really do want to be able to ask deep_thought
a question when we click the button, and more generally, we do want to be able to call object methods in their native context when responding to things like events and setTimeout
calls. Two little-known JavaScript methods, apply
and call
, indirectly enable this functionality by allowing us to manually override the default value of this
when we execute a function call. Let’s look at call
first:
<mce:script type="text/javascript"><!--
var first_object = {
num: 42
};
var second_object = {
num: 24
};
function multiply(mult) {
return this.num * mult;
}
multiply.call(first_object, 5); // returns 42 * 5
multiply.call(second_object, 5); // returns 24 * 5
// --></mce:script>
In this example, we first define two objects, first_object
and second_object
, each with a num
property. Then we define a multiply
function that accepts a single argument, and returns the product of that argument, and the num
property of its this
object. If we called that function by itself, the answer returned would almost certainly be undefined
, since the global window
object doesn’t have a num
property unless we explicitly set one. We need some way of telling multiply
what its this
keyword ought refer to; the call
method of the multiply
function is exactly what we’re looking for.
call方法的第一个参数定义了this关键字在被调用方法的执行上下文中指向和对象,call方法的剩余参数则是被调用方法的参数。因此当
multiply.call(first_object, 5)被执行,
multiply函数被调用
, 5
为传入方法的第一个参数, this
执行 first_object对象。
Likewise, when multiply.call(second_object, 5)
is executed, the multiply
function is called, 5
is passed in as the first argument, and the this
keyword is set to refer to object second_object
.
apply方法和
call方法基本一致
,但是允许你以数组的形式向被调用的函数传递参数, which can be quite useful when programatically generating function calls. Replicating the functionality we just talked about using apply
is trivial:
<mce:script type="text/javascript"><!--
...
multiply.apply(first_object, [5]); // returns 42 * 5
multiply.apply(second_object, [5]); // returns 24 * 5
// --></mce:script>
apply
and call
are very useful on their own, and well worth keeping around in your toolkit, but they only get us halfway to solving the problem of context shifts for event handlers. It’s easy to think that we could solve the problem by simply using call
to shift the meaning of this
when we set up the handler:
function addhandler() {
var deep_thought = new BigComputer(42),
the_button = document.getElementById('thebutton');
the_button.onclick = deep_thought.ask_question.call(deep_thought);
}
上面的代码仍然存在问题: call是立即执行函数的,因此我们提供的
onclick
handler是函数的执行结果而不是函数本身.我们需要JavaScript的另一个特性来解决这个问题:bind方法。
The Beauty of .bind()
I’m not a huge fan of the Prototype JavaScript framework, but I am very much impressed with the quality of its code as a whole. In particular, one simple addition it makes to the Function
object has had a hugely positive impact on my ability to manage the context in which function calls execute: bind
performs the same general task as call
, altering the context in which a function executes. The difference is that bind
returns a function reference that can be used later, rather than the result of an immediate execution that we get with call
.
If we simplify the bind
function a bit to get at the key concepts, we can insert it into the multiplication example we discussed earlier to really dig into how it works; it’s quite an elegant solution:
<mce:script type="text/javascript"><!--
var first_object = {
num: 42
};
var second_object = {
num: 24
};
function multiply(mult) {
return this.num * mult;
}
Function.prototype.bind = function(obj) {
var method = this,
temp = function() {
return method.apply(obj, arguments);
};
return temp;
}
var first_multiply = multiply.bind(first_object);
first_multiply(5); // returns 42 * 5
var second_multiply = multiply.bind(second_object);
second_multiply(5); // returns 24 * 5
// --></mce:script>
First, we define first_object
, second_object
, and the multiply
function, just as before. With those taken care of, we move on to creating a bind
method on the Function
object’s prototype
, which has the effect of making bind
available for all functions in our program. When multiply.bind(first_object)
is called, JavaScript creates an execution context for the bind
method, setting this
to the multiply
function, and setting the first argument, obj
, to reference first_object
. So far, so good.
The real genius of this solution is the creation of method
, set equal to this
(the multiply
function itself). When the anonymous function is created on the next line, method
is accessible via its scope chain, as is obj
(this
couldn’t be used here, because when the newly created function is executed, this
will be overwritten by a new, local context). This alias to this
makes it possible to use apply
to execute the multiply
function, passing in obj
to ensure that the context is set correctly. In computer-science-speak, temp
is a closure that, when returned at the end of the bind
call, can be used in any context whatsoever to execute multiply
in the context of first_object
.
This is exactly what we need for the event handler and setTimeout
scenarios discussed above. The following code solves that problem completely, binding the deep_thought.ask_question
method to the deep_thought
context, so that it executes correctly whenever the event is triggered:
function addhandler() {
var deep_thought = new BigComputer(42),
the_button = document.getElementById('thebutton');
the_button.onclick = deep_thought.ask_question.bind(deep_thought);
}
Beautiful.
相关推荐
javascript中apply、call和bind的用法区分_.docx
JavaScript函数之call、apply以及bind方法案例详解 总结 1、相同点 2、区别 call() 方法 /* 正常模式 */ let obj = { sum(a, b) { console.log(this) return a + b } } // 执行 sum 函数的 apply、bind...
js代码-JavaScript的call/apply/bind函数实现
在Javascript中,Function是一种对象。Function对象中的this指向决定于函数被调用的方式,使用apply,call 与 bind 均可以改变函数对象中this的指向。
本文主要Javascript中call,apply,bind方法的进行全面分析,并在文章结尾对call,apply,bind方法的联系和区别做了总结,具有很好的参考价值,需要的朋友一起来看下吧
主要介绍了javascript中call,apply,bind函数用法,结合实例形式分析了call,apply,bind函数的功能、使用方法与相关注意事项,需要的朋友可以参考下
apply/call/bind三者的联系就在于,都可以用来改变函数中 this 指向的值,且第一个参数为要指向的 this 的值,apply的第二个参数(或 bind 与 call 的不定参数)为要传入的参数。这就不得不提及 javascript 中函数的...
浅谈javascript中的call、apply、bind_.docx
在JavaScript中,call、apply和bind是Function对象自带的三个方法,本文将通过几个场景的应用,来详细理解三个方法。 call() call() 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。 ...
本文主要介绍了javascript中apply/call和bind的使用。具有很好的参考价值,下面跟着小编一起来看下吧
主要介绍了JavaScript必知必会(十) call apply bind的用法说明 的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
一、call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。简单的说就是改变函数执行的上下文,这是最...
在JavaScript 中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以我们需要一种可以把this的含义固定的技术,于是就有了call,apply 和bind这三个方法,来改变函数体内部 this 的...
主要介绍了JavaScript中的this/call/apply/bind的使用及区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
主要为大家详细介绍了javascript中的call、apply、bind方法,感兴趣的朋友可以参考一下
Javascript中apply、call、bind都是为了改变函数体内部 this 的指向。下面通过本文重点给大家介绍js中apply,call,bind的巧妙使用方法,感兴趣的朋友一起学习吧