JS 变量详解

发布时间:2017-03-14

关于JS中的变量

JS中的变量是松散类型的,可以存储任何类型的数据。

JS变量松散类型的本质,决定了变量只是在特定时间用于保存特定值的一个名字而已。

由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。 

用var关键字声明的变量,未经初始化时,保存的是一个特殊的值——undefined。

变量初始化仅仅是给变量赋一个值。

可以在一条语句中声明多个变量,初始化或不初始化皆可,变量之间用逗号隔开。

使用更具语义的变量名,让代码的可读性更强。

用var关键字声明的变量是定义该变量的作用域中的局部变量。

当使用var关键字声明了一个变量时,创建的这个变量是不可配置的,也就是说这个变量无法通过delete运算符删除。

(function num() {
    var num2 = 10;
    delete num2;
    console.log(num2);    //10
})();  
delete num1;    
console.log(num1);    //10

这表明,不管是在全局作用域,还是在局部作用域,var声明的变量都不能通过delete删除。 

在严格模式下,使用delete运算符删除var关键字声明的变量会导致SyntaxError。

省略var关键字会导致定义一个全局变量,但是不推荐这种做法。在严格模式下,给未声明的变量赋值会导致ReferenceError。

1 (function num() {
2     num2 = 10;
3     console.log(num2);    //10
4 })();    
5 console.log(num2);    //10

JS是基于词法作用域的语言:全局变量在整个程序中始终是有定义的,局部变量在声明它的函数体内以及其所嵌套的函数体内始终是有定义的。

在函数体内,局部变量的优先级高于同名的全局变量。

JS没有块级作用域,取而代之的是函数作用域:变量在声明它们的函数体内以及这个函数体嵌套的任何函数体内都是有定义的。

函数内部声明的变量和函数,要等到函数真正执行过后,才能有定义。

基本类型值与引用类型值

JS中的变量可以保存两种不同类型的值:基本类型值和引用类型值。

在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。

基本数据类型:Number、String、Boolean、Null、Undefiend;这5种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。

对于基本类型值,在复制变量的时候,会在新的变量上创建一个新值,这个新值是原值的一个副本,它们相互独立。

基本类型值之间的比较,只是单纯的值的比较。

引用类型值是保存在变量中的对象;引用类型值就是指对象。

保存引用类型值的变量,实际上保存的是一个指向该对象的指针。

当复制保存着对象的某个变量时,复制的其实是指针;复制操作结束后,两个变量指向同一个对象。

对于引用类型值,可以为其添加属性和方法,也可以修改或者删除其属性和方法。

在为对象添加属性和方法时,操作的是实际的对象,因此,改变任何一个变量,都会影响另外一个变量。

复制代码

1 var person1 = {
2     name : "CC"
3 };
4 var person2 = person1;
5 console.log(person2.name);    //"CC"
6 person1.name = "VV";
7 console.log(person2.name);    //"VV"

复制代码

引用类型值的比较并非值的比较:即使两个对象包含相同的属性和值,它们也是不相等的;各个索引元素完全相等的两个数组也不相等。 

引用类型值的比较是引用的比较,当且仅当它们引用同一个对象时,它们才相等。

示例1:

复制代码

1 var person1 = {
2     name : "CC"
3 };
4 var person2 = {
5     name : "CC"
6 };
7 console.log(person1==person2);    //false

复制代码

示例2:

1 var person1 = {
2     name : "CC"
3 };
4 var person2 = person1;
5 console.log(person1 == person2);    //true

类型检测

typeof操作符,检测一个变量是不是基本数据类型;具体而言,typeof操作符是确定一个变量是不是字符串、布尔值、数字、undefined的最佳工具;如果变量的值是一个函数,则会返回function;如果变量的值是null或者是一个其它的对象,则会返回object。

instanceof操作符,如果一个变量是给定的某一个引用类型的实例,则会返回true。

instanceof操作符的本质,在于确定左边的操作数的原型链上是否有右边的操作数的prototype属性。

全局变量

当JS解析器启动时,或者任何Web浏览器加载新页面的时候,它将创建一个新的全局对象,并给他一组定义的初始属性:

全局属性:比如undefined、Infinite、NaN

全局函数:比如isNaN()、parseInt()、eval()

构造函数,比如Date()、String()、Array()、Object()

全局对象:比如Math、Json

初次创建的时候,全局对象定义了JS中所有的预定义全局值。

如果代码声明了一个全局变量,这个全局变量就是全局对象的一个属性。

全局变量作用于全局作用域,在JS代码中的任何地方都是有定义的。

变量的声明、定义与初始化

声明——给变量一个名字,宣告它从此刻开始存在;

定义——给变量分配一个存储空间;

初始化——给变量的存储空间赋值。

在JS中,就是这样子:

1 var x;    //声明——变量x从现在开始存在;2 x = "hello";    //(定义并)初始化。

由于JS是一种动态语言,其变量的类型是不固定的,可以随着保存值的变化而变化,所以其定义变得无关紧要,以上。

变量声明提升

JS在执行的时候,会把所有变量的声明都提升到当前作用域的最前面。

声明提升,这步操作是在JS引擎“预编译”阶段实现的,是在代码开始运行之前。

比较下面两段代码。

1 var x = "hello";
2 (function func() {
3     var x = "world";
4     console.log(x);    //"world"
5 })();

给上面的代码换一下顺序:

1 var x = "hello";
2 (function func() {
3     console.log(x);    //undefined
4     var x = "world";
5 })();

上面的代码中变量x的声明被提升了,实际上代码应该是这样的:

复制代码

1 var x = "hello";
2 (function func() {
3     var x;    //变量声明提升
4     console.log(x);    //undefined
5     x = "world";    //初始化语句
6 })();

复制代码

小提示:特意将变量声明放在函数体顶部,将赋值语句靠近放在使用变量之处,这种做法使得源代码非常清晰地反映了真实的变量作用域。

名字解析顺序

JS中一个名字可能以4种方式进入作用域,其优先级如下:

(1)语言内置——所有作用域中都有arguments对象和this对象;

(2)函数声明

(3)形式参数

(4)变量声明——不会影响同名的函数声明或者形式参数声明

本文转载至: http://www.cnblogs.com/cc156676/archive/2016/07/30/5719805.html