该部分常见面试题目
// ------------------
console.log(a)
a = '林一一'
function fn(){
console.log(a)
a = 12
}
fn()
console.log(a)
// 输出 Uncaught ReferenceError: a is not defined
// ------------------------
var a = '林一一'
function fn(){
if(!a){
var a = 12
}
console.log(a)
}
fn()
// 输出 12
// var a = 12 会变量提升 所以 !a = true; var a = 12 执行了
// -------------------
var a=12, b = 13, c = 14
function fn(a){
a = 0
var b = 0
c = 0
}
fn(a)
console.log(a)
console.log(b)
console.log(c)
// 输出 12 13 14
// a 为形参 b为局部变量 所以不会改变全局变量的值 c改变了全局变量的值
基础概念
作用域:作用域就是变量的访问的范围和权限,变量在哪个范围内可以访问到,这个范围就是他的作用域。全局下可以访问到就是全局作用域,仅函数内部可以访问到作用域就是函数体内。es6引入块级作用域。
变量提升:函数和使用var声明的变量,无论代码中在哪里定义该变量,都会被提升到作用域的顶部声明。在之前使用并不会报错。
核心原理
作用域:每个函数都有[[scope]]属性,指向的是当前函数的执行上下文集合。
作用域链:[[scope]]属性指向的执行上下文集合就是我们所说的作用域链
看一个函数的[[scope]]
简单的分析:
function test() {
var a = 'a'
}
var glob = 'global'
test()
当函数声明的时候,[[scope]]
中只有全局一个作用域,表示函数在这个范围内可访问。
但是当test函数被调用的时候就形成了作用域链了,存在[[scope]]
集合中
变量提升:
js在执行代码过程中,会有编译和执行2个阶段。
其中编译阶段并不是把所有代码拿过来一起编译,而是执行一部分代码则编译一部分代码。
但是由于这个短暂的编译过程,js引擎会收集所有的变量进行声明,并让所有的变量生效。剩下的语句则需要等到执行阶段执行到某一句的时候才会具体生效。
用来做什么的
- 用作划分变量访问范围,变量在哪些地方有访问权限
- 可以用作闭包
优缺点
作用域:
优点:
- 让变量有自己的访问范围,让代码更加灵活
- 作用域链的机制可以实现继承
- 保护自己作用域的变量,与其他作用域的变量隔离
缺点:
1. es5只有函数和全局作用域,循环和部分代码块中无作用域
面试点分析
console.log(a)
a = '林一一'
function fn(){
console.log(a)
a = 12
}
fn()
console.log(a)
输出 Uncaught ReferenceError: a is not defined
变量a并无var声明为全局变量,不会提前声明,所以第一句console.log(a)会报错,后面代码都不会执行。
var a = '林一一'
function fn(){
if(!a){
var a = 12
}
console.log(a)
}
fn()
// 输出 12
// var a = 12 会变量提升 所以 !a = true; var a = 12 执行了
输出 12. 执行fn()时,if语句里面的var不管执不执行,var a = 12都会提前声明。
即 if(!a) 中a 为undefined,所以经过if语句以后 a为局部变量 打印出12
var a=12, b = 13, c = 14
function fn(a){
a = 0
var b = 0
c = 0
}
fn(a)
console.log(a)
console.log(b)
console.log(c)
// 输出 12 13 0
// a 为形参 b为局部变量 所以不会改变全局变量的值 c改变了全局变量的值
此体主要考察,函数调用的时候覆盖了哪些全局变量。
当调用fn时,全局的a作为形参传入函数,b用var声明即作为局部变量。
只有c是直接改变了全局的c。所以会打印出 12 13 0
拓展
闭包:函数作用域内的变量都是私有变量,函数外部是访问不到的,但是通过某种手段访问到该函数内部变量就形成了闭包。
当函数内部return 返回的函数被其他作用域引用的时候,该函数内部的私有变量不会被垃圾回收机制回收
由于垃圾回收机制不会回收,会导致内存消耗。
惰性函数、柯里化函数、compose函数都是用了闭包机制。