函数的扩展
一,函数参数的默认值
在ES5中,设置参数的默认值:
function (x,y){ x = x || "hello"; y = y || " world"; console.log(x+y); } //但是如果y赋值为false时,那么y还是为默认值 因此要先判断x和y的数据类型 function(x,y){ if(typeof x === 'undefined'){ x="hello"; } if(typeof y === 'undefined'){ y=" world"; } console.log(x+y); }
ES6允许在参数的默认值直接写在参数后面
function Person (name="MGT360124", age=18){ this.name = name; this.age = age;}let p = new Person();p//{name:"MGT360124",age:18}
参数变量是默认声明的,不能用let 或者const再次声明。使用默认参数时,函数不能有同名参数;
function fn(x = 5){ let x=1;//errorconst x= 2;//error}function fn(x,x,y){//允许}function fn(x,y,y=10){//出错}
二,与解构赋值默认值结合使用
参数默认值可以与解构赋值的默认值,结合起来使用
function fn(x,y=5){ console.log(x,y);}fn({})//undefined 5fn({x:1})//1 5fn({x:1,y:2})//1 2fn();//TypeError :cannot read property "x" of undefined
三,参数默认值的位置
function person(name,age=18,sex){return [x,y,z];}person()//[undefined ,18, undefined]person("MGT")//["MGT",18,undefined ]person("MGT", , 'M')//errorperson("MGT",undefined,"M")//["MGT",18,"M"]
四,函数的length属性
length属性的返回值,等于函数的参数个数减去指定了默认值的参数个数
(function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2
如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
(function (a = 0, b, c) {}).length // 0(function (a, b = 1, c) {}).length // 1
五,作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context),等到初始化结束时,这个作用域就会消失,这种语法行为,在不设置参数默认值时,是不会出现的;
var x= 1;function fn(x,y =x){console.log(y)}fn(2);//2
参数y的默认值就等于变量x,调用函数时,参数形成一个单独的作用域,在这个作用域里面,默认值变量y指向第一个参数x,而不是全局变量x,所以输出的是2;
let x =1;function fn(y =x){ let x =2;console.log(y);}fn();//1
上面的代码中,函数调用时,参数y = x形成一个单独的作用域,这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x,函数调用时,函数体内部的局部变量影响不到默认值的变量x;如果全局变量x不存在,那么就会报错
function fn(y=x){let x =3;console.log(y);}fn();//ReferenceError :x is not defined
六,rest参数(...变量名)
ES6引入rest参数(形式为 ...变量名),用于获取函数的多与参数,这样就不需要使用arguments对象了,rest参数搭配的搭配的变量是一个数组,该变量将多余的参数放入数组中;
function add(...values) { let sum = 0; for(var val of values){ }return sum;}add(2,5,3);//10
add是一个求和函数,利用rest参数可以求任意数目的参数
严格模式
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
七,name属性
函数name属性,返回该函数的函数名
function person(){}person.name //'person'
箭头函数(=>)
var f = v => v;//等同于var f = function(v) {return v;}
如果箭头函数不需要参数或者需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;f()//5//等同于var f = function (){ return 5};var sum = (num1,num2) =>num1+num2;//等同于var sum = function(num1,num2){ return num1+num1;}sum(1,2)//3
由于花括号{}被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上一个括号,否则会报错
let getTempItem = id =>( {id:id,name:'MGT'} )getTempItem(360124)//{id:360124,name:"MGT"}//等同于let getTempItem = function(id){ return { id:id, name:"MGT" };}getTempItem(360124)
如果箭头函数只有一行语句,且不需要返回值:
let fun = () => void doesNotReturn();
箭头函数可以结合变量解构使用
let full = ({first,escond}) => first +" "+ second ;//等同于function full(person){ return person.first +" "+person.last;}
箭头函数简化回调函数
[1,2,3].map(function(x){return x*x})//[1,4,9]//简化[1,2,3].map(x=>x*x);
箭头函数的注意点
(1)函数体内的this对象,就是定义时所在的对象,而不是使用所在的对象;
(2)不可以当作构造函数,不能使用new命令
(3)不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替
(4)不可以使用yield命令,因此箭头函数不能用作Generator函数
this对象的指向是可变的,但是在箭头函数中,他是固定的
funnction foo(){ setTimeout( () => { console.log("id :", this.id); },1000);}var id =21;foo.call( { id:42} );// id :42
setTimeoout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它真正执行要等到1000毫秒以后,如果他是普通函数,执行时this应该指向全局对象window,这时输出的是21,但是箭头函数导致this总是指向函数定义生效时所在的对象{id :42},所以输出42;
function Timer () { this.s1 = 0; this.s2 = 0; setInterval( () => this.s1++,1000 ); setInterval( function () { this.s2++; },1000);}var timer = new Timer();setTimeout( ()=> console.log("s1 : ", timer.s1),3100);setTimeout( ()=> console.log("s2 : ", timer.s2),3100);//s1 : 3//s2 : 0
Timer函数内部设置了两个定时器,分别为箭头函数和普通函数,前者的this绑定定义时所在的作用域(为TImer函数),后者的this指向运行时所在的作用域(window),所以3100毫秒之后,timer.s1更新了3次,而timer.s2一次都没更新;
箭头函数可以让this指向固定化,这种特性很有利于封装回调函数;
var handler ={ id :"123456", init :function () { document.addEventListener("click", event => this.doSomething(event.type), false); }, doSomething:function (type) { console.log('handling '+type + " for " +this.id); }};
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this,正是因为他没有this,所以也就不能用作构造函数。
由于箭头函数没有自己的this,所以当然也就不能用call().apply(),bind()这些方法去改变this的指向;