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 相关文章推荐
解密效果
Jun 23 Javascript
使用javascript访问XML数据的实例
Dec 27 Javascript
JSON 和 JavaScript eval使用说明
Jun 13 Javascript
一个关于jqGrid使用的小例子(行按钮)
Nov 04 Javascript
JS限制上传图片大小不使用控件在本地实现
Dec 19 Javascript
JavaScript使用yield模拟多线程的方法
Mar 19 Javascript
jQuery过滤HTML标签并高亮显示关键字的方法
Aug 07 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
May 26 Javascript
微信小程序商城项目之侧栏分类效果(1)
Apr 17 Javascript
Vue2路由动画效果的实现代码
Jul 10 Javascript
p5.js实现动态图形临摹
Oct 23 Javascript
微信小程序商品详情页底部弹出框
Nov 22 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 增加了对 .ZIP 文件的读取功能
2006/10/09 PHP
php中的一个中文字符串截取函数
2007/02/14 PHP
php用正则表达式匹配URL的简单方法
2013/11/12 PHP
PHP读取大文件的多种方法介绍
2016/04/04 PHP
PHP无限极分类函数的实现方法详解
2017/04/15 PHP
深入理解Yii2.0乐观锁与悲观锁的原理与使用
2017/07/26 PHP
PHP实现的简单对称加密与解密方法实例小结
2017/08/28 PHP
php和asp语法上的区别总结
2019/05/12 PHP
基于jquery的分页控件(C#)
2011/01/06 Javascript
用JQuery模仿淘宝的图片放大镜显示效果
2011/09/15 Javascript
实现网页页面跳转的几种方法(meta标签、js实现、php实现)
2014/05/20 Javascript
NodeJS学习笔记之网络编程
2014/08/03 NodeJs
Node.js中使用Log.io在浏览器中实时监控日志(等同tail -f命令)
2014/09/17 Javascript
jquery插件unobtrusive实现片段式加载
2015/06/15 Javascript
AngularJS  自定义指令详解及实例代码
2016/09/14 Javascript
js模拟支付宝密码输入框
2017/04/11 Javascript
Require.js的基本用法详解
2017/07/03 Javascript
Vue项目组件化工程开发实践方案
2018/01/09 Javascript
基于IView中on-change属性的使用详解
2018/03/15 Javascript
React组件内事件传参实现tab切换的示例代码
2018/07/04 Javascript
微信小程序日历弹窗选择器代码实例
2019/05/09 Javascript
使用layer弹窗提交表单时判断表单是否输入为空的例子
2019/09/26 Javascript
JS通过识别id、value值对checkbox设置选中状态
2020/02/19 Javascript
Postman无法正常返回结果问题解决
2020/08/28 Javascript
[02:39]DOTA2国际邀请赛助威团西雅图第一天
2013/08/08 DOTA
Java及python正则表达式详解
2017/12/27 Python
Django数据库连接丢失问题的解决方法
2018/12/29 Python
详解Python:面向对象编程
2019/04/10 Python
python实现证件照换底功能
2019/08/20 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
keras实现基于孪生网络的图片相似度计算方式
2020/06/11 Python
英国鞋类及配饰零售商:Kurt Geiger
2017/02/04 全球购物
大专生工程监理求职信
2013/10/04 职场文书
个人作风剖析材料
2014/02/02 职场文书
超级实用的公文标题大全!
2019/07/19 职场文书
再也不用花钱买漫画!Python爬取某漫画的脚本及源码
2021/06/09 Python