函数首先是对象
函数是Function构造函数的实例,也就是说,如果我们把function当做对象用也是能够出发对象的优化机制的。
- prototype 指向 原型对象
- proto 指向 Function.prototype
声明式函数
function outer() {
let x = 10;
return function inner() { return x; }; // 闭包保留对x的引用
}
- 捕获当前的词法环境,形成闭包
- 通过作用域链访问外部元素直到顶部
- 函数的生命在执行前被提升到作用域顶部(hoisting)
函数提升
这里的提升其实是因为JS的执行过程分为:
声明 - 执行 - 回收
每一个作用域下都是先声明再回收
所以对于下面这种情况JS的执行顺序就会是:
myFunc(); // 正常执行
function myFunc() {}
- 声明 myFunc() 但是未赋值, 执行当前作用域,进入myFunc
- 声明 myFunc 作用域内容,执行 Func 作用域
- 还有一种说法是函数声明提升了函数定义和函数体,这样理解我认为也没有问题。
对于 var, 也是一样的,在声明阶段被声明,但是没有初始化,所以是 undefined
变量不提升
对于使用 let const 声明的变量,在执行到声明语句之前,都会处于暂时性死区。所以下面的函数声明方式不能提升:
myFunc()
// ReferenceError cannot access xx before initialization
let myFunc = function(){}
优先级
不同的声明方式之间有优先级:函数声明 > 变量声明
注意这里的优先级是值声明的时机优先级,而不是生效优先级
foo();
// TypeError: foo is not a function(表达式未提升函数体)
var foo = function() { console.log(1); };
function foo() { console.log(2); }
foo(); // 1(覆盖函数声明)
所以对于上面这种情况,function 声明的 foo 反而会被 var 声明覆盖,导致无法访问
构造式函数
let x = 10
const dynamicFunc = new Function('return x') // 不能访问到 10
使用 Function 解析字符串生成的变量只能在全局作用域中执行,但是可以使用 with(this)绑定到当前实例。Vue2就是这么做的
注意,使用 Function 解析字符串的开销是很大的
箭头函数
没有独立的this和arguments,没有prototype,不能作为构造函数使用
笔者才疏学浅,各位读者多多担待,不吝赐教。