JS函数方法

apply()

1
func.apply(thisArg, [argsArray])

描述

在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

applycall() 非常相似,不同之处在于提供参数的方式。apply 使用参数数组而不是一组参数列表。apply 可以使用数组字面量(array literal),如 fun.apply(this, ['eat', 'bananas']),或数组对象, 如 fun.apply(this, new Array('eat', 'bananas'))

参数

thisArg

必选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。

argsArray

可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 浏览器兼容性 请参阅本文底部内容。

返回值

调用有指定this值和参数的函数的结果。

示例

apply将数组各项添加到另一个数组

1
2
3
4
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

使用apply和内置函数

1
2
3
4
5
6
7
/* 找出数组中最大/小的数字 */
var numbers = [5, 6, 2, 3, 7];

/* 使用Math.min/Math.max以及apply 函数时的代码 */
var max = Math.max.apply(null, numbers);
/* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */
var min = Math.min.apply(null, numbers);

call()

1
func.call(thisArg, arg1, arg2, ...)

描述

call() 允许为不同的对象分配和调用属于一个对象的函数/方法。

call() 提供新的 this 值给当前调用的函数/方法。你可以使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。

如果没有传递第一个参数,this 的值将会被绑定为全局对象。

参数

thisArg

可选的。在 function 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。

arg1, arg2, ...

指定的参数列表。

返回值

使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined

示例

使用 call方法调用父构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Product(name, price) {
this.name = name;
this.price = price;
}

function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}

function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}

var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);

使用call方法调用匿名函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];

for (var i = 0; i < animals.length; i++) {
(function(i) {
this.print = function() {
console.log('#' + i + ' ' + this.species
+ ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}

使用call方法调用函数并且指定上下文的 ‘this’

1
2
3
4
5
6
7
8
9
10
function greet() {
var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}

var obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj); // cats typically sleep between 12 and 16 hours

使用call方法调用函数并且不指定第一个参数(argument)

1
2
3
4
5
6
7
var sData = 'Wisen';

function display() {
console.log('sData value is %s ', this.sData);
}

display.call(); // sData value is Wisen

如果没有传递第一个参数,this 的值将会被绑定为全局对象。

在严格模式下,this 的值将会是 undefined

1
2
3
4
5
6
7
8
9
'use strict';

var sData = 'Wisen';

function display() {
console.log('sData value is %s ', this.sData);
}

display.call(); // Cannot read the property of 'sData' of undefined

bind()

1
func.bind(thisArg[, arg1[, arg2[, ...]]])

描述

bind() 函数会创建一个新的绑定函数bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数

绑定函数具有以下内部属性:

  • [[BoundTargetFunction]] - 包装的函数对象
  • [[BoundThis]] - 在调用包装函数时始终作为 this 值传递的值。
  • [[BoundArguments]] - 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。
  • [[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数的列表。

参数

thisArg

调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bindsetTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArgnullundefined,执行作用域的 this 将被视为新函数的 thisArg

arg1, arg2, ...

当目标函数被调用时,被预置入绑定函数的参数列表中的参数

返回值

返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。

示例

创建绑定函数

不论怎么调用,这个函数都有同样的 this 值。

JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 this 是原来的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
var module = {
x: 81,
getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

偏函数

bind() 的另一个最简单的用法是使一个函数拥有预设的初始参数。

当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function list() {
return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
return arg1 + arg2
}

var list1 = list(1, 2, 3); // [1, 2, 3]

var result1 = addArguments(1, 2); // 3

// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);

// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37);

var list2 = leadingThirtysevenList();
// [37]

var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]

var result2 = addThirtySeven(5);
// 37 + 5 = 42

var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略

配合setTimeout

在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或 global)对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom(); // 一秒钟后, 调用 'declare' 方法

作为构造函数使用的绑定函数

绑定函数自动适应于使用 new 操作符去构造一个由目标函数创建的新实例。

当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function Point(x, y) {
this.x = x;
this.y = y;
}

Point.prototype.toString = function() {
return this.x + ',' + this.y;
};

var p = new Point(1, 2);
p.toString(); // '1,2'

var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);

// 本页下方的 polyfill 不支持运行这行代码,
// 但使用原生的 bind 方法运行是没问题的:

var YAxisPoint = Point.bind(null, 0/*x*/);

/*(译注:polyfill 的 bind 方法中,如果把 bind 的第一个参数加上,
即对新绑定的 this 执行 Object(this),包装为对象,
因为 Object(null) 是 {},所以也可以支持)*/

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new YAxisPoint(17, 42) instanceof Point; // true

toString()

1
func.toString()

描述

Function对象覆盖了从Object继承来的toString 方法。对于用户定义的 Function 对象,toString方法返回一个字符串,其中包含用于定义函数的源文本段。

返回值

表示函数源代码的一个字符串

示例

1
2
3
4
5
6
7
8
9
10
11
function sum(a, b) {
return a + b;
}

console.log(sum.toString());
// expected output: "function sum(a, b) {
// return a + b;
// }"

console.log(Math.abs.toString());
// expected output: "function abs() { [native code] }"