国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入理解ES6之《函數》

Seay / 3448人閱讀

摘要:默認參數中要為參數指定默認值,只能如下所示但是這樣有一個問題如果傳進來的值為,則也會賦值變成,所以更加完全的做法是檢測參數類型中直接可以為任意參數指定默認值,在已指定默認值的參數后可以繼續聲明無默認值參數是否使用函數默認值主要依賴于調用函數

默認參數

ES5中要為參數指定默認值,只能如下所示:

function makeRequst(url, timeout, callback) {
  timeout = timeout || 2000;
  callback = callback || function () { }
}

但是這樣有一個問題如果timeout傳進來的值為0,則也會賦值變成2000,
所以更加完全的做法是檢測參數類型

function makeRequst(url, timeout, callback) {
  timeout = (typeof timeout !== "undefined") ? timeout : 2000;
  callback = (typeof callback !== "undefined") ? callback : function () { }
}

ES6中直接

function makeRequst(url, timeout = 2000, callback = function () { }) {

}

可以為任意參數指定默認值,在已指定默認值的參數后可以繼續聲明無默認值參數

function makeRequst(url, timeout = 2000, callback) {

}

是否使用函數默認值主要依賴于調用函數是實參是否全等于undefined

ES5非嚴格模式下,函數命名參數的變化會體現在arguments對象中

function mixArgs(first, second) {
  console.log(first === arguments[0])//true
  console.log(second === arguments[1])//true
  first = "c"
  second= "d"
  console.log(first === arguments[0])//true
  console.log(second === arguments[1])//true
}
mixArgs("a", "b")

而在嚴格模式下,無論參數如何變化,arguments對象不再隨之改變

function mixArgs(first, second) {
  "use strict"
  console.log(first === arguments[0])//true
  console.log(second === arguments[1])//true
  first = "c"
  second = "d"
  console.log(first === arguments[0])//false
  console.log(second === arguments[1])//false
}
mixArgs("a", "b")

如果使用了函數默認值,則arguments對象的行為將與ES5在嚴格模式下保持一致:arguments對象保持與命名參數分離(備注:其實這種分離的特性可以將參數恢復為初始值)

function mixArgs(first, second="b") {
  console.log(first === arguments[0])//true
  console.log(second === arguments[1])//false
  first = "c"
  second = "d"
  console.log(first === arguments[0])//false
  console.log(second === arguments[1])//false
}
mixArgs("a")

函數默認值除了可以給原始值,還可以指定函數,只不過只有未傳入參數需要默認值時才能去調用些此函數,也就是說默認參數是在函數調用時才求值
指定默認值為函數不要忘記小括號,如果忘記小括號則傳入的是對函數的引用而不是函數調用的結果

function getValue(value) {
  return value + 5
}
function add(first, second = getValue(first)) {
  return first + second
}
console.log(add(1))//7

函數參數有自己的作用域和臨時死區,其與函數體的作用域是各自獨立的,也就是說參數的默認值是不可訪問函數體內聲明的變量

處理無命名參數

在函數命名參數前添加...三個點表明這是一個不定參數

function pick(obj, ...keys) {
  let result = Object.create(null)
  for (let i = 0, len = keys.length; i < len; i++) {
    result[keys[i]] = object[keys[i]]
  }
  return result
}

函數的length屬性統計的是函數命名參數的數量,不定參數的加入不會影響length屬性的值
每個函數最多只能聲明一個不定參數,而且一定要放在所有參數的末尾
不定參數不能用于對象字面量setter之中,因為對象字面量setter的參數有且只能有一個

let obj = {
  //Uncaught SyntaxError: Setter function argument must not be a rest parameter
  set name(...value) {
    console.log(value)
  }
}

看一個有趣的例子:無論是否使用不定參數,arguments對象總是包含所有傳入函數的參數

默認參數和不定參數的特性同樣適用于Function構造函數

var add = new Function("first", "second=first", "return first+second")
console.log(add(1))//2

var pickFirst=new Function("...args","return args[0]")
console.log(pickFirst(1,2))//1
展開運算符

舉例來說,Math.max可接受任意數量的參數并返回最大的那個,但如果傳入的是一個數組,則只能使用apply

console.log(Math.max(11, 2, 3, 12, 43, 904, 3543, 43))
let values = [11, 2, 3, 12, 43, 904, 3543, 43]
console.log(Math.max.apply(Math, values))

使用展開運算符就變得特別簡單了

let values = [11, 2, 3, 12, 43, 904, 3543, 43]
console.log(Math.max(...values))

如果你想限定Math.max返回的最小值為0,還可以如下使用

let values = [-11, -2, -3, -12]
console.log(Math.max(...values, 0))
函數的name屬性

函數的name屬性的值不一定引用同名變量,它只是協助調用用的額外信息,所以不能使用name屬性的值來獲取函數的引用

function doSomething() { }
console.log(doSomething.name)//doSomething

var doSome = function doSomeElse() { }
var person = {
  get firstName() { return "angela" },
  sayName: function () { }
}
console.log(doSome.name)//doSomeElse
console.log(person.sayName.name)//sayName
console.log(person.firstName.name)//undefined

var doThing = function () { }
console.log(doThing.bind().name)//bound doThing
console.log((new Function()).name)//anonymous
函數的多重用途

JS函數中有兩個不同的內部方法:[[Call]]和[[Construct]]
當通過new關鍵字調用函數時,執行的是[[Construct]]函數,它負責創建一個通常被稱作實例的新對象,然后再執行函數體,將this綁定到實例上
如果不是通過new關鍵字調用函數,則執行[[Call]]函數,從而直接執行代碼中的函數體
不是所有函數都有[[Construct]]方法,因此不是所有方法都可以通過new來調用,具有[[Construct]]方法的函數被統稱為構造函數

ES5中想確定一個函數是否通過new關鍵字被調用

function Person(name) {
  if (this instanceof Person) {
    this.name = name
  } else {
    throw new Error("必須通過new關鍵字來調用")
  }
}

但是上述方法不是絕對完全可靠的,比方說如下調用就失效了

var person = new Person("angela")
var notAPerson = Person.call(person, "Shing")//這樣對于函數本身是無法區分是通過Person.Call、Apply還是new調用得到的實例

ES6中可以如下絕對安全的判定

function Person(name) {
  //或者typeof new.target===Person
  if (typeof new.target !== "undefined") {
    this.name = name
  } else {
    throw new Error("必須通過new關鍵字來調用")
  }
}
var person = new Person("angela")
var notAPerson = Person.call(person, "Shing")//拋出錯誤

當調用函數的[[Construct]]方法時,new.target被賦值為new操作符的目標,如果調用的是[[Call]]方法,則new.target的值為undefined
在函數外使用new.target是一個語法錯誤

塊級函數

ES5嚴格模式下,在代碼塊內部聲明函數程序會報錯
在ES6嚴格模式下,可以在代碼塊中聲明函數,塊級函數聲明會被提升至此代碼塊頂部,超出此塊級作用域,則函數將不再存在

"use strict"
if (true) {
  console.log(typeof doSomeThing)  //function
  doSomeThing()//----------
  function doSomeThing() {
    console.log("----------")
  }
}
console.log(typeof doSomeThing) //undefined

在ES6非嚴格模式下,這些函數不再提升至代碼塊的頂部而是提升至外圍函數或全局作用域的頂部

if (true) {
  console.log(typeof doSomeThing)  //function
  doSomeThing()//----------
  function doSomeThing() {
    console.log("----------")
  }
}
console.log(typeof doSomeThing) //function
箭頭函數

箭頭函數與傳統函數有如下幾點不同

沒有this、super、arguments和new.target綁定--也就是說箭頭函數中的this、super、arguments和new.target這些值由外圍最近一層非箭頭函數決定

不能通過new關鍵字調用--因為箭頭函數沒有[[Construct]]

沒有原型--箭頭函數不存在prototype屬性

不可以改變this的綁定--函數內的this值不可被改變

不支持arguments對象--只能通過命名參數和不定參數來訪問函數中的參數

不支持重復的命名參數

當箭頭函數只有一個參數時,可以直接寫參數名,箭頭緊隨其后,箭頭右側的表達式被求值后便立即返回,即使沒有顯式的返回語句
如果要傳入兩個或兩個以上參數則需要在參數兩側添加一對小括號
如果函數沒有參數,也要在聲明時寫一組沒有內容的小括號

let sum = (num1, num2) => num1 + num2
//相當于
let sum = function (num1, num2) {
  return num1 + num2
}
尾調用優化

尾調用指的是函數作為另一個函數的最后一條語句被調用,其實也就是滿足以下三個條件

尾調用不訪問當前棧幀的變量--函數不是一個閉包

在函數內部,尾調用是最后一條語句

尾調用的結果作為函數值返回

ES6嚴格模式下,JS引擎才會進行尾調用自動優化

function f(x){
  return g(x);
}
function factorial(n) {
  if (n <= 1) {
    return 1
  } else {
    //無法優化,必須在返回后執行乘法操作
    return n * factorial(n - 1)
  }
}

function factorial(n, p = 1) {
  if (n <= 1)
    return 1 * p
  else {
    let result = n * p;
    //優化后
    return factorial(n - 1, result)
  }
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87363.html

相關文章

  • 深入理解ES6《用模塊封裝代碼》

    摘要:導入模塊的代碼執行后,實例化過的模塊被保存在內存中,只要另一個語句引用它就可以重復使用它和的一個重要的限制是它們必須在其它語句和函數之外使用,也就是說不允許出現在語句中,不能有條件導出或以任何方式動態導出。 什么是模塊 模塊是自動運行在嚴格模式下并且沒有辦法退出運行的Javascript代碼 在模塊的頂部this的值是undefined 其模塊不支持html風格的代碼注釋除非用def...

    BigTomato 評論0 收藏0
  • 深入理解ES6《用模塊封裝代碼》

    摘要:導入模塊的代碼執行后,實例化過的模塊被保存在內存中,只要另一個語句引用它就可以重復使用它和的一個重要的限制是它們必須在其它語句和函數之外使用,也就是說不允許出現在語句中,不能有條件導出或以任何方式動態導出。 什么是模塊 模塊是自動運行在嚴格模式下并且沒有辦法退出運行的Javascript代碼 在模塊的頂部this的值是undefined 其模塊不支持html風格的代碼注釋除非用def...

    AbnerMing 評論0 收藏0
  • 深入理解ES6《ES7》

    摘要:指數運算符是可以進行求冪運算的求冪運算符是兩個星號求冪運算符的優先級高于其它二元運算符,但是一元運算符的優先級高于求冪運算符求冪運算符左側的一元運算符只能是或者是語法錯誤可以這樣包裹也可以這樣包裹在中可通過方法來檢查給定字符串中是 指數運算符 Math.pow是可以進行求冪運算的求冪運算符是兩個星號 let result = 5 ** 2 console.log(result) //2...

    lx1036 評論0 收藏0
  • 深入理解ES6《ES7》

    摘要:指數運算符是可以進行求冪運算的求冪運算符是兩個星號求冪運算符的優先級高于其它二元運算符,但是一元運算符的優先級高于求冪運算符求冪運算符左側的一元運算符只能是或者是語法錯誤可以這樣包裹也可以這樣包裹在中可通過方法來檢查給定字符串中是 指數運算符 Math.pow是可以進行求冪運算的求冪運算符是兩個星號 let result = 5 ** 2 console.log(result) //2...

    xeblog 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<