在 ES6 之前,JavaScript 的函数语法几乎没有发生太大的变化,而遗留的一些问题导致实现一些基本的功能经常要编写很多代码。而 ES6 对函数的大力度改进,让我们编写函数时更加方便且更少出错。
而关于参数的处理以及箭头函数是我非常喜欢的功能。
一、函数形参的默认值
JavaScript 中的函数有一个比较特别的地方是形参和实参的数量可以不相同。当定义的形参没有默认值传入的时候,JavaScript 会为我们自动传入一个默认值。
在 ES5 的阶段,我们通常会自己设置一个默认值,就像下面这样:
function getAge(age) {
age = age || 10;
console.log(age);
}
getAge(12); // 12
getAge(0); // 10
复制代码
这段代码想告诉我们,当传入参数时,我们就取传入的值,如果没有传入,我们就取默认的 10。但是这通常会有一个问题,当我们传入一个 0 的时候,它也会被默认为一个假值,并最终将 age 赋值为 10。
在这种情况下,我们往往通过 typeof
检查参数类型,来实现相关功能:
function getAge(age) {
age = (typeof age !== "undefined") ? age : 10;
console.log(age);
}
getAge(12); // 12
getAge(0); // 10
复制代码
这种写法可以帮助我们更好地处理参数,但仔细想想,若是有多个参数时,这会让我们写许多额外的代码。幸好 ES6 参数默认值设置的出现,让我们可以很好的解决这个问题。
function getAge(age=10) {
console.log(age);
}
getAge(); // 10,使用默认值
getAge(12); // 12,不使用默认值
getAge(0); // 0,不适用默认值,且传入参数为假值的情况
复制代码
值得注意的一点是:
function getAge(age=10, newAge=age) {
console.log(newAge);
}
getAge(); // 10
复制代码
你可以把第二个参数的默认值设置为第一个参数,但是不能把第一个参数的默认值设置为第二个参数。
另一方面,函数的默认值还可以是一个表达式:
function getValue() {
return 3;
}
function add(first, second=getValue()) {
return first + second;
}
add(1, 3); // 4
add(2); // 5
复制代码
二、箭头函数
箭头函数是一个比较有趣的特性。因为简单的语法,大家工作中也经常用到,所以大家也比较熟悉,下面就简单说说箭头函数的语法。
箭头函数有1个参数,且函数体只有一条语句:
let f = value => value;
// 相当于
let f = function(value) {
return value;
};
复制代码
箭头函数没有参数或者有多个参数,参数部分需要使用小括号:
let f = () => 20;
// 相当于
let f = function() {
return 20
};
let f = (a, b) => a + b;
// 相当于
let f = function(a, b) {
return a + b;
}
复制代码
箭头函数的函数体内有多条语句:
let f = (a, b) => {
return a * b;
};
复制代码
想让箭头函数返回一个对象字面量,需要将该字面量包裹在小括号里:
let f = () => ({ id: 1, name: 'zhangsan', age: 18 });
// 相当于
let f = function() {
return {
id: 1,
name: 'zhangsan',
age: 18
};
}
复制代码
简单的介绍完箭头函数的基本语法,我们来看看箭头函数的一些主要特性:
1、箭头函数没有 this 绑定
箭头函数中没有 this
绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,则 this
绑定的是最近一层非箭头函数的 this
;否则,this
的值会被设置为全局对象。
或者再简单一点来说:箭头函数的 this
指向离它最近的父级作用域 。
举个例子:
// 普通函数
let person = {
name: 'zhangsan',
age: 18,
say: function() {
console.log(this); // person 对象
console.log(this.name); // 'zhangsan'
console.log(this.age); // 18
}
};
person.say(); // 普通函数,谁调用,this 指向谁
复制代码
// 箭头函数
let person = {
name: 'zhangsan',
age: 18,
say: () => {
console.log(this); // window 对象
console.log(this.name); // undefined
console.log(this.age); // undefined
}
};
person.say(); // 箭头函数,没有 this,函数内部的 this,指向父级作用域,即全局
复制代码
最后,因为箭头函数中没有 this
,所以也不能用 call()、apply()、bind()
等方法改变 this
的指向。
2、箭头函数没有原型,不能通过 new
来调用
箭头函数的设计初衷是”即用即弃“,所以不能用它来定义新类型。所以,箭头函数中没有 prototype
属性,自然不能实例化,也就是不能用 new
关键字来调用。
let Person = () => {};
let p1 = new Person(); // Uncaught TypeError: Person is not a constructor
let Person = () => {};
console.log(Person.prototype); // undefined
复制代码
3、没有 argments 绑定
// 普通函数
let person = function() {
console.log(arguments);
}
person(1); // 打印 arguments 对象
复制代码
// 箭头函数
let person = () => {
console.log(arguments);
}
person(1); // Uncaught ReferenceError: arguments is not defined
复制代码
总的来说,箭头函数和一些小特性的加入,可以使我们的编码更加方便。
友情链接
如果文章中错误或表述不严谨的地方,欢迎指正
也欢迎大家关注我的同名微信公众号:李等等扣丁