开发过程中,我们会经常定义一堆函数,函数内部运算处理结果。但是你真的了解function的用法吗?如下4种方法的定义有区别吗?现在可以仔细思考一下。
// 函数关键字
function f1(name) {
console.log(`hello ${name}!`)
}
// 函数字面量
var f2 = function(name) {
console.log(`hello ${name}!`)
}
// Function()构造函数
var f3 = new Function('name', 'console.log(`hello ${name}`)')
// 箭头函数
var f4 = (name) => {
console.log(`hello ${name}!`)
}
函数关键字和函数字面量是我们经常用到的定义方法的方式,使用的方式也很接近,但是他们之前有区别吗?我们看如下的实例:
f1('张三') // hello 张三!
function f1(name) {
console.log(`hello ${name}!`)
}
f2('张三') // Uncaught TypeError: f2 is not a function
var f2 = function(name) {
console.log(`hello ${name}!`)
}
从上面的例子能发现,函数字面量来定义方法,在函数定义前使用,js报错了,但是函数关键字定义方法可以正常运行。这是因为函数关键字定义方法是可以函数提升的,就算你在定义函数前使用了这个函数,也可以正常运行。而函数字面量方式定义了一个匿名函数,将其赋值给变量f2,在调用f2('张三')时,js判断使用了f2变量,将变量提升到使用前,但是此时并没有赋值,所以f2是undefined。 现在我们从运行效率方面看下,这2种的运行速度:
console.time('f1')
function f1(name) {
console.log(`hello ${name}!`)
}
f1('张三')
console.timeEnd('f1') // f1: 0.098876953125 ms
console.time('f2')
var f2 = function(name) {
console.log(`hello ${name}!`)
}
f2()
console.timeEnd('f2') // f2: 0.101806640625 ms
从运行效率角度看,函数关键字语句运行效率稍微高点,但是js引擎对函数优化的很好,所以基本上不需要考虑这2中写法的效率问题,根据自己的习惯来就好。 接下来我们看下Function构造函数来创建函数的方式:
function wrapFunction() {
var temp = '我是临时变量'
return new Function('return temp')()
}
wrapFunction() // Uncaught ReferenceError: temp is not defined
从如上的案例可以看出,构造函数的方式生成function是无法访问局部变量的,他会自动升级成顶级函数,不遵循典型的作用域。而且Function()每次执行都会解析函数主体,并创建一个新的函数对象,所以调用Funciton()的效率相对较低。但是对于某些极端场景,function内容是接口返回的,此时我们就需要使用此种方式。
console.time('f3')
var f3 = new Function('name', 'console.log(name)')
f3()
console.timeEnd('f3') // f3: 0.14404296875 ms
终于到了最后一种,箭头函数了。他是es6提案中提出来的,可以简化了写法,和箭头函数的写法一致,但是你知道使用箭头函数过程中会遇到那些坑吗?
var person = {
name: '张三',
sayName: function() {
console.log(`我是${this.name}`)
}
}
person.sayName() // 我是张三
var person = {
name: '张三',
sayName: () => {
console.log(`我是${this.name}`)
},
consoleArguments: () => {
console.log(arguments)
},
sayName1: function() {
return () => console.log(`我是${this.name}`)
}
}
person.sayName() // 我是
person.sayName1()() // 我是张三
person.consoleArguments() // Uncaught ReferenceError: arguments is not defined
我们期望在箭头函数中获取person的this,但是他却拿到了person对象所处作用域的this,也就是指向了window对象。由此可见,箭头函数没有自己的this和arguments对象,所以bind, call和apply是无法改变箭头函数的this指向。但是由于箭头函数也是函数,所以这3个方法并不会报错。
happy hacking!