ES 函数基础 —— 属性与方法
ES 中的函数也是对象,因此也有属性和方法。
属性
name
[ES2015]
函数的 name
属性,返回该函数的函数名。
这个属性早就被浏览器广泛支持,但是直到 ES2015,才被写入标准。
function foo() {}
foo.name // "foo"
如果一个将匿名函数赋值给一个变量:
-
ES5 的
name
属性,返回空字符串 -
ES2015 的
name
属性返回实际的函数名
const foo = function () {}
// ES5
foo.name // ""
// ES2015
foo.name // "foo"
如果将一个有函数名的函数赋值给一个变量,ES5 和 ES2015 的 name
属性都会返回这个函数本来的名字。
const foo = function bar() {}
// ES5
foo.name // "bar"
// ES2015
foo.name // "bar"
Function 构造函数返回的函数实例,其 name
属性的值为 'anonymous'
。
(new Function).name // "anonymous"
Function.prototype.bind()
返回的函数, name
属性值会加上 'bound'
前缀。
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
length
length
属性表示函数预期接受的参数的个数。
function sayHi() {
}
function sayName(name) {
}
function sum(num1, num2) {
}
console.log(sayHi.length); // 0
console.log(sayName.length); // 1
console.log(sum.length); // 2
方法
apply()
/ call()
apply()
接受两个参数:
- 函数将要运行的作用域
-
函数的参数数组(也可以是
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))
console.log(callSum2(10, 10))
在上面的代码中, callSum1()
在执行 sum()
函数时传入了 this
(因为是在全局作用域中调用的,所以传入的就是 global
对象)和 arguments
对象。而 callSum2()
同样也调用了 sum()
函数,但它传入的则是 this
和一个参数数组。这两个函数都会正常执行并返回正确的结果。 call()
除了接收的参数不同,其他都相同。call()
的第一个参数还是 this,但是其他参数都直接传递,比如:
function sum(num1, num2) {
return num1 + num2
}
function callSum(num1, num2) {
return sum.call(this, num1, num2)
}
console.log(callSum(10, 10))
结果与使用 apply()
没有什么不同。
使用 apply()
还是 call()
使用哪个方法,取决于你传递参数的方式:
-
如果打算直接传入 arguments 对象或数组,用
apply()
-
否则,就用
call()
- 如果不向函数传递参数,用哪个都无所谓
apply()
/ call()
存在的意义
apply()
/ call()
仅仅是用来传传参数,实在是大材小用。它真正存在的意义是更改函数的执行环境。
function sayColor() {
console.log(this.color)
}
global.color = 'red'
const o = { color: 'blue' }
sayColor() // red
sayColor.call(global) // red
sayColor.call(o) // blue
sayColor()
是作为全局函数定义的。以上代码使用了三种调用方式:
-
在全局作用域中调用时,
this
会指向全局对象,输出red
。 -
sayColor.call(global)
显式地在全局作用域中调用函数,和前一种情况一样。 -
sayColor.call(o)
使函数体内的this
指向了o
,输出blue
apply()
/call()
的好处多多,其中一点 —— 对象不需要与方法有任何耦合关系。
之前,是需要将 sayColor()
函数放到对象 o 中,然后再通过 o 来调用它的:
function sayColor() {
console.log(this.color)
}
const o = { color: 'blue' }
o.sayColor = sayColor
o.sayColor() // blue
bind()
bind()
的作用是函数绑定 —— 创建一个保持了执行环境的函数。
被绑定的函数与普通函数相比有更多开销,必要时再用。
bind()
会创建一个函数的实例,并将传给 bind()
的参数绑定到这个实例的 this
上,比如:
function sayColor() {
console.log(this.color)
}
global.color = 'red'
const o = { color: 'blue' }
const objectSayColor = sayColor.bind(o)
objectSayColor() // blue
上面的代码中,sayColor()
调用其自身的 bind()
方法,并传入对象 o
,这样创建出了 objectSayColor()
函数。 objectSayColor()
函数的 this
绑定了 o
。所以,即便是在全局作用域中调用这个函数,也会显示 blue
。
实现细节
function bind(fn, context) {
return function () {
return fn.apply(context, arguments)
}
}
bind()
中创建了一个闭包,闭包使用 apply()
调用传入的函数,并给 apply()
传递 context
和 arguments
。
toLocaleString()
/ toString()
每个函数继承的 toLocaleString()
和 toString()
方法始终都返回函数的代码。返回的格式因引擎而异:
- 有的返回函数源代码
- 有的返回函数源代码的内部表示(由解析器删除了注释并对某些代码做了改动后的代码)
由于存在差异,所以也没法根据这两个方法返回的结果来实现什么重要的功能。不过这些信息在调试的时候还是挺有用的。