let 和 var 的区别?
- let不存在变量提升
- let不允许重复声明
- let会产生块级作用域
- 暂时性死区的问题
变量提升
在当前上下文代码自上而下执行之前,会把所有带var/function关键字的进行提前的声明或者定义
- 带var是只声明
- 带function是声明+定义(赋值)都完成了
重复声明
重复声明的检测和报错,是发生在词法解析阶段
暂时性死区(浏览器的BUG)
typeof 检测一个未被声明的变量不会报错,结果是undefined
这个bug的应用
检测js的运行环境,判断是node环境还是浏览器环境,便于实现对应模块化
typeof window !== "undefined"
jQuery源码
// 利用闭包的保护作用:自己编写的代码(类库或者插件)为了防止和外界的变量造成污染,需要放到闭包中
(function (global, factory) {
// 在浏览器中运行代码:global=window
// 在NODE中运行代码:global=global/module
// factory === anonymous
"use strict"; //=>采用JS严格模式(默认是非严格模式)
if (typeof module === "object" && typeof module.exports === "object") {
// NODE环境下执行(CommonJS模块规范)
// ...
module.exports = factory(global, true);
} else {
// 浏览器环境 anonymous(window)
factory(global);
}
})(typeof window !== "undefined" ? window : this, function anonymous(window, noGlobal) {
//【浏览器环境】 window=window noGlobal=undefined
//【NODE环境下】 window=global noGlobal=true
var jQuery = function (selector, context) {
// ...
};
if (typeof noGlobal === "undefined") {
// 把闭包中私有的东西暴露到全局上使用
window.jQuery = window.$ = jQuery;
}
return jQuery;
});
块级作用域
如果当前代码块中出现了let/const/function
则会在当前代码块中产生一个块级上下文
for var 循环 每个 i 都是全局的
for (var i = 0; i < 5; i++) {}
for let i 循环 每个i都是单独块级作用域中私有的
for (let i = 0; i < 5; i++) {}
并且会产生6个块级作用域,有一个是控制循环的父级作用域
浏览器对ES3和ES6的兼容
在块级作用域中如果存在var 或 function 浏览器为了兼容性会做出以下处理
- 块级作用域中,var或者function声明的变量会映射给全局一份,注意function只会映射声明
console.log(window.a, window.b)
{
console.log(a, b)
var a = 1
function b() {};
}
- 块级作用域中,function声明之前的代码会映射一份给全局上下文的foo中
{
function foo() {} // 映射给全局声明
foo = 1;
}
console.log(foo); // function foo()
{
function foo() {}
foo = 1;
function foo() {} // 最后一个声明之前的代码映射给全局,foo = 1
}
console.log(foo); // 1
- function 之后的代码不再对全局 a 操作,被认为是私有的le
验证
{
function foo() {}
foo = 1;
function foo() {}
foo = 2;
}
console.log(foo); // 1