JavaScript变量类型、声明方式与作用域机制详解

作者:异步漫步时间:2026-10-26 16:35:08浏览:185

本文深入解析JavaScript中变量的类型、声明方式及作用域机制。重点阐述JS无类型弱检测特性,对比显式与隐式声明的区别,详解全局与局部变量的生命周期。通过代码示例揭示函数作用域、变量提升及预编译对执行结果的影响,并区分基本类型与引用类型的内存分配与赋值行为。

JavaScript变量类型

一、变量的类型

与Java、C等语言不同,JavaScript是一种无类型且具备弱检测机制的语言。在JS中定义变量时无需显式声明类型,只需通过赋值操作,即可将任意类型的数据赋予同一变量名。例如:

i=100;//Number类型 i="variable";//String类型 i={x:4};//Object类型 i=[1,2,3];//Array类型

这种动态赋值的特性虽然提升了编码的灵活性,但也带来了调试困难的问题。由于编译器执行弱类型检测,在维护长代码时容易引发难以排查的错误。

变量的声明方式

二、变量的声明

JavaScript中的变量声明分为显式声明和隐式声明两种形式。 var i=100;//显式申明 i=100;//隐式申明 在函数内部使用var关键字进行声明的变量被视为局部变量;若未使用var关键字而直接赋值,则该变量成为全局变量。 当尝试访问一个未声明的变量时,JavaScript会抛出错误;然而,若对一个未声明的变量进行赋值,JavaScript不会报错,而是将其视为隐式声明了一个全局变量。这一点在实际开发中需格外注意。

三、全局变量和局部变量

全局变量与局部变量

JavaScript解析器在执行代码时,首先会在执行环境中构建一个全局对象,所有定义的全局属性均作为该对象的属性存在。在顶层代码中,可以通过this关键字或window对象访问该全局对象。而函数体内的局部变量仅存在于函数执行时生成的调用对象中,函数执行完毕后,局部变量即被销毁。因此,在程序设计中合理声明变量至关重要,这不仅能减少不必要的内存开销,还能有效避免因变量重复定义覆盖先前值而导致的调试难题。

四、变量作用域

变量作用域机制

在任何编程语言中,变量的作用域都是关键细节。与Java、C等语言相比,JavaScript的变量作用域更为宽松,其显著特征是缺乏块级作用域。在函数中声明的变量在整个函数体内均有效,运行以下代码:


<SCRIPT LANGUAGE="JavaScript" type="text/javascript"> 
//定义一个输出函数 
function outPut(s){ 
document.writeln(s) 
} 
//全局变量 
var i=0; 
//定义外部函数 
function outer(){ 
//访问全局变量 
outPut(i); // 0 
//定义一个类部函数 
function inner(){ 
//定义局部变量 
var i = 1; 
// i=1; 如果用隐式申明 那么就覆盖了全局变量i 
outPut(i); //1 
} 
inner(); 
outPut(i); //0 
} 
outer(); 
</SCRIPT> 

输出结果为0 1 0,从上述结果可以证明,若在函数体内使用var声明变量,则该变量仅在且仅在该函数体内有效,函数运行结束时本地变量即被销毁。 基于上述JavaScript特性,还需注意一个关键问题。此前若使用ActionScript,尽管其与JavaScript均基于ECMA标准,但在此处存在差异。例如下面代码:


<SCRIPT LANGUAGE="JavaScript" type="text/javascript"> 
//定义一个输出函数 
function outPut(s){ 
document.writeln(s) 
} 
//全局变量 
var i=0; 
//定义外部函数 
function outer(){ 
//访问全局变量 
outPut(i); // 0 
//定义一个类部函数 
function inner(){ 
outPut(i); //undefiend 
var i=1; 
outPut(i); //1 
} 
inner(); 
outPut(i); //0 
} 
outer(); 
</SCRIPT> 

你可能认为输出结果是0 0 1 0,事实上在AS中确实是这样的,而在JS中的输入却是0 undefined 1 0,为何会这样了?刚才我们说到了JS函数体中声明的本地变量在整个函数中都有效,因此在上面代码中var i = 1 ;在inner函数中都有效,实际上显式声明的变量i是在预编译时就已经编译到调用对象中了,不同于隐式声明变量在解释时才被定义为全局变量,只是在调用outPut(i)时,还没有将它初始化变量,此时的本地变量i是未赋值变量,而不是未定义变量,因此输出了undefined。上面的代码等效于下面代码:


function inner(){ 
var i; //定义但不赋值 
outPut(i); //undefiend 
i=1; 
outPut(i); //1 
}

为了避免上面的这类问题,因此在函数开始位置集中做函数声明是一个极力推荐的做法。

基本类型与引用类型

五、基本类型和引用类型

JavaScript与Java、C等语言不同,在变量声明时无需指定存储空间。变量中存储的数据可分为两类:基本类型和引用类型。其中数值、布尔值、null和undefined属于基本类型,对象、数组和函数属于引用类型。 基本类型在内存中具有固定的内存大小。例如:数值型在内存中占有八个字节,布尔值只占有一个字节。对于引用型数据,它们可以具有任意长度,因此内存大小是不定的,变量中存储的实际上是对此数据的引用,通常是内存地址或者指针,通过它们我们可以找到这个数据。 引用类型和基本类型在使用行为上也有不同之处:


<SCRIPT LANGUAGE="JavaScript" type="text/javascript"> 
//定义一个输出函数 
function outPut(s){ 
document.writeln(s) 
} 
var a = 3; 
var b = a; 
outPut(b); 
//3 
a = 4; 
outPut(a); 
//4 
outPut(b); 
//3 
</SCRIPT> 

对基本类型b进行赋值时,实际上是又开辟了一块内存空间,因此改变变量a的值对变量b没有任何影响。


<SCRIPT LANGUAGE="JavaScript" type="text/javascript"> 
//定义一个输出函数 
function outPut(s){ 
document.writeln(s) 
} 
var a_array = [1,2,3]; 
var b_array = a_array; 
outPut(b_array); //1,2,3 
a_array[3] = 4; 
outPut(b_array);//1,2,3,4 
</SCRIPT> 

上面是对引用类型的变量赋值,实际上他们传递的是对内存地址的引用,因此对a_array和b_array的存取,实际上都是操作的同一块内存区域。如果希望重新分配内存空间存储引用型变量,那么我就需要使用克隆方法或者自定义方法来复制引用变量的数据。

JS变量作用域


<script language ="javascript" type ="text/javascript" > 
var a = "change"; 
function fun() { 
alert(a);//输出undefined 
var a = "改变了"; 
alert(a);//输出改变了 
} 
alert(a);//输出change 
fun(); 
</script> 

var定义的是一个作用域上的变量,在第一次输出a之前,JS在预编译分析中已经将a赋值为change,所以第一次输出change,当调用到fun()函数的时候,JS创建一个新的作用域,在输出a之前,初始化所有var变量的值为undefined,所以fun()中第一次输出的是undefined,第二次输出已经给a赋值了,所以输出新的值;两个a在函数里面和外面是不同的两个变量,如:


<script language ="javascript" type ="text/javascript" > 
var b; 
function fun() { 
b = "change"; 
} 
alert(b);//输出undefined 
</script> 

变量b在函数外面已经定义了,在函数中有给b赋值,但输出的却是undefined。

作者最新文章