这是我参与更文挑战的第11天,活动详情查看:更文挑战
原创声明
文章曾被多个网站转载,特此声明一下,图灵社区原文和掘金本文,均为本人创作,其余出处为他人转载。 本篇为学习《JavaScript DOM编程艺术》的学习笔记。
前言
在JavaScript引擎正式编译之前,会进行一次预编译,在这个过程中,会将变量声明及函数声明提升至当前作用域的最顶端,其后才进行接下来的处理。
变量提升
未使用块级作用域:
源代码:
console.log(msg);// undefined
var msg = "This is a message";
console.log(msg);// This is a message
function fn () {
console.log(hello); // undefined
var hello = 'hello world';
console.log(hello); // hello world
}
fn();
JavaScript解析器的解析流程:
var msg;// 变量提升,全局作用域范围内,此时只是声明,并没有赋值
console.log(msg);// undefined
msg = "This is a message";// 此时才赋值
console.log(msg);// 打印出This is a message
function fn () {
var hello;// 变量提升,函数作用域范围内,此时只是声明,并没有赋值
console.log(hello); // undefined
hello = 'hello world';// 此时才赋值
console.log(hello); // hello world
}
fn();
ES5只有全局作用域和函数作用域,而ES6开始提供了块级作用域。使用ES6语法的let创建的变量和const语法创建的常量,均不存在变量提升。
使用块级作用域:
console.log(msg);//Uncaught ReferenceErrord
let msg = "This is a message";//没有被执行
console.log(msg);//没有被执行
function fn () {
console.log(hello); //Uncaught ReferenceErrord
let hello = 'hello world'; //没有被执行
console.log(hello); //没有被执行
}
fn();
IIFE与块级作用域
一般的JavaScript函数有三种写法。
1.函数关键字,也叫函数声明语句写法
function foo(){}; foo();
2.函数字面量,也叫函数表达式写法
var foo = function(){}; foo();
3.funtion()构造函数
var foo = new function(): foo();
有时需要在定义函数之后,立即调用该函数。这种函数就叫做立即执行函数,全称为立即调用的函数表达式IIFE(Imdiately Invoked Function Expression)。 通过立即调用的函数表达式,能够实现块级作用域的效果。
JavaScript引擎规定,如果function关键字出现在行首,一律解释成函数声明语句,而且声明语句必须要有一个函数名。所以如下的代码demo会报错。
function () {}; //Uncaught SyntaxError: Unexpected token (
正确的写法是给函数声明语句提供一个函数名。
function foo() {}; //undefined
接下来将函数声明语句与JavaScript分组操作符进行组合,看上去这样的组合好像并没有什么意义,并且会抛出一个错误:
function foo() {} (); //Uncaught SyntaxError: Unexpected token )
错误在于JavaScript分组操作符需要指定一个值,不能为空。
正确的组合写法:
function foo() {} (0);//0
或
function foo() {}; (0); //0 两种写法等价。
这样也仅仅是实现了函数声明语句与不报错的分组操作符的组合。
所以需要将函数声明语句改成函数表达式写法,将function使用分组操作符进行组合。这样就不需要再指定一个函数名。这个表达式将会在加载网页时立即执行,而不需要单独调用函数。执行后,函数内代码块声明的变量将只在局部作用域内有效。无法被外层访问到。
(function () {} () );
或者
(function () {}) ();
在ECMAScript6中,由于块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
// IIFE 写法
(function () { var tmp = 0; }());
// 块级作用域写法
{ let tmp = 0; }
函数提升
函数提升与变量提升效果一致,但JavaScript只有函数声明语句才存在函数提升.
源代码:
console.log(msg1); // function msg1() {};
console.log(msg2); // undefined
function msg1() {}
var msg2 = function() {}
JavaScript解析器的解析流程:
function msg1() {}; // 函数提升,整个代码块提升到文件的最开始
console.log(msg1);
console.log(msg2);
var msg2 = function() {}
参考来源: