Es6 函數(shù)的擴(kuò)展

1.函數(shù)的默認(rèn)值

  • 以前給函數(shù)的參數(shù)設(shè)置默認(rèn)值
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重新聲明參數(shù)
function fn(x){
    let x=10;
}
//error

上面代碼中,參數(shù)變量x是默認(rèn)聲明的,在函數(shù)體中,不能用let或const再次聲明,否則會報錯。

  • 使用函數(shù)參數(shù)默認(rèn)值不可以有相同的參數(shù)
function fn(x,x,y){
}

上邊的代碼不會報錯,因?yàn)椴]有設(shè)置默認(rèn)值,但是第二個的x的值會覆蓋第一個x

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

  • 函數(shù)參數(shù)默認(rèn)值與解構(gòu)賦值結(jié)合使用

    • 參數(shù)默認(rèn)值可以與解構(gòu)賦值的默認(rèn)值,結(jié)合起來使用。
    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
    

    仔細(xì)比較這個代碼和上邊的代碼有什么不同,這里的fn執(zhí)行的時候沒有傳入?yún)?shù),而上邊的也沒有傳入?yún)?shù),為什么這里的能正常執(zhí)行呢,是應(yīng)為,上邊的代碼沒有在fn()執(zhí)行的時候添加和參數(shù)默認(rèn)值解構(gòu)的對象,而這里的是在參數(shù)里邊已經(jīng)做啦解構(gòu)賦值,只不過是一個空對象而已.

  • 函數(shù)的length

    • 函數(shù)的length屬性,將返回沒有指定默認(rèn)值的參數(shù)個數(shù)。也就是說,指定了默認(rèn)值后,length屬性將失真
        function fn(x){
      
        }
      
        console.log(fn.length) // 1
      
        function fn1(x=1){
      
        }
        console.log(fn.length) //0
      
  • 作用域

    • 一旦參數(shù)設(shè)置啦默認(rèn)值,函數(shù)在聲明初始化時會形成一個單獨(dú)的域,等到初始化結(jié)束,域消失,參數(shù)沒有設(shè)置默認(rèn)值時,是不會形成這個域的
let x= 10;
function fn (x,y=x){ 
    console.log(y)
}
fn(1) // 1

上面代碼中,參數(shù)y的默認(rèn)值等于變量x。調(diào)用函數(shù)f時,參數(shù)形成一個單獨(dú)的作用域。在這個作用域里面,默認(rèn)值變量x指向第一個參數(shù)x,而不是全局變量x,所以輸出是2。

let x = 1;

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

fn() // 1

在上邊的代碼中,雖然函數(shù)里有變量x,但是這個作用域是在函數(shù)聲明初始化的時候形成的,所以里邊里邊的x指向全局的x.

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

f() // ReferenceError: x is not defined

報錯是因?yàn)樵谌种袥]有找到全局變量x

var x = 1;

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

foo() // ReferenceError: x is not defined

上面代碼中,參數(shù)x = x形成一個單獨(dú)作用域。實(shí)際執(zhí)行的是let x = x,由于暫時性死區(qū)的原因,這行代碼會報錯”x 未定義“。

2.rest參數(shù)

ES6 引入 rest 參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù),這樣就不需要使用arguments對象了。rest 參數(shù)搭配的變量是一個數(shù)組,該變量將多余的參數(shù)放入數(shù)組中。

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必須是最后一個參數(shù),否則會報錯
function fn(x,...values,y){
}
//error
  • 函數(shù)的length屬性,不包括 rest 參數(shù)。
function fn(x,y=2,...values){

}
console.log(fn.length)

3.嚴(yán)格模式

從 ES5 開始,函數(shù)內(nèi)部可以設(shè)定為嚴(yán)格模式 , ES2016 做了一點(diǎn)修改,規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值、解構(gòu)賦值、或者擴(kuò)展運(yùn)算符,那么函數(shù)內(nèi)部就不能顯式設(shè)定為嚴(yán)格模式,否則會報錯。

下邊是報錯的一些例子:

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

// 使用啦參數(shù)設(shè)置默認(rèn)值報錯
const a= function ({a, b}) {
  'use strict';
  // code
};

// 使用啦解構(gòu)賦值報錯
const a= (...a) => {
  'use strict';
  // code
};
// 報錯
function doSomething(value = 070) {
  'use strict';
  return value;
}

上面代碼中,參數(shù)value的默認(rèn)值是八進(jìn)制數(shù)070,但是嚴(yán)格模式下不能用前綴0表示八進(jìn)制,所以應(yīng)該報錯。但是實(shí)際上,JavaScript 引擎會先成功執(zhí)行value = 070,然后進(jìn)入函數(shù)體內(nèi)部,發(fā)現(xiàn)需要用嚴(yán)格模式執(zhí)行,這時才會報錯。

解決辦法
1.設(shè)置全局的嚴(yán)格模式

'use strict';

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

2.套在一個無參數(shù)的自執(zhí)行函數(shù)里

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

4.name 屬性

  • 函數(shù)的name屬性,返回該函數(shù)的函數(shù)名。
function foo() {}
foo.name // "foo"
  • ES6 對這個屬性的行為做出了一些修改。如果將一個匿名函數(shù)賦值給一個變量,ES5 的name屬性,會返回空字符串,而 ES6 的name屬性會返回實(shí)際的函數(shù)名。
var f = function () {};

// ES5
f.name // ""

// ES6
f.name // "f"
  • 如果將一個具名函數(shù)賦值給一個變量,則 ES5 和 ES6 的name屬性都返回這個具名函數(shù)原本的名字。
var a = function fn(){
 
};
//Es5
console.log(a.name) // fn
//Es6
console.log(a.name) // fn
  • Function構(gòu)造函數(shù)返回的函數(shù)實(shí)例,name屬性的值為anonymous。
(new Function).name // "anonymous"

5.Es6允許使用“箭頭”(=>)定義函數(shù)。

  • 基本用法
var f = v => 1;
f() //1
// v 函數(shù)的形參, 1 函數(shù)的實(shí)參和返回值
  • 如果有多個參數(shù),使用一個圓括號代表參數(shù)部分
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" });
  • 與解構(gòu)賦值的結(jié)合使用
 var f = ({name,age}) => name+' '+age
 f({name:'suo',age:28}) //"suo 20"

箭頭函數(shù)使用注意事項

(1)函數(shù)體內(nèi)的this對象,就是定義時所在的對象,而不是使用時所在的對象。
(2)不可以當(dāng)作構(gòu)造函數(shù),也就是說,不可以使用new命令,否則會拋出一個錯誤。
(3)不可以使用arguments對象,該對象在函數(shù)體內(nèi)不存在。如果要用,可以用 rest 參數(shù)代替。
(4)不可以使用yield命令,因此箭頭函數(shù)不能用作 Generator 函數(shù)。

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

var id = 21;

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

上面代碼中,setTimeout的參數(shù)是一個箭頭函數(shù),這個箭頭函數(shù)的定義生效是在foo函數(shù)生成時,而它的真正執(zhí)行要等到 100 毫秒后。如果是普通函數(shù),執(zhí)行時this應(yīng)該指向全局對象window,這時應(yīng)該輸出21。但是,箭頭函數(shù)導(dǎo)致this總是指向函數(shù)定義生效時所在的對象(本例是{id: 42}),所以輸出的是42。

箭頭函數(shù)可以讓setTimeout里面的this,綁定定義時所在的作用域,而不是指向運(yùn)行時所在的作用域。下面是另一個例子。

6.雙冒號運(yùn)算符

  • 函數(shù)綁定運(yùn)算符是并排的兩個冒號(::),雙冒號左邊是一個對象,右邊是一個函數(shù)。該運(yùn)算符會自動將左邊的對象,作為上下文環(huán)境(即this對象),綁定到右邊的函數(shù)上面。
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尾調(diào)用

  • 什么是尾調(diào)用

    • 尾調(diào)用是函數(shù)式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數(shù)的最后一步是調(diào)用另一個函數(shù)。

    • 調(diào)用之后再操作的都不算尾調(diào)用

    • 尾調(diào)用不一定出現(xiàn)在函數(shù)尾部,只要是最后一步操作就好

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

情況一 : 調(diào)用之后有操作;
情況二 : 調(diào)用之后有操作;
情況三 : function(){g(x) return undefined;};

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容