ES6笔记——函数

函数参数的默认值

基本用法

在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属性

指定了默认值以后,函数的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

rest参数

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属性

属性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;
}

箭头函数有以下几个使用注意事项:

  1. 函数体内的this对象就是定义时所在的对象,而不是使用时所在的对象
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
  1. 不可以当作构造函数。也就是说不能使用new
  2. 不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替
  3. 不可以使用yield命令,因此箭头函数不能用作Generator函数
    5、在箭头函数中this、arguments、super和new.target是不存在的,都指向外层函数对应的变量。
function foo(){
    setTimeout(()=>{
        console.log('args',arguments); // [2,4,6,8]
    },100);
}
foo(2,4,6,8);

绑定this(ES7)

函数绑定运算符是并排的双冒号(::),双毛好左边是一个对象,右边是一个函数。该运算符会自动将左边的对象作为上下文环境(即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);

未完待续

你可能感兴趣的:(javascript)