es6学习笔记-函数扩展_v1.0
函数参数的默认值
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
var p = new Point();
console.log(p) // { x: 0, y: 0 }
如果参数默认值是变量,那么参数就不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
let x = 99;
function foo(p = x + 1) {
console.log(p);
}
foo() // 100
x = 100;
foo() // 101
与解构赋值默认值结合使用
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined, 5,触发默认值
foo({x: 1}) // 1, 5 ,触发默认值
foo({x: 1, y: 2}) // 1, 2
//因为参数是一个对象,对象之后才会解析x y参数
foo() // TypeError: Cannot read property 'x' of undefined
//双重默认值,第一重是对象默认值,第二重是对象里面的属性的默认值
function fetch(url, { method = 'GET' } = {}) {
console.log(method);
}
//当触发两重的默认值的时候,会使用最里面的默认值
fetch('http://example.com')
// "GET"
function foo(x = 5, y = 6) {
console.log(x, y);
}
//undefiend会触发默认值,null则不会
foo(undefined, null)
// 5 null
函数的 length 属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
console.log((function (a) {}).length) // 1
console.log((function (a = 5) {}).length) // 0
console.log((function (a, b, c = 5) {}).length) // 2
作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
var x = 1;
//即使x=1,但是没有影响里面的值
function f(x, y = x) {
console.log(y);
}
f(2) // 2
//---------------------------
let x = 1;
//同理,不过这里是函数里面设置了x值来测试
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
如果参数的默认值是一个函数,该函数的作用域也遵守这个规则
let foo = 'outer';
//设置了一个默认值func,是一个匿名函数,匿名函数返回的是foo变量
//这个变量指向的是外部的foo,因为默认值形成的单独作用域没有foo,所以会向上层继续找
function bar(func = x => foo) {
let foo = 'inner';
console.log(func()); // outer
}
//触发默认值,所以输出
bar();
var x = 1;
//y的默认值是一个匿名函数,并且里面设置了x=2,
//这个x是指向参数里的x,他们属于同一个单独的作用域(默认值生成的)
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();//执行y后并没有改变内部函数的x
console.log(x);//所以输出3
}
foo() // 3
console.log(x) // 1,x没有变化,所以是1
应用
参数的默认值不是在定义时执行,而是在运行时执行(即如果参数已经赋值,默认值中的函数就不会运行)
//参数默认值设为undefined,表明这个参数是可以省略的。
function foo(optional = undefined) { ··· }
rest参数
ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
//自动获取了其他参数
console.log(add(2, 5, 3)) // 10
// arguments变量的写法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
function push(array, ...items) {//...的是数组
items.forEach(function(item) {//支持数组的方法forEach
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
扩展运算符
扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。(输出结果并没有使用逗号分隔)
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
替代数组的apply方法
由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。
// ES5的写法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的写法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f(...args);
// ES5的写法
Math.max.apply(null, [14, 3, 77])
// ES6的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
扩展运算符的应用
(1)合并数组
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
console.log(arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
console.log([...arr1, ...arr2, ...arr3])
// [ 'a', 'b', 'c', 'd', 'e' ]
(2)与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
//位置是对应的
console.log(first) // 1
console.log(rest) // [2, 3, 4, 5]
const [first, ...rest] = [];
//当没有参数的时候,rest参数能够获取空数组
console.log(first) // undefined
console.log(rest) // []:
const [first, ...rest] = ["foo"];
//有参数的时候,按顺序
console.log(first) // "foo"
console.log(rest) // []
(3)函数的返回值
直接返回多个值
var dateFields = [1,2,3,4,5];
var d = test(...dateFields);
function test(x,y,z,a,b) {
console.log(x);
console.log(y);
console.log(z);
console.log(a);
console.log(b);
}
d;
(4)字符串
将字符串转为数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
(5)实现了Iterator接口的对象
任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构,但是其他数据结构并没有(主要是对象),需要自己手动设置
(6)Map和Set结构,Generator函数
扩展运算符内部调用的是数据结构的Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符,比如Map结构。
严格模式
ECMAScript 2016标准》做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
name 属性
函数的name属性,返回该函数的函数名。
箭头函数
参考引用:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。