天天都在codeing,可是若是沒有總結的話,根本記不住。之後按期寫文章,無論有沒有人看都會有必定的收穫。git
個人GitHub,歡迎stargithub
使用了默認參數的函數,會自動啓用ES6面試
function fn(a, b = 1) { } fn(1)
不傳或者手動傳遞undefined都會使用默認的參數。閉包
除此以外,和正常的ES5
還有一些區別:app
let
聲明的同樣(意味着存在TDZ
)ES6
,因此當前scope
都是處於strict
模式下的。形參列表裏的參數的scope
和函數體內的scope
是兩個scope
(書上是這麼說的,可是他媽的若是是兩個scope
,那我從新用let
聲明爲何還報錯?幹!因此我以爲應該只是說形參列表的默認參數不能使用函數做用域內部的變量,但仍是屬於同一個scope
,由於相似的for
循環,括號裏和花括號裏是兩個scope
我就能用let
重複聲明)
記住一點,嚴格模式下arguments
只和傳入的實參同樣,並且不保證同步。函數
因此一旦使用了默認參數,就說明要麼是沒傳,要麼是傳了undefined
。那arguments
裏就確定沒有默認參數了。優化
function fn(a, b = 1) { console.log(arguments[0] === a) // true console.log(arguments[1] === b) // false } fn(1)
function fn(a, ...args) { }
使用限制:ui
setter
中,由於setter
的參數只能有一個value
,在不定參數的定義中是能夠有無限多。這二者在當前上下文中不容許一些注意的點:this
arguments
中只存儲傳入的參數fn.length
則是命名參數的個數,也就是說fn
的length
屬性是不包括args
中的東東的其實在ES4
的草案中,arguments
對象是會被不定參數給幹掉的,不過ES4
擱置之後,等到ES6
出來,它很ES4
的區別是保留了arguments
對象
在非嚴格模式下,arguments
對象和實參保持同步:prototype
function fn(a, b) { console.log(a === arguments[0]) a = 'hehe' console.log(a === arguments[1]) } fn(1, 2)
結果都是true
之因此給實參加粗,是由於即便保持同步,也只是和傳入的參數保持一致,好比我若是沒有傳入b
,而後我修改了b
,這個時候arguments[0]
和b
是不一致的。
可是在嚴格模式下,arguments
和參數則不會保持同步。
與普通函數的區別:
new.target、this、arguments、super
,這些東西都是最近一層非箭頭函數的東西.(因此,一旦不存在這樣的函數,可是在箭頭函數中訪問了這些keyword
就會拋出錯誤)new
調用,沒有[[construct]]
內部方法prototype
屬性arguments
,因此參數只能經過命名參數和不定參數來訪問yield
關鍵字,因此也就不能當作generator
函數咯注意,可否被用做constructor
和其有無prototype
屬性無關
就算用call、apply、bind
這樣的方法,也無法改變箭頭函數的this
。不過經過bind
能夠傳遞參數卻是真的
name
屬性是爲了更好地辨別函數:
function fn() {} // fn const a = function() {} // a const b = fn // fn const c = a // a const d = function hehe() {} // hehe
註釋就是對應函數的name
。仔細觀察很容易發現,若是函數是使用函數聲明建立的,那name
就是function
關鍵字後的string。若是是使用賦值語句建立的,那name
就是對應的變量名。並且一旦function.name
肯定下來,後續賦值給其餘變量也不會改變。其中function
聲明比賦值語句的優先級高。
特殊狀況:
const obj = { get name() { }, hehe() { } } console.log(obj.name) // 書上說是 get name,可是我親測是undefined啊 console.log(obj.hehe) // hehe
另外bind
出來的函數,name
帶有bound
前綴;經過Function
建立的函數帶有anonymous
函數的name
屬性不必定同步於引用變量,只是一個協助調試用的額外信息而已,因此不要使用name
屬性來獲取函數的引用
節流就是等到你不觸發了我在執行:
function debounce(fn, time, immediate = false) { let clear return function(...args) { if (immediate) { immediate = false fn(...args) return } if (clear) { clearTimeout(clear) } clear = setTimeout(() => { fn(...args) clear = 0 }, time) } }
防抖就是不管你觸發多少次,我只在規定的時間裏觸發一次
function throttle(fn, time, immediate = false) { let clear let prev = 0 return function(...args) { if (immediate) { immediate = false fn(...args) return } if (!clear && Date.now() - prev >= time) { prev = Date.now() clear = setTimeout(() => { fn(...args) clear = 0 prev = 0 }, time) } } }
尾調用就是函數做爲另外一個函數的最後一條語句被調用。
在ES5
中,尾調用的實現和普通的函數調用同樣,都是建立一個新的stack frame
,將其push
到調用棧,來表示函數調用,若是在循環調用中,調用棧的大小過大就會爆棧。
而尾遞歸優化呢,指的就是不在建立新的stack frame
,而是清除掉當前的stack frame
,而後重用便可。這樣,尾遞歸的時候,整個調用棧的大小就不會變了,達到了優化的效果。
如下狀況會優化:
stack frame
的變量。也就是說函數不能是一個閉包function fn1() { // 其餘語句 return fn2() }
JavaScript
函數中有兩個內部方法:[[call]]
和[[construct]]
。經過new
來調用函數的時候執行的是construct
內部方法,而正常調用則執行call
內部方法。
instance
,而後執行函數體。當使用new
調用函數的時候,new.target
被賦值爲new操做符的目標,一般就是被new調用的構造函數。因此若是須要判斷函數是否被new調用,則只須要查看new.target
是否爲undefined
便可具備[[construct]]
內部方法的函數被統稱爲構造函數。不是全部的函數都是構造函數,因此不是全部的函數都可以被new
調用(好比箭頭函數)。這個具體細節看下文。
JS
目前具備三種類型的function object
:
ECMAScript Function Object
:全部經過JS語言生成的function object
都是ECMAScript Function Object
;Built-in Function
:引擎內置的全部function object
若是沒有實現爲ECMAScript Function Object
,必須實現爲此處的Built-in Function Object
;Bound Function
:Function.prototype.bind
生成的function object
爲<u>Bound Function Object</u>,調用<u>Bound Function Object</u>會致使調用綁定的<u>bound target function</u>;ES6
標準指出,函數內部都有兩個方法:[[call]] [[construct]]
。前者是普通調用,後者是new
調用。
而即使都是new
調用,built in
和 普通的 function object
仍是有所差異:
new operator
做用於ECMAScript Function Object
會根據當前function object
的prototype
屬性生成一個新的對象,並將其做爲this
傳入function object
進行調用;new operator
做用於Built-in Function Object
的時候不會生成一個新的對象做爲this
傳入當前的function object
,而是由當前的function object
在function call
的時候本身生成一個新的對象。常常看到面試題問new operator
執行了哪些操做,而後就開始巴拉巴拉:根據原型生成一個新的對象,而後將新的對象做爲this調用函數,最後根據函數的返回值是否爲對象來判斷應該返回什麼。。。(心中千萬只草泥馬飄過);固然,若是要用JS
來模擬new operator
那隻能按照這個流程搞,頂多再用上new.target
。
之前一直覺得全部js
函數都有prototype
,直到最近才發現不是。
除非在特定函數的描述中另有指定,不然不是構造函數的內置函數不具備原型屬性。
也就是說,js
的一些內置函數原本就沒打算用做constructor
,也就沒有添加[[construct]] internal-method
。可是反過來不必定成立,由於有的構造函數沒有prototype
,但它仍然是一個構造函數,好比:
console.log(Proxy.prototype); // undefined // 可是能夠經過new Proxy(args)來建立對象
按照規範,若是一個function-object
既具備prototype
屬性,又具備[[construct]] internal-method
,那麼它就是一個constructor
,此時該function-object
承擔着creates and initializes objects
的責任;
但Proxy constructor
爲何沒有prototype
屬性呢?雖然constructor
用於 creates and initializes objects
,但若是生成的對象的[[prototype]]
屬性不須要constructor
的prototype
屬性初始化,那麼constructor
的prototype
就沒有存在的必要。
也就是說,大部分狀況下只要某個function
有prototype
屬性,同時又具備[[constructor]]
,那這個function
就是一個constructor
。
可是某些特殊狀況下也會有例外,即:它不承擔建立對象而且初始化。可是因爲某些緣由它又同時具有了上述條件。
這是規範中指出的,目前尚未在built-in function
中發現過這種特例。不過在function object
中有兩個特例。
generator
不是 constructor
,可是同時具有 prototype
經過 bind
生成的bound function
是沒有 prototype
屬性,不過它仍然能夠看成一個 constructor
。
綜上所述,明確瞭如下幾點:
[[construct]]
prototype
屬性prototype
屬性和函數是否爲構造函數無關,只要有[[construct]]
屬性就是構造函數new
調用,好比Symbol
一個function object
能夠用new
調用的條件是什麼?
也就是說,是否能夠用new
方式調用,和函數是否是構造函數沒有關係,有沒有prototype
也不要緊,只要函數對象上具備內部的[[construct]]
,而且函數自己是容許new
調用的,就能夠經過new
來調用該function
。
function
聲明是存在塊級做用域的。不過在當前的scope
中不存在TDZ
。非嚴格模式下則不存在塊級做用域的特性,會直接提高至頂層做用域if (true) { function a() {} } console.log(a) // undefined
[[HomeObject]]
屬性,對象的方法有,可是普通的函數則沒有。通常狀況下都不會有什麼區別,可是在使用super
的時候會有區別const proto = { method() { return 'this is a method on proto' } } const obj = Object.setPrototypeOf({ test() { console.log(super.method()) } }, proto) obj.test() // this is a method on proto const obj = Object.setPrototypeOf({}, proto) obj.test = function() { super.method() // 語法錯誤 } obj.test()
個人GitHub,歡迎star.
發現錯誤,歡迎在評論裏指出😆。