美文网首页
函数声明提升

函数声明提升

作者: butterflyq | 来源:发表于2017-02-06 13:52 被阅读0次

来源:https://dancon.gitbooks.io/git-books/content/js/essay/function_hoisting.html 

在ES5 中存在这样的事实,变量声明提升,函数声明提升。 在抛出这篇文章要讨论的问题之前,我们先来解释下这两个概念。

变量声明提升: 通过var声明的变量在代码执行之前被js引擎提升到了当前作用域的顶部。

函数声明提升: 通过函数声明的方式(非函数表达式)声明的函数在代码执行之前被js引擎提升到了当前作用域的顶部,而且函数声明提升优先于变量声明提升。

示例代码

1. js中变量没有声明就直接使用,是会导致引用错误的,如下:

console.log(a);

运行结果:

Uncaught ReferenceError: a is not defined(…)

2. 变量声明提升

console.log(a);

var a = 1;

运行结果:

undefined

没有报错,而是输出了undefined, 说明变量声明var a被提升到了作用域的顶部,console.log进行RHS引用时找到了变量a, 所以没有报错。

3. 函数声明提升

a();

function a() {

console.log('This is a function body');

}

运行结果:

This is a function body

函数的调用发生在函数声明之前,但是依旧正常执行。其实真正的函数声明只包含如下部分:

function () {

console.log('This is a function body');

}

这部分执行的结果就是创建了一个函数对象,我们假设为funcObj。

a只是指向funcObj的指针,函数声明提升,提升的应该是创建funcObj的过程,也就是上述的代码块。

在一些引擎的实现中,a也会赋值给funcObj对象上的一个name属性。 比如 a.name 会输出 a

4. 函数声明提升优于变量声明提升

a();

var a;

function a() {

console.log(1);

}

a = function() {

console.log(2);

}

a();

运行结果:

1

2

上述代码会被js引擎解析为如下:

function a() {

console.log(1);

}

a();

a = function() {

console.log(2);

}

a();

var a ;属于重复声明,被忽略掉了。然而后续的函数声明还是会覆盖之前的函数声明。如下:

a();

var a;

function a() {

console.log(1);

}

a = function() {

console.log(2);

}

function a() {

console.log(3);

}

运行结果:

3

所以得出如下猜想:

函数声明提升其实做了两个提升动作:

函数名变量提升,类似变量声明function a();

函数定义提升{ /*function body*/ }.

也就是说通过函数声明的方式定义一个函数会有以下三个步骤(或者说两个也可以,第三个可以归并到第二步中)(YY而已,不要当真):

声明函数名变量a

创建函数对象funcObj

把函数名变量a指向函数对象funcObj

而一般的函数声明提升会把这三个步骤都提升到作用域的顶部。

一般的函数声明提升的结果如上所述,那不一般的函数声明提升又会是什么样的呢?

问题如下:在chrome 49, FF 46, IE 11中运行如下代码都得出类似结果

(function(){

console.log(a);

if(false){

console.log(a());

function a(){

console.log('true');

}

}

a();

})();

chrome运行结果:

undefined

Uncaught TypeError: a is not a function

奇怪吧?!函数提升发生在所有代码执行之前,所以,尽管a 的定义过程写在了 if 分支中,但是理论上或者说ES6之前, 它是不会影响函数声明提升的,而现在,在作用域顶部console.log(a)输出undefined, 而执行a()发生TypeError。 我们稍作如下修改:

(function(){

console.log(a);

if(true){

console.log(a());

function a(){

console.log('true');

}

}

a();

})();

chrome运行结果:

undefined

true

true

再做一次修改:

(function(){

'use strict';

if(true){

console.log(a());

function a(){

console.log('true');

}

}

console.log(a);

})();

chrome运行结果:

true

Uncaught ReferenceError: a is not defined

现代浏览器的JS引擎已经支持块作用域了, 只是在非严格模式下,只有函数名变量声明会提升到当前闭包的顶部,这也是不管if 分支是否成立,在它之前console.log(a)都会输出undefined的原因。 而函数定义提升只提升到了if 的块作用域内,这就是在if 为真时,在if块内且在函数声明之前console.log(a())会输出true的原因。 但是在严格模式下, 函数名变量的提升也只提升到了if 块的顶部。这就是在严格模式下,在if 块外部对a 进行RHS引用是报 TypeError 的原因。

+

注意

在ES5中,严格模式下,函数的声明只能在全局作用域或者函数内,其他块(if, for)都会报错。

// 如下代码ES5中都会报错

if(1){

function a() {……} // 报错,ES6中不报错,是因为ES6支持了块作用域,所以在块作用域中声明函数是合理的。

}

相关文章

  • 引用类型

    变量提升和函数声明提升   函数声明提升就是把函数声明提升到函数声明所在作用域中(或者说一个函数体内)的顶端,变量...

  • JavaScript 函数声明与函数表达式的区别

    函数声明 存在函数提升(同比于变量提升) 函数声明在JS解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪...

  • JS中创建函数的几种方式

    1.使用 "函数声明" 创建函数函数声明具有函数声明提升的特点,将函数声明提升到作用域顶端,意思是在执行代码之前会...

  • js原生

    三种定义函数的方式 变量声明提升 在函数体内部,声明变量,会把该声明提升到函数体的最顶端。 只提升变量声明,不赋值...

  • 函数声明提升

    引用

  • 函数声明提升

    来源:https://dancon.gitbooks.io/git-books/content/js/essay/...

  • 《JavaScript高级程序设计》读书笔记-第七章(函数表达式

    函数 函数提升 函数声明提升执行代码之前会先读取函数声明。意思是可以把函数声明放到调用它的语句后面 函数表达式 这...

  • 函数表达式和函数声明

    定义函数两种方式:A(函数声明)、 B(函数表达式)A:函数声明方式定义函数:函数声明的重要特性:函数声明提升。...

  • 函数与作用域

    函数声明和函数表达式有什么区别 函数声明会提升到当前作用于执行之前;而函数表达式提升的声明是变量的声明。 函数声明...

  • 猫眼

    var变量提升,函数声明提升,消除变量声明提升(let); 高阶函数,函数式的编程,柯里化 原型链继承,js面向对...

网友评论

      本文标题:函数声明提升

      本文链接:https://www.haomeiwen.com/subject/mjzyittx.html