1.null和undefined
①概念上区别:
null是一个特殊的对象,是“非对象”,使用typeof后是object对象
undefined用未定义的值表示更深层次的“空值”,它是变量的一种取值,表示变量没有初始化。使用typeof后是undefined,undefined是预定义的全局变量(和null不同,null是关键字)
null表示"没有对象",即该处不应该有值。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
②使用场景上:
null类型也只有一个值,即null。null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype)
// null
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
var i;
i // undefined
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
function f(x){console.log(x)}
f() // undefined
(3)对象没有赋值的属性,该属性的值为undefined。
var o = new Object();
o.p // undefined
(4)函数没有返回值时,默认返回undefined。
var x = f();
x // undefined
2.全局对象
全局对象(global object)在JavaScript中有着重要的用途:
全局对象的属性是全局定义的符号,JavaScript程序可以直接使用。当JavaScript解释器启动时候,它将创建一个新的全局对象,并定义一组初始属性。
在代码的最*——不在任何函数内的Javascript代码——可以使用Javascript关键字this来引用全局对象。
var global = this;
在客户端Javascript当中,在其表示的浏览器窗口中的所有javascript代码中,window对象充当了全局对象,这个全局Window对象有一个属性window引用其自身,可以代替this来引用全 局对象。
初次创建的时候,全局对象定义了Javascript中所有的预定义全局值。这个特殊对象同样包含了为程序定义的全局值。如果代码声明了一个全局变量,这个全局变量就是全局对象的一个属性。
3.包装对象
存取字符串、数字或者布尔值的属性时创建的临时对象称为包装对象。
理解:
我们在使用JS的时候,经常遇到下面的情况:
1 var s = 'Hello World!';
2 s.len = 12; //这个对象是临时的,所以下句代码执行后为undefiend
3 alert(s.len);
s是一个字符串,并不是一个对象,为什么能使用s.len这个属性呢?
原因:在调用s.len时候,会使用new String(s)创建一个临时的对象,这个对象继承了字符串的方法和属性。
同理数字和布尔值也可以通过Number()和Boolean()来构造一个临时的对象。
注意:
①下面执行的结果是:test类型时string,而test2的类型时object
1 //打印两者的类型,发现test是字符串,而test2则为object类型
2 var test2 = new String(test);
3 alert(typeof (test) + " " + typeof (test2));
②
1 //test和test2在使用==时候是相等的,但是使用===就不同了
2 if (test == test2) {
3 alert("他们一样!");
4 }
5 else {
6 alert("他们不一样!");
7 }
8
9 if (test === test2) {
10 alert("他们一样!");
11 }
12 else {
13 alert("他们不一样!");
14 }
4.不可变的原始值和可变的对象引用
这个有点像C#当中的值类型和引用类型,还涉及了C#当中字符串的不可变性
JS当中的原始值包括:布尔型、数字、字符串、null、undefined
JS当中的对象类型包括:数组、对象等
①两者的变化性是不同的
原始值是不可变的,对于布尔、数字、null和undefined这几个类型比较容易理解,但是对于字符串涉及到了字符串的不可变性。
例如:
1 var str = "hello";
2 str.toUpperCase();
3 alert(str);
结果是打印了hello。
对象的值是可以修改的。
例如:
1 //对象值可变
2 var object1 = { x: 1, y: 2 };
3 object1.x = 10; //修改一个属性值
4 object1.z = 12; //增加一个属性值
5 alert(object1.x + "......" + object1.z);
6
7
8 var array1 = [1, 2, 3];
9 array1[0] = 10; //修改一个数组的值
10 array1[3] = 4; //增加一个数组的值
11 alert(array1[0] + "......" + array1[3]);
输出结果:
②两者的比较也不一样
1)原始值的比较就是值的比较:只有在它们值相等时候它们才相等。对已字符串如果它们的长度相同,并且每个索引的字符都相等,则认为它们相等
2)对象值的比较不是值的比较,即使两个对象包含同样的属性和相同的值,它们也是不相等的。各个索引元素完全相等的两个数组也不是相等的。
例如:
1 //对象的比较
2 var object2 = { x: 1 };
3 var object3 = { x: 1 };
4 alert(object2 == object3); //输出是false
5
6 var a = [1];
7 var b = [1];
8 alert(a == b); //输出是false
9
10 //当两个对象指向同一个基对象时候它们才相等
11 var x = [];
12 var y = x;
13 x[0] = 1;
14 alert(y[0]); //输出结果为1
15 alert(x == y); //输出结果为true
上面代码所示var y = x;仅仅是把x的引用赋值给了y,如果想得到一个引用类型的副本,就必须显示地进行赋值对象的每一个属性或者数组的每一个元素。(循环的方式)
同理引用类型的比较也必须显示的比较每一个属性或者元素。
5.类型转换
JS中的类型装换会根据需要进行转换,非常灵活。不想其他高级语言会有错误的提示。
1)转换和相等性:一个值转换成另一个值,并不意味着这两个值相等。
例如:在期望使用布尔值的地方使用了undefined,它会转换成false,但是这并不表明undefined == false。
2)显示类型转换
做显示类型转换最简单的方法就是使用以下的函数:
Number()
Boolean()
String()
Object()
注意:除了null和undefined之外的任何值都具有toString()方法,这个方法的执行结果和String()一致。
数字转换成字符串(number-to-string)
有几个方法需要了解
toString()方法
例:
1 var num = 100;
2 var bin = num.toString(2);//二进制
3 var oct = num.toString(8);//八进制
4 var hex = num.toString(16);//十六进制
5
6 alert(bin + "..." + oct + "..." + hex);
处理科学计算数据的时候,可以使用以下方法
①toFixed()方法
根据小数点后的指定位数将数字转换为字符串。
②toExponential()
使用指数方式进行记录,小数点钱只有一位
③toPrecision()
根据指定的有效数字位数将数字转换成字符串。如果有效位数少于数字整数部分的位数,则转换成指数形式
例:
1 var n = 123456.789;
2 alert(n.toFixed(0) + "..." + n.toFixed(2) + "..." + n.toFixed(5));
3 alert(n.toExponential(1) + "..." + n.toExponential(3));
4 alert(n.toPrecision(4) + "..." + n.toPrecision(7) + "..." + n.toPrecision(10));
注意结果,它们都进行了4舍5入
将字符串转换成数字(string-to-number)
①直接使用Number()函数
传入一个字符串,试图将其转换成一个整数或者浮点数直接量,这个方法只能基于十进制进行转换,并且不能出现非法的尾随字符。
②使用parseInt()和parseFloat()方法
parseInt只解析整数,而parseFloat可以解析整数和浮点数
如果字符串的前缀是“0x”或者“0X”,则解析为16进制
parseInt可以接受2个参数,第二参数指定了进制位数,合理取值是2-36
对象转换成原始值
①对象到boolean值
由上面最开始的图知道,所有对象转换为boolean值都是true;
对于包装对象也是如此,new Boolean(false)是一个对象而不是原始值,转换后为true
②对象到字符串,对象到数字
以下的转换规则只适用于本地对象,宿主对象根据自己的算法进行转换
所有的对象继承了两个转换方法toString()和valueof();
toString方法作用是返回一个对象的字符串,但是要注意的是很多类型定义了自己的toString方法
例如:
数组:返回一个以“,”作为分隔的字符串
函数,返回函数实现的定义
日期,返回一个可读的是日期时间
RegExp类,返回一个符合正则表达式的字符串
Valueof()
对象是复合值,大多数对象无法真正表示为一个原始值
数组,函数,正则,在调用的时候,都会返回对象的本身,而不是一个原始值
日期 会返回一个毫秒数
JS当中对象到字符串的转换过程:
1)先调用toString(),如果返回一个原始值就把这个值转成字符串返回
2)否则调用valueof(),如果成功返回一个原始值,就转换成字符串返回
3)都不行,就抛出异常
JS当中对象到数字的转换
和对象到字符串的转换过程稍微有一点不同,他是先进行valueof()调用,返回一个原始值,那么就转换成数字返回。如果没有返回原始值,就再调用toString()。
解释:为什么空数组会被转换成数字0?
1)首先空数组调用valueof()函数,它返回的是一个对象而不是一个原始值,然后再调用toString(),空数组转化成空字符串进行返回,空字符串转换数字就是0。(可以看最开始的表)
6.变量的声明
这个没啥讲的,var,弱类型,初始化不赋值,就是undefined
7.变量的作用域
一个变量的作用域(scope)是程序源代码中定义这个变量的区域。
变量根据作用域的不同可以分为,全局变量和局部变量,特有意思的是JS当中全局和局部变量可以同名,这在其他高级语言里面都是不能的。
在函数体内,局部变量的优先级高于全局变量。
例如:
var s = "Global";
function checkscope() {
var scope = "Local";
return scope;
}
alert(checkscope());
这里要注意一点:我们在编写全局作用域的时候可以不写var语句,但是声明局部变量时候必须使用var语句。
例如:
var s = "Global";
function checkscope() {
s = "Local";
return s;
}
alert(checkscope()+"..."+s);
函数定义是可以而嵌套的,
1 var scope = "Global";
2 function checkscope() {
3 alert(scope);
4 var scope = "local";
5 function nested() {
6 var scope = "nested";
7 alert(scope);
8 return scope;
9 }
10 alert(scope);
11 return nested();
12 }
13 checkscope();
输出结果是:
由上图我们看到第一次输出是undefined,为什么会这样呢?这就涉及到了下面要讲的“声明提前”这个概念。
①函数作用域和声明提前
在C语言等一些高级语言中,可以把花括号之间的每一段代码看成具有自己的作用域,而且变量在声明他们的代码段之外是不可见的。我们成为块级作用域。在JS当中没有块级作用域这个概念。取而代之的是函数作用域,变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。‘
例子
function test(o)
{
var i = 0;
if (typeof o == "object")
{
var j = 0;
for (var k = 0; k < 10; k++) {
console.log(k);
}
console.log(k);
}
console.log(j);
}
var o = new String(123);
test(o);
输出是
可以看到K最后输出的值是10,说明k的作用域不仅仅是在循环内。j最后输出是0,也说明j的作用域不仅仅在if判断当中。
上面那个输出undefined的例子,也能够被解释了,因为变量在整个函数体内是可见的,但是第一次alert的时候并没有被赋值,所以输出undefined。
所以上面的代码等价于把,变量的声明放在函数的顶部,所以就叫“声明提前”。
②作为属性的变量
声明一个全局变量时候,相当于定义了一个全局对象的属性,当使用var进行声明变量的时候,这个属性是不能够被删除的,变量无法通过delete运算符来删除,但是去掉var,js也会创建一个全局的变量,这种方式创建的全局属性是可以进行删除的。
③作用域链
简单理解
http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html