[TOC]
* * * * *
## 一 . Function.prototype.call
> call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
>[info]语法:
~~~
fun.call(thisArg, arg1, arg2, ...)
参数:
thisArg
在fun函数运行时指定的this值。
PS:需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this值。
1.如果这个函数处于非严格模式下,则指定为 null 和 undefined 的 this 值会自动指向全局对象( 浏览器中就是 window 对象 );
2.同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
arg1, arg2, ...
指定的参数列表。
~~~
>[info] 用法 1:模拟面向对象的继承
~~~
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
/*
这一句相当于:
1.把 Product 函数里的this指向当前函数的环境对象;
2.执行Product函数
等价于,给函数增添了一段代码:
this.name = name;
this.price = price;
*/
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
//输出 'cheese'
~~~
>[info]用法 2:为了避免 for循环语句定义的变量,避免因闭包特性而出错
~~~
var person= [
{sex: 'man', name: 'wdd'},
{sex: 'woman', name: 'girl'}];
for (var i = 0; i < person.length; i++) {
(function (i) {
this.print = function () {
console.log('My index is',i);
}
}).call(person[i], i);
}
这个函数给原数组的每个元素(为对象),添加了一个 print 方法
~~~
* * * * *
## 二. Function.prototype.apply
>注意:该方法与 call 只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。
>[info] 用法 1:求出一组数中的最大和最小值
~~~
用传统的方法:
var numbers = [5, 6, 2, 3, 7];
var max = -Infinity, min = +Infinity;
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] > max)
max = numbers[i];
if (numbers[i] < min)
min = numbers[i];
}
利用 apply 借用 Math 的方法:
Math.max/min(arg1,arg2,arg3,...)
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
~~~
* * * * *
## 三. Function.prototype.bind
>`bind()` 方法创建一个新的函数, 当被调用时,将其 this 关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
>[danger] PS:这个方法很大一个功能就是绑定执行环境对象,但是和 call & apply 方法的用法还是很不同的。
>[info]语法:
~~~
fun.bind(thisArg, [arg1,arg2,...])
参数:
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。
当使用new 操作符调用绑定函数时,该参数无效。
arg1, arg2, ...
当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值
返回由指定的this值和初始化参数改造的原函数拷贝
~~~
>[info]用法1(绑定执行环境对象):
~~~
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX();
/*
返回 81
用对象调用这个方法,则函数的执行环境对象就是这个调用对象,即 this 指向这个调用对象
*/
var retrieveX = module.getX;
retrieveX();
/*
返回 9
在这种情况下,this 指向全局作用域
调用这个函数的环境对象是全局作用域
*/
var boundGetX = module.getX.bind(module);
/*
构造了一个新函数,这个函数里的 this 固定指向 module
*/
boundGetX();
// 返回 81
~~~
>[info]用法二:偏函数(Partial Functions)
> `bind()` 的另一个最简单的用法是使一个函数拥有预设的初始参数。这些参数(如果有的话)作为 `bind()` 的第二个参数跟在 `this`(或其他对象)后面。之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。
~~~
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3);
// [1, 2, 3]
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList();
// [37]
var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]
~~~
>[info]用法三:快捷调用
>在你想要为一个需要特定的 this 值的函数创建一个捷径(shortcut)的时候,bind() 方法也很好用。
你可以用 Array.prototype.slice 来将一个类似于数组的对象(array-like object)转换成一个真正的数组,就拿它来举例子吧。
你可以创建这样一个捷径:
~~~
var slice = Array.prototype.slice;
/*
数组以及字符串类型下的一些内置函数,
都是需要调用它们的执行环境对象的,
那么这里绑定的对象就被用作执行环境对象。
*/
slice.apply(arguments);
用 bind() 可以使这个过程变得简单。
在下面这段代码里面,
slice 是 Function.prototype的 apply() 方法的绑定函数,
并且将 Array.prototype 的 slice() 方法作为 this 的值。
这意味着我们压根儿用不着上面那个 apply() 调用了。
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice);
slice(arguments);
~~~