ES6 函數


一、函數參數

1.可以使用默認參數

function add(x=1,y=2){
    return x+y;
}

2.用let或const再次聲明參數會報錯,var不會。

function add(x=1,y=2){
    let x = 1; // error
    const x = 2; // error
    var x = 3;
}

3.使用參數默認值時,函數不能有同名參數。

// 不報錯
function foo(x, x, y) {
  // ...
}

// 報錯
function foo(x, x, y = 1) {
  // ...
}

4.參數默認值不是傳值的,而是每次都重新計算默認值表達式的值。也就是說,參數默認值是惰性求值的。

let x = 99;
function foo(p = x + 1) {
  console.log(p);
}

foo() // 100

x = 100;
foo() // 101

5.通常情況下,定義了默認值的參數,應該是函數的尾參數。

//No
function f(x = 1, y) {
  return [x, y];
}
//Yes
function f(y, x = 1) {
  return [x, y];
}

6.指定了默認值以后,函數的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

7.一旦設置了參數的默認值,函數進行聲明初始化時,參數會形成一個單獨的作用域(context)。等到初始化結束,這個作用域就會消失。這種語法行為,在不設置參數默認值時,是不會出現的。

var x = 1;

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

f(2) // 2
let x = 1;

function f(y = x) {    //參數y = x形成一個單獨的作用域。這個作用域里面,變量x本身沒有定義,
  let x = 2;               //所以指向外層的全局變量x。函數調用時,函數體內部的局部變量x影響不到默認值變量x。
  console.log(y);     
}

f() // 1

如果此時,全局變量x不存在,就會報錯。

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

f() // ReferenceError: x is not defined

下面這樣寫,也會報錯。

var x = 1;

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

foo() // ReferenceError: x is not defined

上面代碼中,參數x = x形成一個單獨作用域。實際執行的是let x = x,由於暫時性死區的原因,這行代碼會報錯”x 未定義“。
8.應用
利用參數默認值,可以指定某一個參數不得省略,如果省略就拋出一個錯誤。

function throwIfMissing() {
  throw new Error('Missing parameter');
}

function foo(mustBeProvided = throwIfMissing()) {
  return mustBeProvided;
}

foo()
// Error: Missing parameter

上面代碼的foo函數,如果調用的時候沒有參數,就會調用默認值throwIfMissing函數,從而拋出一個錯誤。

從上面代碼還可以看到,參數mustBeProvided的默認值等於throwIfMissing函數的運行結果(注意函數名throwIfMissing之后有一對圓括號),這表明參數的默認值不是在定義時執行,而是在運行時執行。如果參數已經賦值,默認值中的函數就不會運行。

二、rest參數

ES6 引入 rest 參數(形式為...變量名),用於獲取函數的多余參數,這樣就不需要使用arguments對象了。
arguments對象不是數組,而是一個類似數組的對象。rest 參數就不存在這個問題,它就是一個真正的數組,數組特有的方法都可以使用。
注意,rest 參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。

// 報錯
function f(a, ...b, c) {
  // ...
}

函數的length屬性,不包括 rest 參數。

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

三、嚴格模式
從 ES5 開始,函數內部可以設定為嚴格模式。ES2016 做了一點修改,規定只要函數參數使用了默認值解構賦值、或者擴展運算符,那么函數內部就不能顯式設定為嚴格模式,否則會報錯。

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

// 報錯
const doSomething = function ({a, b}) {
  'use strict';
  // code
};

// 報錯
const doSomething = (...a) => {
  'use strict';
  // code
};

const obj = {
  // 報錯
  doSomething({a, b}) {
    'use strict';
    // code
  }
};

四、name屬性

函數的name屬性,返回該函數的函數名。

function foo() {}
foo.name // "foo"

如果將一個匿名函數賦值給一個變量,ES5 的name屬性,會返回空字符串,而 ES6 的name屬性會返回實際的函數名。

var f = function () {};

// ES5
f.name // ""

// ES6
f.name // "f"

如果將一個具名函數賦值給一個變量,則 ES5 和 ES6 的name屬性都返回這個具名函數原本的名字。

const bar = function baz() {};

// ES5
bar.name // "baz"

// ES6
bar.name // "baz"

Function構造函數返回的函數實例,name屬性的值為anonymous。

(new Function).name // "anonymous"

bind返回的函數,name屬性值會加上bound前綴。

function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "

五、箭頭函數

如果箭頭函數不需要參數或需要多個參數,就使用一個圓括號代表參數部分。

var f = () => 5;
// 等同於
var f = function () { return 5 };

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

如果箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,並且使用return語句返回。

var sum = (num1, num2) => { return num1 + num2; }

箭頭函數直接返回一個對象,必須在對象外面加上括號,否則會報錯。

// 報錯
let getTempItem = id => { id: id, name: "Temp" };

// 不報錯
let getTempItem = id => ({ id: id, name: "Temp" });

使用注意點

箭頭函數有幾個使用注意點。

(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。

(2)不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。

(3)不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。

(4)不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。

上面四點中,第一點尤其值得注意。this對象的指向是可變的,但是在箭頭函數中,它是固定的。

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

var id = 21;

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

this指向的固定化,並不是因為箭頭函數內部有綁定this的機制,實際原因是箭頭函數根本沒有自己的this,導致內部的this就是外層代碼塊的this。正是因為它沒有this,所以也就不能用作構造函數。
除了this,以下三個變量在箭頭函數之中也是不存在的,指向外層函數的對應變量:arguments、super、new.target。
另外,由於箭頭函數沒有自己的this,所以當然也就不能用call()、apply()、bind()這些方法去改變this的指向。
轉自ECMAScript 6 入門


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM