We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
请写出以下代码的打印结果:
var name = 'Tom'; (function () { if (typeof name == 'undefined') { var name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
答案:Goodbye Jack
Goodbye Jack
立即调用函数表达式,也叫 IIFE ,顾名思义是一个在定义时就会立即执行的 JavaScript 函数,这样的设计模式也被成为 自执行匿名函数,常见于各种类库的封装,通过一对圆括号包裹一个匿名函数,在声明后立即调用, 为什么会有这样的一种设计模式?
自执行匿名函数
(function () {})(); // 一对圆括号包裹的一个匿名函数
IIFE 的出现更像是在弥补 JavaScript 语言在 访问控制 设计上的不足,相较于其他大部分面向对象的语言,直到 ES6 之前,JavaScript 只有 全局作用域 和 函数作用域,没有 块级作用域 。也就是说,在 JavaScript 中,你只能通过函数实现 作用域隔离。IIFE 以一种较优雅的方式,通过函数作用域模拟实现了 块级作用域,由于匿名函数拥有自己独立的词法作用域,不仅避免了外界访问 IIFE 中的变量,而且也不会污染全局作用域。
访问控制
ES6
全局作用域
函数作用域
块级作用域
作用域隔离
此外,IIFE 还有以下优点:
变量提升(Hoisting)被认为是,JavaScript 中执行上下文工作方式的一种认识,单从概览来理解比较晦涩,简单来说,就是指声明的变量和函数在编译阶段被放入内存中。
什么是执行上下文?
JavaScript 引擎遇到可执行代码(executable code)时,会创建执行环境,执行上下文(execution context)可以理解为当前执行代码的环境 / 作用域。
执行上下文(execution context)
可执行代码的类型只有三种:
对应的执行上下文也有三种:
一段可执行代码中可能有多个执行上下文,每个函数执行时都会创建一个执行上下文,为了管理执行上下文,JavaScript 引擎还会创建 执行上下文栈(execution context stack),执行栈本质上就是一个普通的栈,只是它里面存放的是执行上下文。
执行上下文栈(execution context stack)
回到变量提升,怎么去理解 声明的变量和函数在编译阶段被放入内存中 ?
声明的变量和函数在编译阶段被放入内存中
JavaScript 引擎在正式执行代码前,会进行一次"预编译",在内存中开辟一些空间,用来存放变量和函数,具体的步骤如下:
可以看出,JavaScript 引擎仅提升声明,而不会提升初始化,所以如果先使用变量,再声明初始化它,变量的值将会是 undefined:
console.log(foo); // undefined var foo = 'foo';
上面的代码相当于:
var foo; console.log(foo); foo = 'foo';
此外,函数和变量相比,会被优先提升,与声明的先后顺序无关:
console.log(foo) // ƒ foo () {} var foo = 'foo' function foo () {}
对于每一个执行上下文,有三个重要的属性:
什么是作用域链
JavaScript 引擎在查找变量时,会先从当前执行上下文的变量对象中去找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中去找,一直找到全局上下文的变量对象,也就是全局对象,由多个执行上下文的变量对象构成的一个链表就叫作用域链。
也就是说,作用域链查找是从作用域链最底层开始查找,当遇到同名变量时,查找到的是距离当前执行上下文最近的变量:
var name = 'Tom' function () { var name = 'Jack' console.log(name) // Jack }
回到我们刚开始的题目,由于变量提升,上述的代码相当于:
var name = 'Tom'; (function () { var name if (typeof name == 'undefined') { name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
匿名函数内的变量 name 被提升至当前执行上下文(匿名函数)的最顶端,由于仅提升声明,不提示初始化,所以 name 的初始值为 undefined
name
undefined
执行 typeof name 会查找 “name” 这个变量,通过作用域链查找,发现当前匿名函数的执行上下文就有 name,所以这里的 typeof 相当于:
typeof undefined
需要注意的是 typeof 返回的值是字符串,所以最终打印结果为 Goodbye Jack
typeof
面试题解JavaScript(二): new 的实现原理是什么
如果有疑问或者发现错误,可以在相应的 issues 进行提问或勘误
如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励
(完)
The text was updated successfully, but these errors were encountered:
No branches or pull requests
请写出以下代码的打印结果:
答案:
Goodbye Jack
立即调用函数表达式
立即调用函数表达式,也叫 IIFE ,顾名思义是一个在定义时就会立即执行的 JavaScript 函数,这样的设计模式也被成为
自执行匿名函数
,常见于各种类库的封装,通过一对圆括号包裹一个匿名函数,在声明后立即调用, 为什么会有这样的一种设计模式?IIFE 的出现更像是在弥补 JavaScript 语言在
访问控制
设计上的不足,相较于其他大部分面向对象的语言,直到ES6
之前,JavaScript 只有全局作用域
和函数作用域
,没有块级作用域
。也就是说,在 JavaScript 中,你只能通过函数实现作用域隔离
。IIFE 以一种较优雅的方式,通过函数作用域模拟实现了块级作用域
,由于匿名函数拥有自己独立的词法作用域,不仅避免了外界访问 IIFE 中的变量,而且也不会污染全局作用域。此外,IIFE 还有以下优点:
变量提升
变量提升(Hoisting)被认为是,JavaScript 中执行上下文工作方式的一种认识,单从概览来理解比较晦涩,简单来说,就是指声明的变量和函数在编译阶段被放入内存中。
JavaScript 引擎遇到可执行代码(executable code)时,会创建执行环境,
执行上下文(execution context)
可以理解为当前执行代码的环境 / 作用域。可执行代码的类型只有三种:
对应的执行上下文也有三种:
一段可执行代码中可能有多个执行上下文,每个函数执行时都会创建一个执行上下文,为了管理执行上下文,JavaScript 引擎还会创建
执行上下文栈(execution context stack)
,执行栈本质上就是一个普通的栈,只是它里面存放的是执行上下文。回到变量提升,怎么去理解
声明的变量和函数在编译阶段被放入内存中
?JavaScript 引擎在正式执行代码前,会进行一次"预编译",在内存中开辟一些空间,用来存放变量和函数,具体的步骤如下:
可以看出,JavaScript 引擎仅提升声明,而不会提升初始化,所以如果先使用变量,再声明初始化它,变量的值将会是 undefined:
上面的代码相当于:
此外,函数和变量相比,会被优先提升,与声明的先后顺序无关:
作用域链查找
对于每一个执行上下文,有三个重要的属性:
JavaScript 引擎在查找变量时,会先从当前执行上下文的变量对象中去找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中去找,一直找到全局上下文的变量对象,也就是全局对象,由多个执行上下文的变量对象构成的一个链表就叫作用域链。
也就是说,作用域链查找是从作用域链最底层开始查找,当遇到同名变量时,查找到的是距离当前执行上下文最近的变量:
解析
回到我们刚开始的题目,由于变量提升,上述的代码相当于:
匿名函数内的变量
name
被提升至当前执行上下文(匿名函数)的最顶端,由于仅提升声明,不提示初始化,所以name
的初始值为undefined
执行 typeof name 会查找 “name” 这个变量,通过作用域链查找,发现当前匿名函数的执行上下文就有 name,所以这里的 typeof 相当于:
需要注意的是
typeof
返回的值是字符串,所以最终打印结果为Goodbye Jack
下一篇文章
面试题解JavaScript(二): new 的实现原理是什么
勘误与提问
如果有疑问或者发现错误,可以在相应的 issues 进行提问或勘误
如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励
(完)
The text was updated successfully, but these errors were encountered: