欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基础——重中之重之JS的变量的声明

程序员文章站 2022-05-26 14:19:31
基础——重中之重之js的变量的声明 在现在这个浮躁的前端圈,人们盲目学着所谓火热的框架,都多多少少疏忽了基础,但任其框架万变,都万变不离其宗—...

基础——重中之重之js的变量的声明

在现在这个浮躁的前端圈,人们盲目学着所谓火热的框架,都多多少少疏忽了基础,但任其框架万变,都万变不离其宗——js尔。

本系列课程着重讲解js中基础,一些容易忽略的知识。

js的变量声明

说起变量声明大家都是十分熟悉的,在js声明一个新变量可以用var,const或者let, 他们属于js里面的操作符,接下来我们来依次聊一下他们

0.无操作符的情况

在js里面也是支持直接把变量直接赋值不需要声明的,如:

a = 1;
console.log(a); // 1
console.log(window.a) // 1

这种情况,会创建一个全局变量, 在严格模式(严格模式是es5出的, ie10之前不支持)下会报错,项目中极其不推荐这样做,很容易导致变量覆盖引发不可预知的bug,
目前前端的ide多数会自动检测(如webstorm),给予一个弱警告,推荐配置eslint

1.var

js是弱类型语言,var声明的变量无需指定类型, 也可以只声明不赋值,如果只声明会保存一个特殊的值——undefined,如下:

var a;
console.log(a === undefined); // true
提升

var声明变量会导致提升情况, 如下面的代码

console.log(a === undefined); // true
var a;
console.log(b === undefined); //uncaught referenceerror: b is not defined

变量提升是js引擎解释执行代码前所做的工作,或者说js编译时,顺便提一下,在《你不知道的javascript上卷》1.1节中,作者有提到js是编译语言,并给出了解释,
尽管我们把js归为“动态”和“解释执行”的语言,有兴趣的可以去看一下。下面再给出两个例子

//eg.1
a = 1;
var a;
console.log(a); // 1;

如果从直觉上看,认为js执行时是由上而下一行一行执行力的, 我们会认为结果是undefined,再看一个例子

//eg.2
console.log(a);
var a = 1;

你猜结果如何? referenceerror或者是1? 结果其实undefined。
当你看到var a = 1可能认为这是一个声明, 对于js而言, 其实是两个步骤, 声明var a和赋值a = 1,但第一步在编译阶段进行的。
所以上面两个例子的处理流程为

var a;
a = 1;
console.log(a);
var a;
console.log(a);
a = 1;
全局作用域下声明变量会绑定在全局对象上(window)

未测试node.js

var a = 1;
console.log(window.a); // 1;

顺便提一下, 带有id的dom元素为将其绑定在window上,key为id,如


 

<script > console.log(window.testid === document.getelementbyid('testid')); // true </script>

2.let

let是var的兄弟,在es6中引入的新关键字,把变量隐式地劫持在了其作用域(通常是{...}中),如:

if (true) {
    let a = 1;
}
console.log(a); // referenceerror
let循环

for循环是let发挥优势的典型例子, 这里相对于var减少了副作用,如:

for (var i = 0; i < 10; i++) {
}
console.log(i); // 10

for (let j = 0; j < 10; j++) {
}
console.log(j); // referenceerror
let不存在var一样的变量提升

这个特性是需要稍微注意的

console.log(a); //referenceerror
let a = 1;
typeof 不再是绝对安全的操作

以前我们判断一个变量存不存在会用到 typeof, 因为即使变量不存在也不会报错, 但如果用了let就不一样了, 如:

console.log(typeof a); // undefined
console.log(typeof b); //uncaught referenceerror: b is not defined
let b;

这个属于暂时性死区(tdz), 即只要进入当前块级作用域,所使用的变量已经存在了,但在声明之前都属于死区,不可进行操作。

全局作用域下声明变量不会绑定在全局对象上(window)
let a = 1;
console.log(window.a); // undefined;

3.const

const也是es6引入的新关键词, 它除了拥有let上面介绍的特性外,还有两条特性:

1.const声明的变量是不可修改的。
2.const声明的变量必须是其作用域内未定义过的

const a = 1;
a = 2; //uncaught typeerror: assignment to constant variable.
var a = 1;
const a = 2; //uncaught syntaxerror: identifier 'a' has already been declared

关于项目中使用

目前国内的占比还是不能肆意妄为的使用es6的特性的, 不过有类似babel之类的转换器,可以让我们写代码时可以用es6的一些新特性,兼容问题交给转换器来做。
不过我们要明白一点,转换器不是真正意义上的做到完美,他能做得是一些语法糖的兼容,js引擎的跨度不是全都能由代码补丁解决的,举个例子,es5新增对象属性劫持
是没办法在ie8以下实现的,(ps:司徒正美用ie独自支持的vbscript在avalon.js中实现了, vbscript不算js)。
如果项目中配了babel,只是让我们的代码更规范,减少错误,我们代码中的用到的let,const在babel中都会变成var, 类似这样的语法糖兼容起来要么是无法做到的,
要么兼容起来需要极大量代码的,最后折中处理了。
这里说一个在不支持let的环境里模拟其作用域特性的代码

// 模拟 let a = 1;
try {
    throw 1;
} catch (a) {
    console.log(a); // 1
}
console.log(a); // uncaught referenceerror: a is not defined

代价就是这么大, ┑( ̄д  ̄)┍