Function对象

每次看源码或者找一些求最大值最小值简便方法时,就会遇见call(),apply()这两个方法,当时的理解就是:设置函数上下文,this指向。但是……理解得太片面了,正好有时间,就打算了解一下👏👏👏

1. Function类型

我们先了解一波Function这种引用类型吧~~~

1.1 函数定义

「1」函数声明语法 function fun () {}
「2」函数表达式定义 var fun = function () {}
「3」Function构造函数 var fun = new Function (‘params1’, ‘params2’, ‘return params1 + prams2’)

不推荐使用Function构造函数定义,因为会导致两次解析:第一次是解析常规的js代码,第二次是解析传入构造函数中的字符串

1.2 函数内部的一些属性

每个函数内部都可以使用arguments来访问传入的所有的参数(是一个伪数组);
arguments.callee是一个指针,指向拥有这个arguments对象的函数;
caller是函数对象的属性,保存着调用此函数的函数引用。

1
2
3
4
5
6
7
8
var inner = function() { 
console.log(inner.caller); // outer
// 等价于下面
console.log(arguments.callee.caller)
};
var outer = function() {
inner();
};

如果某函数在全局作用域下调用的话,则某函数的caller为null

1.3 函数属性

「1」长度length:表示的函数接受的命名参数的个数
「2」原型prototype:不可枚举,保存了所有实例方法

2. 函数内部非继承方法:apply,call,bind

apply,call,bind三个方法都是指定在特定作用域内调用此函数,实际上相当于设置了此函数内的this对象的值

2.1 apply

apply(作用域,数组类型参数)
两个参数:一个在其中运行的函数的作用域,一个是参数数组(arguments或者Array实例)

1
2
3
4
5
6
7
8
9
10
11
function sum (num1, num2) {
return num1 + num2;
}
function applySum (num1, num2) {
return sum.apply(this, arguments);
}
function applySum1 (num1, num2) {
return sum.apply(this, [num1, num2]);
}
applySum(10, 10); // 20
applySum1(10, 10); // 20
2.2 call

call(作用域,参数1,参数2,……,参数N)
两类参数:一类也就是第一个参数在其中运行的函数的作用域;另一类也就是参数,是直接传递给函数的参数,传递给函数的参数必须逐一列举出来

1
2
3
4
5
6
7
function sum (num1, num2) {
return num1 + num2;
}
function callSum (num1, num2) {
return sum.call(this, num1, num2)
}
callSum(10 ,10)// 20
2.3 bind IE9+

bind()这个方法会创建一个函数的实例,其this的值会被绑定到传给bind()函数的值。

1
2
3
4
5
6
7
window.color = 'red';
var object = { color: 'blue' };
function getColor () {
return this.color;
}
var getColor1 = getColor.bind(object);
getColor1(); // blue
2.4 apply、call、bind区别

call,apply,bind作用:扩大了函数赖以运行的作用域。
对于call,apply的第一个参数如果指定成null或者undefined的时候,则此时的this就会指向全局环境。

「1」call,apply区别主要在于传参,除了指定作用域的参数外,call的其他参数主要是直接传递给函数的参数,需要一一列举;而apply的其他参数是一个参数数组(arguments或者Array实例)。其实就是参数格式不一样。
「2」bind与call,apply的区别主要是call,apply不会生成一个函数,而是直接传递作用域;而bind则是使用传入的作用域绑定this创建一个函数的实例。

1
2
3
4
var numbers = [1, 2, 3, 4, 5, 6, 7];
var max1 = Math.max.apply(null, numbers);
// 等价于下面
var max2 = Math.max.call(null, ...numbers);