1. 函数名称要高于赋值变量的变量名
const test = function nameElse () {
console.log(11)
}
console.log(test.name) // nameElse
2. 通过使用 new.target 来判断函数是否使用了new进行调用
new.target
指向被new
调用的构造函数
function Person (name) {
if (new.target === Person) {
this.name = name
} else {
throw new Error("You must use new with Person.")
}
}
var person = new Person('zhoou')
console.log(person.name) // 'zhoou'
var person1 = Person('ss') // 抛出错误 You must use new wi th Person
3. 箭头函数
1. 没有 this 、 super 、 arguments ,也没有 new.target 绑定: this 、 super 、arguments 以及函数内部的 new.target 的值由所在的、最靠近的非箭头函数来决定
2. 不能被使用 new 调用: 箭头函数没有 [[Construct]] 方法,因此不能被用为构造函数,使用 new 调用箭头函数会抛出错误。
3. 没有原型: 既然不能对箭头函数使用 new ,那么它也不需要原型,也就是没有prototype 属性。
4. 不能更改 this : this 的值在函数内部不能被修改,在函数的整个生命周期内其值会保持不变。
5. 没有 arguments 对象: 既然箭头函数没有 arguments 绑定,你必须依赖于具名参数或剩余参数来访问函数的参数。
6. 不允许重复的具名参数: 箭头函数不允许拥有重复的具名参数,无论是否在严格模式下;而相对来说,传统函数只有在严格模式下才禁止这种重复
this指向:
一、普通函数中this
(1)总是代表着它的直接调用者,如obj.fn,fn里的最外层this就是指向obj (谁触发的这个函数 指向谁)匿名函数没有直接调用者,this指向window
(2)默认情况下,没有直接调用者,this指向window
(3)严格模式下(设置了'use strict'),this为undefined
(4)当使用call,apply,bind(ES5新增)绑定的,this指向绑定对象
let obj = {
id: 1233,
init: function () {
console.log(this) // obj
document.addEventListener('click', function () {
console.log(this) // document
this.getId()
}.apply(this)) // 改变this指向obj
},
getId() {
console.log(this.id) // 1233
}
}
obj.init()
二、ES6箭头函数中this
(1)默认指向定义它时,所处上下文的对象的this指向。即ES6箭头函数里this的指向就是上下文里对象this指向,偶尔没有上下文对象,this就指向window (如果箭头函数被包含在一个非箭头函数内,那么 this 值就会与该函数的this指向相等;否则,
this 值就会是全局对象)匿名函数指向window
(2)即使是call,apply,bind等方法也不能改变箭头函数this的指向
var id = 1233
function getId() {
console.log(this.id) // 1233
}
let obj = {
id: 1233,
init: () => {
console.log(this) // window
document.addEventListener('click', () => {
console.log(this) // window
this.getId()
})
}
}
obj.init()
例子:
var o = {
a: 10,
b: {
a: 12,
fn: function(){
console.log(this.a);
console.log(this);
}
}
}
var j = o.b.fn;
j();
执行j(), 不用看j()赋值成了啥,就看是谁调用的j,在这个例子里window调用的j(),this指向window
window.a 是 undefined ,this指向window
注意:构造函数里的this指的就是将要被new出来的新对象
var a = 1
function test (a) {
this.a = a // this指向b
}
var b = new test(2)
console.log(b.a) // 2
下一个:
var a = 1
var obj = {
a: 2,
testChildren: function () {
console.log(this) // obj
return () => {
console.log(this) // obj
}
}
}
obj.testChildren()
obj.testChildren()()
总结:
普通函数:谁调用它 ,谁触发它 this指向谁,否则指向window
箭头函数:指向外部包裹它的非箭头函数的this, 一层一层往上找,直到找到非箭头函数,否则指向window
匿名函数指向window
var obj = {
a: 2,
wrapper: function () {
console.log(this) // obj
return () => {
console.log(this) // obj
return () => {
console.log(this) // obj
}
}
}
}
obj.wrapper()()()
4. 尾调用
尾调用(tail call )指的是调用函数的语句是另一个函数的最后语句,就像这样:
function doSomething() {
return doSomethingElse(); // 尾调用
}
尾调用是指一个函数里的最后一个动作是返回一个函数的调用结果的情形,即最后一步新调用的返回值直接被当前函数的返回结果。此时,该尾部调用位置被称为尾位置。
此版本的函数并不会被优化,因为在递归调用 factorial() 之后还要执行乘法运算。如果
n 是一个大数字,那么调用栈的大小会增长,并且可能导致堆栈溢出。
优化:蹦床函数
调用栈的长度始终是1