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 相关文章推荐
在 IE 中调用 javascript 打开 Excel 表
Dec 21 Javascript
prototype Element学习笔记(篇一)
Oct 26 Javascript
在jQuery ajax中按钮button和submit的区别分析
Oct 07 Javascript
jquery 取子节点及当前节点属性值的方法
Aug 24 Javascript
js和C# 时间日期格式转换的简单实例
May 28 Javascript
使用Web Uploader实现多文件上传
Jun 08 Javascript
Bootstrap基本样式学习笔记之按钮(4)
Dec 07 Javascript
深入学习 JavaScript中的函数调用
Mar 23 Javascript
Vue.js 中取得后台原生HTML字符串 原样显示问题的解决方法
Jun 10 Javascript
angular.js实现列表orderby排序的方法
Oct 02 Javascript
vue-cli3.0如何使用CDN区分开发、生产、预发布环境
Nov 22 Javascript
JavaScript高级程序设计之变量与作用域
Nov 17 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
《DOTA3》开发工作已经开始 《DOTA3》将代替《DOTA2》
2021/03/06 DOTA
深入PHP获取随机数字和字母的方法详解
2013/06/06 PHP
利用laravel+ajax实现文件上传功能方法示例
2017/08/13 PHP
tp5修改(实现即点即改)
2019/10/18 PHP
jquery 屏蔽一个区域内的所有元素,禁止输入
2009/10/22 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
JavaScript实现16进制颜色值转RGB的方法
2015/02/09 Javascript
值得分享的Bootstrap Ace模板实现菜单和Tab页效果
2015/12/30 Javascript
第十章之巨幕页头缩略图与警告框组件
2016/04/25 Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
2016/08/24 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
Javascript的this用法
2017/01/16 Javascript
解析jquery easyui tree异步加载子节点问题
2017/03/08 Javascript
Vue通过getAction的finally来最大程度避免影响主数据呈现问题
2020/04/24 Javascript
浏览器JavaScript调试功能无法使用解决方案
2020/09/18 Javascript
[45:06]完美世界DOTA2联赛PWL S2 Magma vs InkIce 第二场 11.28
2020/12/02 DOTA
Python模块学习 re 正则表达式
2011/05/19 Python
Python中函数的参数定义和可变参数用法实例分析
2015/06/04 Python
Python读大数据txt
2016/03/28 Python
Python3安装Pymongo详细步骤
2017/05/26 Python
Python中顺序表的实现简单代码分享
2018/01/09 Python
Python OpenCV实现图片上输出中文
2018/01/22 Python
Python SMTP发送邮件遇到的一些问题及解决办法
2018/10/24 Python
python 实现按对象传值
2019/12/26 Python
keras实现多GPU或指定GPU的使用介绍
2020/06/17 Python
html5 datalist标签使用示例(自动完成组件)
2014/05/04 HTML / CSS
Origins悦木之源英国官网:雅诗兰黛集团高端植物护肤品牌
2017/11/06 全球购物
中学劳技课教师的自我评价
2014/02/05 职场文书
总经理助理工作职责
2014/02/06 职场文书
教育技术职业规划范文
2014/03/04 职场文书
八一建军节慰问信
2015/02/14 职场文书
手机销售员岗位职责
2015/04/11 职场文书
大学生就业意向书
2015/05/11 职场文书
教师见习总结范文
2015/06/23 职场文书
2015年终个人政治思想工作总结
2015/11/24 职场文书
C站最全Python标准库总结,你想要的都在这里
2021/07/03 Python