在ES6之前,不能直接为函数指定默认值,只能采取其他方法:
function test(x,y){
if(typeof y === 'undefinded'){
y = 10;
}
....
}
es6可以允许函数的参数为默认值,只需要在参数后面定义即可:
function test(x,y=10){
...
}
通过这种方式更加简介、明了,但是在es6中参数是默认声明的,即不能同时用let或const再次声明,如下面代码会报SyntaxError: Identifier ‘y’ has already been declared错误
function test(x,y=10){
let y = 20;
}
使用结解构赋值的方式参数必须要为一个对象。
function test({x,y=10}){
console.log(x,y);
}
test({x:1}); //1,10
test({});// undefinded,10
test({x:1,y:2});// 1,2
指定了默认值以后,函数的length属性将返回没有指定默认值的参数个数。
(function(a){}).length // 1
(function(a=1){}).length // 0
(function(a,b=2){}).length // 1
(function(...args){}).length // 0
length属性的返回值等于函数的第一个参数到第一个设置了默认值的参数。
(function(a,b=2,c)).length // 1
设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。不设置默认值时这个作用域是不存在的。
var x = 1;
function test(x,y=x){
console.log(y)
}
test(2) // 2
// ===
var x = 1;
function test(x,y=x){
console.log(y)
}
test() //undefined
// 函数y赋了默认值,会形成单独作用域,此时调用函数传入x=2,y会先选择最近的作用域,及2。第二个函数中x没有传入参数默认值为undefined。
单独的作用域只限于参数部分即括号内部分,函数体则是另外一个作用域。
var x = 1;
function test(y=x){
let x = 2;
console.log(y)
}
test() //1
如果当全局变量x不存在时候则会报 x is not defined错误。一个更复杂的例子理解单独作用域:
var x=1;
// 【test(x,y=function(){x=5;return x;})】test参数为一个单独作用域
// y是一个匿名函数,匿名函数内没有定义x向上找则指向的test参数的x并赋值5
function test(x,y=function(){x=5;return x;}){
// 这里的x是函数体的作用域,不影响参数里的作用域
var x=10;
// y的匿名函数返回的参数里x被赋值的5
console.log(y());
// 输出函数体内部的x
console.log(x);
}
test();
// 这里返回最外层里的x
console.log(x);
// 输出5,10,1
利用参数默认值可以指定某一个参数不得省略,如果省略就抛出一个错误
function throwIfMissing(){
throw new Error('Missing Parameter');
}
function test(x=throwIfMissing()){
...
}
test() // Error:Missing Parameter
ES6引入了rest参数(…变量名),用于获取函数的多余参数,可以用来替代arguments参数。rest参数的变量是一个数组,因此可以使用数组的方法
function add(...values){
console.log( values); // [1,2,3]
let sum = 0;
for(let val of values){
sum += val;
}
return sum;
}
console.log(add(1,2,3));
注:rest参数之后不能在有其他参数,否则会报错
在ES5中函数内部可以设定为严格模式
function test(a,b){
'use strict';
// ...
}
在ES6中增加了一些修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
function test(a,b=a){
'use strict';
// ...
}
function test({a,b}}){
'use strict';
// ...
}
function test(...a){
'use strict';
// ...
}
// 以上形式都会报SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list错误
原因是函数内部的严格模式同时适用于函数参数和函数体,但是,函数执行时先执行参数,然后再执行函数体。
// a的默认值是八进制数070,但是严格模式下不能用前缀0表是八进制,所以会报错
function test(a=070){
'use strict';
return a;
}
js引擎会先执行成功a=070,然后执行函数体,使用严格模式执行时才会报错。
属性name属性返回该函数的函数名
function test(a){
'use strict';
// ...
}
console.log(test.name) // test
注:如果将匿名函数赋值给一个便利,ES5name属性会返回空字符串,ES6会返回实际函数名
var b = function(){
}
// es5
f.name // ""
// es6
f.name // "f"
Function 构造函数返回的函数实例,name属性的值为anonymous
console.log((new Function).name) // anonymous
bind返回的函数,name属性会加上bound前缀
function test(a){
'use strict';
// ...
}
console.log(test.bind({}).name) // bound test
ES6中可以使用=>定义函数
// es6写法:(参数)=>{函数体}
// ()里只有一个参数时可以省略(),{}函数体只有一条语句的时候可以省略,多条语句的时候不能省
let test = v => v;
// es5写法
var test = function(v){
return v;
}
// 两种写法的结果是一样的,但是es6更加简洁
// ====
// 如果函数没有参数:
let test2 = ()=> 5;
// 如果函数返回一个对象,则需要再外面加上():
let test3 = ()=>({a:2});
箭头函数可以与变量解构结合使用:
const full = ({first,last})=> first + ' ' +last;
// 等同于:
function full(params){
return params.first+ ' '+params.last;
}
箭头函数有以下几个使用注意事项:
function foo(){
setTimeout(function(){
console.log('id',this.id);
},100)
}
var id = 21;
foo.call({id:42}); // 在es5中输出21,如果去掉定时器则输出42
// es5中this是在运行时绑定,但是foo函数是在1毫秒后执行,此时this指向全局的id
// es6中this则始终是定义时所在的对象
function foo(){
setTimeout(()=>{
console.log('id',this.id);
},100)
}
var id = 21;
foo.call({id:42}); // 始终输出42
function foo(){
setTimeout(()=>{
console.log('args',arguments); // [2,4,6,8]
},100);
}
foo(2,4,6,8);
函数绑定运算符是并排的双冒号(::),双毛好左边是一个对象,右边是一个函数。该运算符会自动将左边的对象作为上下文环境(即this对象)绑定到右边的函数上。
foo::bar;
// 等同于:
bar.bind(foo);
foo::bar(...arguments);
// 等同于:
bar.bind(foo,arguments);
如果冒号左边为空,右边是一个对象的方法,则等于该将方法绑定在该对象上。
let method = obj::obj.foo;
// 等同于:
let method = ::obj.foo;
let log = ::console.log;
// 等同于:
let log = console.log.bind(console);