函数的扩展
length
函数的length
属性,用于返回函数的参数个数。但需要注意的是,如果我们使用了参数默认值,则length
属性只能返回没有默认值的参数个数。
function func1(a, b, c){}
console.log(func1.length); // 3
function func2(a, b = 1, c = 2) {}
console.log(func2.length); // 1
length
有什么用?比如我们可以自己手写一个不算太完美的柯里化函数。
function curry(fn){
let acceptArgs = [];
let fnArgsLen = fn.length;
return function next() {
acceptArgs.push(...arguments);
if (acceptArgs.length < fnArgsLen) {
return next;
} else {
return fn.apply(null, acceptArgs);
}
}
}
function add(a, b, c) {
return a + b + c;
}
let newAdd = curry(add);
console.log(newAdd(1)(2)(3)); // 6
// newAdd(1,2)(3)或newAdd(1,2,3)也可以
name
函数的name
属性,返回该函数的函数名。
function hello(){}
console.log(hello.name); // hello
console.log((new Function()).name); // anonymous
// 使用bind之后的函数,前缀会加上bound
console.log(hello.bind({}).name); // bound hello
箭头函数
主要聚焦于箭头函数的使用注意点。
- 箭头函数没有自己的
this
对象; - 不能当作构造函数,即不能对箭头函数使用
new
; - 箭头函数内没有
arguments
对象; - 不能用作Generator函数,不能使用
yield
命令。
this
最需要注意的便是箭头函数内部的this
指向问题。因为箭头函数没有自己的this
对象,箭头函数的this
永远指向它定义时所在的上层作用域(也可以理解为外层第一个普通函数的this
),且不会改变。所以call
、apply
、bind
这些改变this
指向的不会生效。
let a = {
i: 0,
func1: function() {
console.log('func1: ' + this.i);
},
func2: () => {
console.log('func2: ' + this.i);
}
}
let obj = {
i: 100,
}
var i = 500;
a.func1.call(obj); // 100
a.func2.call(obj); // 500,func2在定义时,它的外层能够拿到this的便是window。如果将var i改用let声明,因为let声明的变量并不是挂在window上,则不是输出500,而是undefined
再添加一个例子巩固:
var i = 'window'
let obj = {
i: 'obj',
func: function() {
return () => {
console.log(this.i);
}
},
func2: function() {
return function() {
console.log(this.i);
}
}
}
let obj2 = {
i: 'obj2'
}
let newFunc = obj.func().bind(obj2); // 即使用了bind,仍旧指向原来的的调用对象obj。
let newFunc2 = obj.func2().bind(obj2);
newFunc(); // obj
newFunc2(); // obj2
new
因为new
的原理中涉及到this
的绑定,那没有this
的箭头函数自然而然不能当作一个构造函数来new
。不能使用new
,那也就无法使用ES6新引入的属性new.target
。
const A = () => {}
let a = new A(); // Uncaught TypeError: A is not a constructor
arguments
箭头函数内部没有自己的arguments
对象。
const func = () => {
console.log(arguments); // Uncaught ReferenceError: arguments is not defined
}
func();
需要使用rest
参数来代替。
const hello = (...rest) => {
console.log(rest);
}
hello(1,2,3); // [1,2,3]
generator
直接在语法上就无法将generator函数的符号*
拼凑上去。
箭头函数不适用的场景
如果我们需要用this
来判断调用发生的目标对象,则不适合用箭头函数。
<button>click</button>
<script>
const btn = document.querySelector('button');
btn.addEventListener('click', () => {
console.log(this); // 此时this指向window,改window上的innerHTML没有实际意义了
this.innerHTML = 'Changed!';
});
// 需改成
btn.addEventListener('click', function() {
console.log(this);
this.innerHTML = 'Changed!';
});
</script>
总结来说,就是如果一个函数内部需要用到动态this
(在执行时确定),则不适合使用箭头函数。