js基础--类型转换与变量作用域

类型转换

  • 转换和相等性

由于JavaScript可以做灵活的类型转换,因此其“==”相等运算符也随相等的含义灵活多变。例如,如下这些比较结果均是true:
null==undefined//这两值被认为相等

"0"==0//在比较之前字符串转换成数字

0==false//在比较之前布尔值转换成数字

"0"==false//在比较之前字符串和布尔值都转换成数字
需要特别注意的是,一个值转换为另一个值并不意味着两个值相等。比如,如果在期望使用布尔值的地方使用了undefined,它将会转换为false,但这并不表明undefined==false。JavaScript运算符和语句期望使用多样化的数据类型,并可以相互转换。if语句将undefined转换为false,但“==”运算符从不试图将其操作数转换为布尔值。
  • 显式类型转换

尽管JavaScript可以自动做许多类型转换,但有时仍需要做显式转换,或者为了使代码变得清晰易读而做显式转换。

做显式类型转换最简单的方法就是使用Boolean()、Number()、String()或Object()函数。当不通过new运算符调用这些函数时,它们会作为类型转换函数做类型转换:
Number("3")//=>3

String(false)//=>"false"或使用false.toString()

Boolean([])//=>true

Object(3)//=>new Number(3)
需要注意的是,除了null或undefined之外的任何值都具有toString()方法,这个方法的执行结果通常和String()方法的返回结果一致。

JavaScript中的某些运算符会做隐式的类型转换,有时用于类型转换。如果“+”运算符的一个操作数是字符串,它将会把另外一个操作数转换为字符串。一元“+”运算符将其操作数转换为数字。同样,一元“!”运算符将其操作数转换为布尔值并取反。在代码中会经常见到这种类型转换的惯用法:
x+""//等价于String(x)

+x//等价于Number(x).也可以写成x-0

!!x//等价于Boolean(x).注意是双叹号
如果通过Number()转换函数传入一个字符串,它会试图将其转换为一个整数或浮点数直接量,这个方法只能基于十进制数进行转换,并且不能出现非法的尾随字符。parseInt()函数和parseFloat()函数(它们是全局函数,不从属于任何类的方法)更加灵活。parseInt()只解析整数,而parseFloat()则可以解析整数和浮点数。如果字符串前缀是"0x"或者"0X",parseInt()将其解释为十六进制数[8],parseInt()和parseFloat()都会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回NaN:

parseInt("3 blind mice")//=>3

parseFloat("3.14 meters")//=>3.14

parseInt("-12.34")//=>-12

parseInt("0xFF")//=>255

parseInt("0xff")//=>255

parseInt("-0XFF")//=>-255

parseFloat(".1")//=>0.1

parseInt("0.1")//=>0

parseInt(".1")//=>NaN:整数不能以"."开始

parseFloat("$72.47");//=>NaN:数字不能以"$"开始

 parseInt()可以接收第二个可选参数,这个参数指定数字转换的基数,合法的取值范围是2~36,例如:

parseInt("11",2);//=>3(1*2+1)

parseInt("ff",16);//=>255(15*16+15)

parseInt("zz",36);//=>1295(35*36+35)

parseInt("077",8);//=>63(7*8+7)

parseInt("077",10);//=>77(7*10+7)
  •  

变量作用域

  • 函数作用域和声明提前

一个变量的作用域(scope)是程序源代码中定义这个变量的区域。全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的。然而在函数内声明的变量只在函数体内有定义。它们是局部变量,作用域是局部性的。函数参数也是局部变量,它们只在函数体内有定义。

在函数体内,局部变量的优先级高于同名的全局变量。如果在函数内声明的一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所遮盖。
var scope="global";//声明一个全局变量
function checkscope(){
    var scope="local";//声明一个同名的局部变量
    return scope;//返回局部变量的值,而不是全局变量的值
}
checkscope()//=>"local"
尽管在全局作用域编写代码时可以不写var语句,但声明局部变量时则必须使用var语句。思考一下如果不这样做会怎样:
scope="global";//声明一个全局变量,甚至不用var来声明
function checkscope2(){
    scope="local";//糟糕!我们刚修改了全局变量
    myscope="local";//这里显式地声明了一个新的全局变量
    return[scope,myscope];//返回两个值
}
checkscope2()//=>["local","local"]:产生了副作用
scope//=>"local":全局变量修改了
myscope//=>"local":全局命名空间搞乱了
函数定义是可以嵌套的。由于每个函数都有它自己的作用域,因此会出现几个局部作用域嵌套的情况,例如:
var scope="global scope";//全局变量
function checkscope(){
    var scope="local scope";//局部变量
    function nested(){
        var scope="nested scope";//嵌套作用域内的局部变量
        return scope;//返回当前作用域内的值
    }
    return nested();
}
checkscope()//=>"嵌套作用域"
  • 作为属性的变量

当声明一个JavaScript全局变量时,实际上是定义了全局对象的一个属性。当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说这个变量无法通过delete运算符删除。可能你已经注意到了,如果你没有使用严格模式并给一个未声明的变量赋值的话,JavaScript会自动创建一个全局变量。以这种方式创建的变量是全局对象的正常的可配值属性,并可以删除它们:
var truevar=1;//声明一个不可删除的全局变量

fakevar=2;//创建全局对象的一个可删除的属性

this.fakevar2=3;//同上

delete truevar//=>false:变量并没有被删除

delete fakevar//=>true:变量被删除

delete this.fakevar2//=>true:变量被删除
 
  • 作用域链

如果将一个局部变量看做是自定义实现的对象的属性的话,那么可以换个角度来解读变量作用域。每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链(scope chain)。这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。当JavaScript需要查找变量x的值的时候(这个过程称做“变量解析”(variable resolution)),它会从链中的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象中不存在名为x的属性,JavaScript会继续查找链上的下一个对象。如果第二个对象依然没有名为x的属性,则会继续查找下一个对象,以此类推。如果作用域链上没有任何一个对象含有属性x,那么就认为这段代码的作用域链上不存在x,并最终抛出一个引用错误(ReferenceError)异常。

猜你喜欢

转载自blog.csdn.net/wuyufa1994/article/details/85730119