1. 每个函数都包含两个非继承而来的方法: call()方法和 apply()方法.
2. 相同点: 这两个方法的作用是一样的.
都是在特定的作用域中调用函数, 等于设置函数体内 this 对象的值, 以扩充函数赖以运行的作用域.
一般来说, this 总是指向调用某个方法的对象, 但是使用 call()和 apply()方法时, 就会改变 this 的指向.
每个函数都包含两个非继承而来的方法: apply()和 call(). 这两个方法的用途都是在特定的作用域中调用函数, 实际上等于设置函数体内 this 对象的值. 首先, apply()方法接收两个参数: 一个是在其中运行函数的作用域, 另一个是参数数组. 其中, 第二个参数可以是 Array 的实例, 也可以是 arguments 对象.
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum1(num1, num2){
- return sum.apply(this, arguments); // 传入 arguments 对象
- }
- function callSum2(num1, num2){
- return sum.apply(this, [num1, num2]); // 传入数组
- }
- console.log(callSum1(10,10)); //20
- console.log(callSum2(10,10)); //20
在上面这个例子中, callSum1()在执行 sum()函数时传入了 this 作为 this 值 (因为是在全局作用域中调用的, 所以传入的就是 window 对象) 和 arguments 对象. 而 callSum2 同样也调用了 sum()函数, 但它传入的则是 this 和一个参数数组. 这两个函数都会正常执行并返回正确的结果.
在严格模式下, 未指定环境对象而调用函数, 则 this 值不会转型为 window. 除非明确把函数添加到某个对象或者调用 apply()或 call(), 否则 this 值将是 undefined.
call()方法与 apply()方法的作用相同, 它们的区别仅在于接收参数的方式不同. 对于 call()方法而言, 第一个参数是 this 值没有变化, 变化的是其余参数都直接传递给函数. 换句话说, 在使用 call()方法时, 传递给函数的参数必须逐个列举出来.
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum(num1, num2){
- return sum.call(this, num1, num2);
- }
- alert(callSum(10,10)); //20
关于 this
函数内部的另一个特殊对象是 this, 其行为与 Java 和 C# 中的 this 大致类似. 换句话说, this 引用的是函数执行的环境对象 -- 或者也可以说是 this 值(当在网页的全局作用域中调用函数时, this 对象引用的就是 window).
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //"red"
- o.sayColor = sayColor;
- o.sayColor(); //"blue"
上面这个函数 sayColor()是在全局作用域中定义的, 它引用了 this 对象. 由于在调用函数之前, this 的值并不确定, 因此 this 可能会在代码执行过程中引用不同的对象. 当在全局作用域中调用 sayColor()时, this 引用的是全局对象 window; 换句话说, 对 this.color 求值会转换成对 window.color 求值, 于是结果就返回了 "red". 而当把这个函数赋给对象 o 并调用 o.sayColor()时, this 引用的是对象 o, 因此对 this.color 求值会转换成对 o.color 求值, 结果就返回了 "blue".
理解了 this, 继续看 call 和 apply
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //red
- sayColor.call(this); //red
- sayColor.call(window); //red
- sayColor.call(o); //blue
- sayColor.apply(o); //blue
这个例子是在前面说明 this 对象的示例基础上修改而成的. 这一次, sayColor()也是作为全局函数定义的, 而且当在全局作用域中调用它时, 它确实会显示 "red"-- 因为对 this.color 的求值会转换成对 window.color 的求值. 而 sayColor.call(this)和 sayColor.call(window), 则是两种显式地在全局作用域中调用函数的方式, 结果当然都会显示 "red". 但是, 当运行 sayColor.call(o)时, 函数的执行环境就不一样了, 因为此时函数体内的 this 对象指向了 o, 于是结果显示的是 "blue".
使用 call()(或 apply())来扩充作用域的最大好处, 就是对象不需要与方法有任何耦合关系. 在前面例子的第一个版本中, 我们是先将 sayColor()函数放到了对象 o 中, 然后再通过 o 来调用它的; 而在这里重写的例子中, 就不需要先前那个多余的步骤了.
ECMAScript 5 还定义了一个方法: bind(). 这个方法会创建一个函数的实例, 其 this 值会被绑定到传给 bind()函数的值
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- var objectSayColor = sayColor.bind(o);
- objectSayColor(); //blue
在这里, sayColor()调用 bind()并传入对象 o, 创建了 objectSayColor()函数. objectSayColor()函数的 this 值等于 o, 因此即使是在全局作用域中调用这个函数.
JavaScript 高级程序设计 (第 3 版) 读书笔记
来源: http://www.jianshu.com/p/398fa6911a2f