ES6之函数的扩展知识点总结(六)

本人学习ES6看的是阮一峰老师的书,写在博客里是因为,只看不动手总结,很多东西理解的不透彻,也容易忽略掉一些知识点,我也只是把我自己理解并且认为重要的总结在一起,如果想要对这一节有准确而深入的理解,请点击http://es6.ruanyifeng.com/#docs/function嗯、阮老师真的很厉害

函数参数的默认值

ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。

function fn(x="donna"){
    console.log("hello:"+x);
}
fn();//hello:donna

注意:参数变量是默认声明的,所以不能用let或const再次声明(可以使用var声明)

function fn(x="donna"){
    let x = "leo";//SyntaxError: Identifier 'x' has already been declared
    console.log("hello:"+x);
}
fn();
function fn(x="donna"){
    var x = "leo";
    console.log("hello:"+x);
}
fn();//hello:leo

使用参数默认值时,函数不能有同名参数。

function fn(x="donna",x){//SyntaxError: Duplicate parameter name not allowed in this context
    console.log("hello:"+x);
}
fn();

但是,如果不设置默认值,是可以有同名参数的

原因是因为一旦参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域,等到初始化结束,这个作用域就会消失,这种语法行为,在不设置参数默认值的时候,是不会出现的。

另外,参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也即是说,参数默认值时惰性求值的。
    let x = 100;
    let z = 0;
    function fn(y = x+1){
         z+= 3;
        console.log(y);
        console.log(z);
    }
    fn();//101   3
    fn();//101   6

与解构赋值默认值结合使用

function  fn({a,b="donna"}={}){
    console.log(a,b);
}
fn();//undefined "donna"
fn({a:1,b:"leo"});//1 "leo"

嗯、再来看个例子:

function fn1({a=0,b=0}={}){
    return console.log([a,b]);
}//设置了对象结构赋值的默认值,同时将函数参数的默认值设为空对象

function fn2({a,b}={a:0,b:0}){
    return console.log([a,b]);
}//没有对象结构赋值的默认值,但是将函数参数的默认值设为一个具有具体属性的对象
fn1();//[0,0]
fn2();//[0,0]
fn1({});//[0,0]
fn2({});//[undefined,undefined]
fn1({a:1});//[1,0]
fn2({a:1});//[1,undefined]
fn1({a:1,b:2});//[1,2]
fn2({a:1,b:2});//[1,2]
fn1({z:3});//[0,0]
fn2({z:3});//[undefined,undefined]

参数默认值的位置:通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数,如果非尾部的参数设置为默认值,实际上这个参数是没法省略的。

还有,如果传入undefined,将触发该参数等于默认值,null则没有这个效果

function fn(a="leo",b="donna"){
    console.log(a,b);
}
fn(undefined,null);//leo,null

函数的length属性(length属性的含义是:该函数预期传入的参数个数)

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数,也就是说,制定了默认值后,length属性将失真。

因为指定了默认值后,预期传入的参数个数就不包括这个参数了(同理,后面的rest参数也不会计入length属性)

rest参数

ES6引入rest参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了,rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中

arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call()方法将其转为数组。rest参数就是一个数组,数组特有的方法它都可以使用。

注意:rest参数之后不能再有其他参数,否则会报错,并且函数的length属性不包括rest参数。

严格模式:从ES5开始,函数内部可以设定为严格模式。

function fn(a, b) {
  'use strict';
 
}

ES6做了一些修改,规定只要函数参数使用了默认值,解构赋值,或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数,但是,函数执行的时候,先执行函数参数,然后执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却因该先于函数体执行。

name属性:函数的name属性,返回该函数的函数名

如果将一个匿名函数赋值给一个变量,ES5的name属性,会返回空字符串,而ES6的name属性会返回实际的函数名

如果将一个具名函数赋值给一个变量,ES5和S6的name属性都会返回这具名函数原本的名字

Function构造函数返回的函数实例,name属性的值为anonymous

bind返回的函数,name属性值会加上bound前缀

let fn1 = function fn(){

}
let fn2 = function(){}
let fn3 = function(){}
let fn4 = new Fun();
function Fun(){}
console.log(fn1.name);//fn
console.log(fn2.name);//fn2
console.log(fn3.bind().name);//bound fn3
console.log(fn4.name);//undefined
console.log((new Function).name);//anonymous

箭头函数:

ES6允许使用箭头函数(=>)

    //ES5函数写法
    var f = function fn(a){
        return a;
    }
  //ES6函数写法
   var f = a => a;

箭头函数的正确使用方式

1、如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分

2、如果箭头函数的代码块部分多于一条语句,就要使用大括号将他们括起来,并且使用return语句返回

3、如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错(因为大括号被解释为代码块)

4、如果箭头函数只有一行语句,且不需要返回值,可以使用下面的方法(前面加void),就不用写大括号了。

 document.onclick = ()=>void alert(0);
 document.onclick = (a,b)=>{
      alert(Number(null));//0
      alert(Number(b));//undefined
  };

使用箭头函数需要注意的点:

1、函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

2、不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

3、不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以使用rest参数代替

4、不可以使用yield命令,因此箭头函数不能用作Generator函数

特别注意:this对象的指向是可变的,但是在箭头函数中,它是固定的。

    document.onclick =function(){
        setTimeout(()=>{
            alert(this);
        },100);
    }//[object HTMLDocument]
    var id = 1;
    var obj = {
        id:3
    }
    var obj2 = {
        id:4
    }
 function foo(){
     return ()=>{
         console.log(this.id);
     }
 }
    var fn = foo();
    foo()();//1(此时箭头函数定义时所在的对象是window)
    foo.call(obj)();//3(此时箭头函数定义时所在的对象是obj)
    fn.call(obj2);//1(此时箭头函数定义时所在的对象是window,注意箭头函数没有自己的this)

研究了好久才搞懂,嗯、注意,箭头函数的this指向是定义时所在的对象(切记是对象,本人刚开始没注意到,所以就总是感觉阮老师搞错了,最后才发现是自己没看仔细)

箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this即是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

除了this,arguments、super、new.target三个变量在箭头函数中也是不存在的,指向外层函数的对应变量

箭头函数可以嵌套箭头函数

双冒号运算符:(::)“函数绑定运算符”

函数绑定运算符是并排的两个冒号,双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);

如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。

var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;
let log = ::console.log;
// 等同于
var log = console.log.bind(console);

如果双冒号运算符的运算结果,还是一个对象,就可以采用链式写法

尾调用优化:

尾调用:是函数式编程的一个重要概念,指某个函数的最后一步是调用另一个函数

function f(x){
  return g(x);
}
一下三种情况都不属于尾调用
// 情况一
function f(x){
  let y = g(x);//调用g函数之后还有赋值操作
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;//调用g函数之后还有操作
}

// 情况三
function f(x){
  g(x);
}//相当于在g(x)后面还有一个return undefined

尾调用不一定出现在函数的尾部,只要是最后一步即可






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值