JavaScript是弱类型脚本语言,系统会自动识别变量的类型,所以不用定义类型,但它同样支持变量生命,并存在局部变量,全局变量之分
变量的定义方式
JavaScript支持不提前定义变量就直接使用,
所以有两种定义方式
- 隐式定义直接给变量赋值
a = "Hello World";
- 显式定义使用关键字定义变量
var a ;
a = "abc";
或直接合并
var a = "abc";
JavaScript是弱类型语言,变量没有固定的数据类型,因此可以对同一个变量在不同的时间赋不同类型的值。
显式声明方式是采用var关键字声明变量,声明时可以没有初始值,生命的变量数据类型是不确定的,当第一次给变量赋值时,变量的数据类型才确定下来,而且使用过程中变量的数据类型也可随意改变。
需要注意的是 JavaScript中的变量可以一次定义多个,而且变量区分大小写,abc和ABC是两个不同的变量
变量的类型转换
自动类型转换
变量的类型转换在JavaScript中可以自动实现。
<script yle="text/javascript">
var a = "3.145";
var b = a - 2;
var c = a + 2;
alert(b + "\n" + c);
</script>
结果
a被定义成值为3.145的字符串,让a和b做减法时,是实际数值的相减——3.145-2=1.145
而a和c做加法时,情况则变成了“3.145”+“2”=“3.1452”,编译器实际是做了对字符串的拼接工作
通过例子我们可以看到,上面程序发生了简单的类型转换
- 减法运算时,由于字符串不支持减法运算,所以“-”:a-c就变成了数值上的减法,即a的值3.145由字符串转换为了数值
- 加法运算时,由于字符串可以支持字符串拼接,运用加号,所以此时的“+”就被认定为连接运算符了,所以系统便将2转换成了字符串,拼接在了a的后面
类型转换在JavaScript中常有发生,他的转换规则如下表
自动转换固然方便,但同时可读性将会变差,而且也不够智能,如同上例,若想让a+2执行的起来是数值加法运算,则需要使用强制类型转换。
强制类型转换
JavaScript提供了如下几个函数类执行强转
- toString():将布尔值,数值等等转换成字符串
- parseInt:将字符串,布尔值等转换成整数
- parseFloat:将字符串,布尔值等转换成浮点数
这样,将上例修改为
<script yle="text/javascript">
var a = "3.145";
var b = a - 2;
var c = parseFloat(a) + 2;
alert(b + "\n" + c);
</script>
即可达到效果
###对于字符串是数字的,强转后将得到相应的数值,但是如果包含其他类型如字母,则会转换成NaN
当使用parseInt()或parseFloat()将各种类型的变量转换成数值类型时,将遵循以下规则
- 字符串值:数字转换为数值,否则转换为NaN
- undefined、null、布尔值及其他对象:NaN
相反,当使用toSring()函数将各种类型的值向字符串转换是,结果全部都是object
变量的作用域
变量有全局变量和局部变量之分,代表两种变量的作用于有所不同,
- 局部变量:在函数内通过var关键字定义的变量
- 全局变量:在全局范围定义的变量(不在函数体内),无论是否使用关键字var,都将被定义为全局变量,在函数体内不使用var定义的变量同样为全局变量
注意
在函数体内定义的局部变量,跳出函数体则失效,
<script yle="text/javascript">
var a = "3.145";
function m(){
b = 10;
var c = 20;
alert(a + "\n" + b + "\n" + c);
}
m();
alert(a + "\n" + b + "\n" + c);
</script>
在上面程序中,可以看到,a是在全局范围用var定义的变量,是全局变量,b是函数体内没有用var关键字定义的全局变量,c是函数体内用var定义的局部变量,所以在输出时,函数体内的alert可以正常输出,因为他可以访问到a,b,c,
而函数外的alert则会由于访问不到局部变量c,而产生报错
其他需要关注的点
1. 变量可以被重复定义
<script yle="text/javascript">
var a = "3.145";
function m(){
var a = 10;
alert(a);
}
m();
alert(a);
</script>
输出的两个a,第一个的值为10,第二个值会是3.145。因为a首先被声明为全局变量,而在函数体内又被定义成局部变量,所以函数体内的alert输出的是局部变量a,但在挑出函数体范围以后,第二个alert由于访问不到局部变量a了,所以他会选择原来的全局变量a来输出。
2. JavaScript中没有块范围
<script yle="text/javascript">
var a = "3.145";
if(typeof o == "object"){
var b = 1;
for(var c = 1 ; c<3 ; c++){
alert(c);
}
}
alert(c + "\n" + b);
</script>
结果会看到两个alert都正常输出,因为没有块范围,所以在for判别式内部定义的c的作用范围是他所属的整个函数,而b也同理。
可以看到,JavaScript中大括号对变量的范围限定非常有限,因为JavaScript没有块范围,JavaScript中变量的范围,只有整个全局范围,或者函数体内(只有定义函数体的大括号才会限定变量的范围,除此之外任何大括号都不能限定范围)两种
3. 变量的提升
我们知道,如果先定义全局变量而后定义同名的局部变量,局部变量会覆盖全局变量,但是,若在函数体内,先输出一个全局变量,在定义同名的局部变量,结果会如何?
<script yle="text/javascript">
var a = "全局变量";
function m(){
document.writeln(a);
var a ="局部变量"
document.writeln(a);
}
m();
document.writeln(a);
</script>
在第一个输出时,并不会像我们想的输出“全局变量”,而是输出了undefined,这是因为虽然在函数体内,虽然我们先输出的a,再重新定义了局部变量a,但是在函数体内,对a的再定义会被提升到函数开头,即
<script yle="text/javascript">
var a = "全局变量";
function m(){
var a;
document.writeln(a);
a ="局部变量"
document.writeln(a);
}
m();
document.writeln(a);
</script>
这就是变量的提升
在编写程序时应当注意,尽量不要定义相同名称的变量,定以变量时也最好将定义写在全局的开头,或者是函数体的开头,
注意
变量的提升,是只要变量被定义,就会发生提升,如果将函数定义写在了一个根本就不会被执行的地方,变量的定义,提升仍然会出现
let变量
上述变量定义是,都是采用var前缀定义,我们可以看到,当用var定义函数时,
- 他会没有块作用域
- var定义的全局变量会自动添加全局window对象的属性(window是最大的对象,他的子对象有document等,所以window常常会被忽略)
- var定义的变量会发生提前装载
运用let关键字定义,将会解决上述问题
如
let a = 1 ;
console.log(window.a);
程序会报错,因为let定义的变量不会变成window对象的属性
<script yle="text/javascript">
var a = "全局变量";
function m(){
document.writeln(a);
let a ="局部变量"
document.writeln(a);
}
m();
document.writeln(a);
</script>
重新输入前文的代码,将函数体内var关键字编程let,由于没有了提前装载,所以函数体内第一次输出a将会报错,
注意
变量提升还是会出现,函数体内的局部变量let a会覆盖全局变量var a,但是由于不会提前装载,所以意味着在第一次输出a时,a已经变成了局部变量,但是没有由于没有装载,所以会报错显示没有找到变量a
const常量
JavaScript的常量和其他语言中类似,定义方法为
const MAX_AGE=80;
一般约定常量名称为大写,const常量再被定义后,就不可能会被修改,对常量的赋值,自增,都会发生语法错误。所以需要常量值在定义时就给出,此后不会发生变更