Es6 函数的扩展

1.函数的默认值

  • 以前给函数的参数设置默认值
function fn(x,y){
    y=y||'world'
}
fn('Hello') // Hello World
fn('Hello', 'China') // Hello China
fn('Hello', '') // Hello World
  • Es6的写法
function fn(x=0,y=10){
     return x+y
}
fn() // 0
fn(10) // 20
fn(10,20) // 30
  • 不可以使用let或者const重新声明参数
function fn(x){
    let x=10;
}
//error

上面代码中,参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。

  • 使用函数参数默认值不可以有相同的参数
function fn(x,x,y){
}

上边的代码不会报错,因为并没有设置默认值,但是第二个的x的值会覆盖第一个x

function fn(x=5,x,y=10){
//error
}

  • 函数参数默认值与解构赋值结合使用

    • 参数默认值可以与解构赋值的默认值,结合起来使用。
    function fn({a,y:5}){
        console.log(a,y)
    }
    fn() //error 
    fn({}) // undefined,5
    fn({x:1}) // 1,5
    fn({x:1,y:5}) // 1,6
    

    为啦防止上边的第一种错误的情况,可以这么写:

    function fn({x=1,y}={}){
        console.log(x,y)
    }
    fn() //x:1,y:undefined
    

    仔细比较这个代码和上边的代码有什么不同,这里的fn执行的时候没有传入参数,而上边的也没有传入参数,为什么这里的能正常执行呢,是应为,上边的代码没有在fn()执行的时候添加和参数默认值解构的对象,而这里的是在参数里边已经做啦解构赋值,只不过是一个空对象而已.

  • 函数的length

    • 函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真
        function fn(x){
      
        }
      
        console.log(fn.length) // 1
      
        function fn1(x=1){
      
        }
        console.log(fn.length) //0
      
  • 作用域

    • 一旦参数设置啦默认值,函数在声明初始化时会形成一个单独的域,等到初始化结束,域消失,参数没有设置默认值时,是不会形成这个域的
let x= 10;
function fn (x,y=x){ 
    console.log(y)
}
fn(1) // 1

上面代码中,参数y的默认值等于变量x。调用函数f时,参数形成一个单独的作用域。在这个作用域里面,默认值变量x指向第一个参数x,而不是全局变量x,所以输出是2。

let x = 1;

function fn(y = x) {
  let x = 2;
  console.log(y);
}

fn() // 1

在上边的代码中,虽然函数里有变量x,但是这个作用域是在函数声明初始化的时候形成的,所以里边里边的x指向全局的x.

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // ReferenceError: x is not defined

报错是因为在全局中没有找到全局变量x

var x = 1;

function foo(x = x) {
  // ...
}

foo() // ReferenceError: x is not defined

上面代码中,参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错”x 未定义“。

2.rest参数

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

function add(...values) {
  let sum = 0;

  for(var i = 0;i < values.length;i++){
    num+=values[i]
  }

  return sum;
}

add(2, 5, 3) // 10
  • rest必须是最后一个参数,否则会报错
function fn(x,...values,y){
}
//error
  • 函数的length属性,不包括 rest 参数。
function fn(x,y=2,...values){

}
console.log(fn.length)

3.严格模式

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

下边是报错的一些例子:

function a(a, b = a) {
  'use strict';
  // code
}

// 使用啦参数设置默认值报错
const a= function ({a, b}) {
  'use strict';
  // code
};

// 使用啦解构赋值报错
const a= (...a) => {
  'use strict';
  // code
};
// 报错
function doSomething(value = 070) {
  'use strict';
  return value;
}

上面代码中,参数value的默认值是八进制数070,但是严格模式下不能用前缀0表示八进制,所以应该报错。但是实际上,JavaScript 引擎会先成功执行value = 070,然后进入函数体内部,发现需要用严格模式执行,这时才会报错。

解决办法
1.设置全局的严格模式

'use strict';

function a(a, b = a) {
  // code
}

2.套在一个无参数的自执行函数里

let a =(function(){
      'use strict';
    retuen function (x=2,y){
        console.log(x,y)
    }
}())

4.name 属性

  • 函数的name属性,返回该函数的函数名。
function foo() {}
foo.name // "foo"
  • ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
var f = function () {};

// ES5
f.name // ""

// ES6
f.name // "f"
  • 如果将一个具名函数赋值给一个变量,则 ES5 和 ES6 的name属性都返回这个具名函数原本的名字。
var a = function fn(){
 
};
//Es5
console.log(a.name) // fn
//Es6
console.log(a.name) // fn
  • Function构造函数返回的函数实例,name属性的值为anonymous。
(new Function).name // "anonymous"

5.Es6允许使用“箭头”(=>)定义函数。

  • 基本用法
var f = v => 1;
f() //1
// v 函数的形参, 1 函数的实参和返回值
  • 如果有多个参数,使用一个圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

  • 如果要返回一个对象必须在对象外边加圆括号
//报错
let obj= id => { id: id, name: "Temp" };
//不报错
let obj= id => ({ id: id, name: "Temp" });
  • 与解构赋值的结合使用
 var f = ({name,age}) => name+' '+age
 f({name:'suo',age:28}) //"suo 20"

箭头函数使用注意事项

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

上面代码中,setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。

箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子。

6.双冒号运算符

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

7尾调用

  • 什么是尾调用

    • 尾调用是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

    • 调用之后再操作的都不算尾调用

    • 尾调用不一定出现在函数尾部,只要是最后一步操作就好

     // 情况一
    function f(x){
      let y = g(x);
      return y;
    }
    
    // 情况二
    function f(x){
      return g(x) + 1;
    }
    
    // 情况三
    function f(x){
      g(x);
    }
    

情况一 : 调用之后有操作;
情况二 : 调用之后有操作;
情况三 : function(){g(x) return undefined;};

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容