js变量以及其作用域详解


Posted in Javascript onJuly 18, 2020

一、变量的类型

Javascript和Java、C这些语言不同,它是一种无类型、弱检测的语言。它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量。例如:

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

JS的这种特性虽然让我们的编码更加灵活,但也带来了一个弊端,不利于Debug,编译器的弱检测让我们维护冗长的代码时相当痛苦。

二、变量的声明

JS中变量申明分显式申明和隐式申明。

var i=100;//显式申明

i=100;//隐式申明

在函数中使用var关键字进行显式申明的变量是做为局部变量,而没有用var关键字,使用直接赋值方式声明的是全局变量。


当我们使用访问一个没有声明的变量时,JS会报错。而当我们给一个没有声明的变量赋值时,JS不会报错,相反它会认为我们是要隐式申明一个全局变量,这一点一定要注意。

三、全局变量和局部变量

当JS解析器执行时,首先就会在执行环境里构建一个全局对象,我们定义的全局属性就是做为该对象的属性读取,在顶层代码中我们使用this关键字和window对象都可以访问到它。而函数体中的局部变量只在函数执行时生成的调用对象中存在,函数执行完毕时局部变量即刻销毁。因此在程序设计中我们需要考虑如何合理声明变量,这样既减小了不必要的内存开销,同时能很大程度地避免变量重复定义而覆盖先前定义的变量所造成的Debug麻烦。

四、变量作用域

任何程序语言中变量的作用域都是一个很关键的细节。JS中变量的作用域相对与JAVA、C这类语言显得更自由,一个很大的特征就是JS变量没有块级作用域,函数中的变量在整个函数都中有效,运行下面代码:

<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,从上面就可以证明JS如果用var在函数体中声明变量,那么此变量在且只在该函数体内有效,函数运行结束时,本地变量即可销毁了。

由于上面的这个JS特性,还有一个关键的问题需要注意。此前一直使用ActionScript,虽然它和JS都是基于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 
}

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

五、基本类型和引用类型

JS不同于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。

Javascript 相关文章推荐
jQuery EasyUI API 中文文档 - ComboBox组合框
Oct 07 Javascript
JavaScript中使用concat()方法拼接字符串的教程
Jun 06 Javascript
js变量提升深入理解
Sep 16 Javascript
js与jquery分别实现tab标签页功能的方法
Nov 18 Javascript
jQuery实现动态给table赋值的方法示例
Jul 04 jQuery
vuex 使用文档小结篇
Jan 11 Javascript
微信小程序实现折叠与展开文章功能
Jun 12 Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
Jan 08 Javascript
详解项目升级到vue-cli3的正确姿势
Jan 28 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
May 26 Javascript
原生js实现密码强度验证功能
Mar 18 Javascript
sharp.js安装过程中遇到的问题总结
Apr 02 Javascript
分享一个asp.net pager分页控件
Jan 04 #Javascript
调试Node.JS的辅助工具(NodeWatcher)
Jan 04 #Javascript
DOM和XMLHttpRequest对象的属性和方法整理
Jan 04 #Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
Jan 03 #Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之二
Dec 31 #Javascript
40个有创意的jQuery图片、内容滑动及弹出插件收藏集之一
Dec 31 #Javascript
js 遍历对象的属性的代码
Dec 29 #Javascript
You might like
php Undefined index的问题
2009/06/01 PHP
php二维数组排序详解
2013/11/06 PHP
php版交通银行网银支付接口开发入门教程
2016/09/26 PHP
JQuery 构建客户/服务分离的链接模型中Table分页代码效率初探
2010/01/22 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
javascript event在FF和IE的兼容传参心得(绝对好用)
2014/07/10 Javascript
基于jQuery的图片不完全按比例自动缩小
2014/07/11 Javascript
JS中JSON对象和String之间的互转及处理技巧
2016/04/06 Javascript
第一章之初识Bootstrap
2016/04/25 Javascript
jQuery自定义数值抽奖活动代码
2016/06/11 Javascript
Google 地图叠加层实例讲解
2016/08/06 Javascript
使用base64对图片的二进制进行编码并用ajax进行显示
2017/01/03 Javascript
微信小程序 input输入框详解及简单实例
2017/01/10 Javascript
js实现下拉菜单效果
2017/03/01 Javascript
JS正则获取HTML元素的方法
2017/03/31 Javascript
使用jQuery和ajax代替iframe的方法(详解)
2017/04/12 jQuery
jQuery实现使用sort方法对json数据排序的方法
2018/04/17 jQuery
vue自定义移动端touch事件之点击、滑动、长按事件
2018/07/10 Javascript
Vue 与 Vuex 的第一次接触遇到的坑
2018/08/16 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
2020/04/29 Javascript
深入讨论Python函数的参数的默认值所引发的问题的原因
2015/03/30 Python
Python自动重试HTTP连接装饰器
2015/04/28 Python
python使用PyGame模块播放声音的方法
2015/05/20 Python
python实现微信自动回复功能
2018/04/11 Python
PyQt5通信机制 信号与槽详解
2019/08/07 Python
matplotlib常见函数之plt.rcParams、matshow的使用(坐标轴设置)
2021/01/05 Python
瑜伽服装品牌:露露柠檬(lululemon athletica)
2017/06/04 全球购物
西班牙香水和化妆品购物网站:Arenal Perfumerías
2019/03/01 全球购物
10条PHP编程习惯
2014/05/26 面试题
武汉高蓝德国际.net机试
2016/06/24 面试题
西部世纪.net笔试题面试题
2014/04/03 面试题
公务员培训心得体会
2013/12/28 职场文书
优秀共产党员先进事迹
2014/01/27 职场文书
2014年9.18纪念日演讲稿
2014/09/14 职场文书
2014年残联工作总结
2014/11/21 职场文书
python基于机器学习预测股票交易信号
2021/05/25 Python