手记

阮一峰的ES6---函数的扩展

函数的扩展

一,函数参数的默认值
在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;//error
const 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 5
fn({x:1})//1 5
fn({x:1,y:2})//1 2
fn();//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')//error
person("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的指向;

1人推荐
随时随地看视频
慕课网APP