Javascript变量声明与变量赋值和变量提升详解

2272 4 年前
变量是对“值”的具名引用。变量就是为“值”起名,然后引用这个名字,就等同于引用这个值。变量的名字就是变量名。

ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。

声明变量

声明变量使用 var 操作符(var是一个关键字),后跟变量名(标识符)。var 操作符定义的变量将成为定义该变量的作用域中的局部变量,关于作用域后续我们再介绍。

var message;

在ES6里,声明变量还可以用let和const。

let message;
const valuea = 10;

在同一作用域内使用var 声明的变量重复声明不会报错,视后面的声明无意义(声明后有赋值的话会赋值成功),当一个变量用到letconst声明的时候(不管letconst是第一次或是后面出现在声明),就不允许重复声明了。

var a = 1
var a = 'tomato'
// tomato
console.log(a);
var a = 1
let a = 'tomato'
//SyntaxError: Identifier 'a' has already been declared
console.log(a);

另外,如果一个变量省略了声明操作符var(letconst),将会创建一个全局变量(应该是全局对象的属性)

var msg = 'hi'
function test(){
    message = 'hello'
}
//{value: "hi", writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(window,'msg')

//{value: "hello", writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(window,'message')

//hello
console.log(message)

//false
delete window.msg

//true
delete window.message

没有省略var变成全局属性的变量configurable特性为true,表示此属性可被删除,特性可配置,所以能被delete删除。

给未经声明的变量赋值在严格模式下会导致抛出 ReferenceError 错误。

可以在一行定义多个变量,用逗号(,)隔开

var a = 'hi',b = 'peter';

var声明的变量在当前执行环境中有交,ES6中使用letconst具有块级作用域,及在当前代码块中有效(使用{}括起来的就是一个代码块)。

{
    let a = 10;
}
//ReferenceError: a is not defined
console.log(a)

使用var声明变量不受条件语句限制,let、const则表现为块级特性:

if(true){
    var a = 10;
}
//10
console.log(a)
if(true){
    let a = 10;
}
//ReferenceError: a is not defined
console.log(a)

var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

ES5 声明变量只有两种方法:var命令和function命令。ES6 除了添加letconst命令,还有 import命令和class命令。

变量命名

前面说到JavaScript 是一种区分大小写的语言。这意味着,变量名 myCounter 与变量名MYCounter 不同。变量名可以是任意长度。变量是一个标识符,所以必须满足标识的命名规则:

  • 第一个字符必须是一个字母、下划线(_)或一个美元符号($);
  • 其他字符可以是字母、下划线、美元符号或数字。
  • 不能是关键字或保留字

变量赋值

前面说到 ECMAScript 的变量是松散类型的,一个变量可以赋值为任意类型的值,用=为一个变量赋值。

var a;
var b = 1;
var b = [1,2,3];

上面代码中,变量a只声明,没有赋值,默认为undefined,变量b赋值为数字1,随后又声明(没用到let、const的变量再次声明无效,如用到let、const声明的变量再次声明则会报错)a并赋值为数组类型值。

变量提升

一个变量的声明与赋值有时随写在一起,但解释器并不是完成声明后就为变量赋值的。

JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量(获取的变量此时的值是undefined),然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(更准确的说是变量声明提升)。

//undefined
console.log(a);

var a = 10

//10
text(a);

//10
console.log(a)

function text(a){
    console.log(a)
}

JavaScript 引擎在处理上面代码的时候,先整体解析一遍,把声明的变量(也包括函数声明)提升到代码的顶端。

实际运行的效果如下:

var a;
function text(a){
    console.log(a)
}

//undefined
console.log(a);

a = 10

//10
text(a);

//10
console.log(a)

函数声明的提升是把整个函数提升,函数表达式只提升变量名:

//hi
b();
function b(){
    console.log('hi')
}
//TypeError: a is not a function
a();
var a = function(){
    console.log('hello world')
};

上面第一段代码,函数声明b整体提升到了顶部,然后再运行 b(),类似如下执行过程

function b(){
    console.log('hi')
}
//hi
b();

第二段代码则是如下执行过程

var a;
a();
a = function(){
    console.log('hello world')
}

ES6中,使用letconst声明的变量不存在变量提升,所以必须在声明后使用。

© 2018邮箱:11407215#qq.comGitHub沪ICP备12039518号-6