![3b960deb1c1ea2e6a65f428d07770a68.png](https://img-blog.csdnimg.cn/img_convert/3b960deb1c1ea2e6a65f428d07770a68.png)
首先要明白一个机制:
先声明,后赋值!!!
var
为什么会有这个机制?
这个要从内存角度去看:
变量是栈内存的 , 我们从栈内存,得到一块空间,我们把它的名字 命名为a (这就是 var a 做的事),无论这个空间里面放着什么,我们统统不要,把它换成 1 的二进制(a =1)
JS的弄巧成拙
以前程序员不懂内存,常常犯的问题就是: 用变量赋值之前却忘了声明
a = 1
b = 2
console.log(a+b)
这很明显会报错的!
但是js为了讨好程序员,搞了一个语法糖 : 你忘记声明了,没关系,我来帮你声明!
这种情况下,上述的代码就可以正常运行了,你好我好大家好! ( ps:都可以想到一个大胖子手里端着咖啡,得意的笑*^_^* )
但是问题很快就接踵而至了!
js引擎执行过程:
- 检查语法错误
- 看到你变量没有声明,那就自动帮你声明
- 构建词法树,确定作用域
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
- 运行代码,碰到函数嵌套,就利用callstack 来进行函数运行环境的切换
划重点了:所有末定义直接赋值的变量自动声明为拥有全局作用域!
那就造成了很多的问题:
- 全局作用域的命名空间,受到了巨大的污染(可能变量重名,可能被人乱改)
- 代码问题
var obj = {
sayHi:funciton(){
a = 1
console.log(a)
}
}
var a = 3
function fn(){
console.log(a)
}
obj.sayHi.call(obj)
fn.call()
------------------------------------------------------------------------------------
3 , 3
a=1 这里的a实际上是一个全局变量,被外面给修改成了3
在obj.sayHi()调用的哪一个瞬间,a已经改变了
那么如何解决这个问题呢
以前的程序员:
究竟是如何污染的呢?
function xx(){
var a = 1
console.log(a)
}
xx()
`再次分析这个代码:`
我们的本意,其实是想在 打印a,但是又不想把 a 暴露给全局, 因为可能有'重名',可能被人'乱改'!
所以,我们用函数作用域 , 也就是xx函数,包裹,这样有两个好处:
1.我什么时候想用,就什么时候用
2.a作为函数的属性,不会直接暴露给全局
`但是:`
这个问题还是没有得到彻底解决------>因为我们还是在全局里面暴露了一个属性 ---> 函数xx!
`进一步:`
如何解决函数暴露在全局的问题呢?
'函数自调用!'
格式:
;(
function (){
逻辑;
}()
)
我们写一个匿名函数,换句话说:'没有xx了' 自然也就不会暴露什么了
这个函数自己执行[后面跟了一个括号!]
最后在最外面套一层 (),解决语法报错问题!
最后加一个; 避免错误
这样太麻烦了,ES6就搞了一个let
let 的语法:
{
let a = 1
}
定义了一个a ,这个a,只在 花括号里面起作用!
这样,就彻底解决了,变量暴露在全局的问题!!!
如何做js的面试题目?
- 弄请js引擎的执行过程
- 画出词法树,注意末定义直接赋值的变量的变量提升
- 脑海中运行代码,根据不同的函数切换到不同的运行环境
- 搞清this是什么
- 搞清函数定义的时机和调用的时机
基本上所有的题目,都可以拿下了!