天天都在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.
发现错误,欢迎在评论里指出😆。