基本概念
一、严格模式(Strict mode)
严格模式开启检测和一些其他措施,使JavaScript变成更整洁的语言。推荐使用严格模式。在严格模式下,某些保留字务必需要添加一些限制。为了开启严格模式,只需在JavaScript文件或script标签第一行添加如下语句:
'use strict';
也可以在每个函数上选择性开启严格模式,只需将上面的代码放在函数的开头:
function functionInStrictMode() {
'use strict';
}
明显错误
严格模式给我们明确的错误,否则JavaScript总是静默失败:下面的函数 f() 执行一些非法操作,它试图更改所有字符串都有的只读属性——length:
function f() {
'abc'.length = 5;
}
当你调用上面的函数,它静默失败,赋值操作被简单忽略。让我们将 f() 在严格模式下运行:
function f_strict() {
'use strict';
'abc'.length = 5;
}
现在浏览器报给我们一些错误:
> f_strict()
TypeError: Cannot assign to read only property 'length' of abc
二、基本数据类型
undefined、Null、Boolean、Number、String基本数据类型;Object引用数据类型
1.undefined一般不存在显示的赋undefined值的情况,表示了变量未赋值(未赋值的变量直接被赋予undefined,未声明则直接报错).返回对象为undefined
2.Null空对象指针,返回对象为OBject,undefined派生于Null,if(undefined == nul) //true
3.Boolean ture/false 区分大小写
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
/*
* 将其他的数据类型转换为Boolean
* - 使用Boolean()函数
* - 数字 ---> 布尔
* - 除了0和NaN,其余的都是true
*
* - 字符串 ---> 布尔
* - 除了空串,其余的都是true
*
* - null和undefined都会转换为false
*
* - 对象也会转换为true
*/
var a = 123; //true
a = -123; //true
a = 0; //false
a = Infinity; //true (无穷大)
a = NaN; //false
//调用Boolean()函数来将a转换为布尔值
a = Boolean(a);
a = " ";
a = Boolean(a);
a = null; //false
a = Boolean(a);
a = undefined; //false
a = Boolean(a);
console.log(typeof a);
console.log(a);
</script>
</head>
<body>
</body>
</html>
4.Number 其中八进制字面量在严格模式下是无效的,导致抛出异常
Number.MAX_VALUE
1.7976931348623157e+308
Number.MIN_VALUE 大于0的最小值
5e-324
Infinity 表示正无穷
-Infinity 表示负无穷
如果使用JS进行浮点运算,可能得到一个不精确的结果
所以千万不要使用JS进行对精确度要求比较高的运算
/*
* 将其他的数据类型转换为Number
* 转换方式一:
* 使用Number()函数
* - 字符串 --> 数字
* 1.如果是纯数字的字符串,则直接将其转换为数字
* 2.如果字符串中有非数字的内容,则转换为NaN
* 3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
* - 布尔 --> 数字
* true 转成 1
* false 转成 0
*
* - null --> 数字 0
*
* - undefined --> 数字 NaN
*
* 转换方式二:
* - 这种方式专门用来对付字符串
* - parseInt() 把一个字符串转换为一个整数
* - parseFloat() 把一个字符串转换为一个浮点数
*/
5.String 可以由单引号或双引号表示, + 号连接字符串 , 用String或toString进行强制转换
将其他的数据类型转换为String
* 方式一:
* - 调用被转换数据类型的toString()方法
* - 该方法不会影响到原变量,它会将转换的结果返回
* - 但是注意:null和undefined这两个值没有toString()方法,
* 如果调用他们的方法,会报错
*
* 方式二:
* - 调用String()函数,并将被转换的数据作为参数传递给函数
* - 使用String()函数做强制类型转换时,
* 对于Number和Boolean实际上就是调用的toString()方法
* 但是对于null和undefined,就不会调用toString()方法
* 它会将 null 直接转换为 "null"
* 将 undefined 直接转换为 "undefined"
6.Object创建对象是后面的()可以省略,但是不推荐。其中Object对象中有以下默认方法:
- Constructor:保存用于创建当前对象的函数Object()
- hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中是否存在,如:o.hasOwnProperty(“name”);
- isPrototypeOf(object)用于检查传入对象是否是另外一个对象的原型
- propertyIsEneumerable(propertyName):用于检查传入的对象是否能够使用for-in语句来枚举
- toLacationString():返回对象的字符串表示,该字符串与执行环节的地区对象
- toString()返回对象的字符串表示
- valueOf()返回对象的字符串、数值或布尔值表示
三、操作符
一元运算符、位操作符、布尔操作符、乘性操作符、加性操作符、关系操作符、相等操作符、条件操作符、赋值操作符、逗号操作符
位运算符
非:
var num1 =25
//二进制00000000000000000000000000011001
var num2 = ~num1:
//二迸制11111111111111111111111111100110
a lert(num2) //-26
与:
var result =25 & 3
alert(result); //1
//同1非0
或:
var result =25 | 13
alert(result); //27
//有一为一
异或(XOR):
同为1,异为0
左移<< 2的几次方倍数 //原理是向左移动n位,后面补0
右移>> 除以2的几次方倍数
关系运算符:
console.log(1 > true); //false
console.log(1 >= true); //true
console.log(1 > "0"); //true
console.log(10 > null); //true
// 任何值和NaN做任何比较都是false
console.log(10 <= "hello"); //false
console.log(true > false); //true
console.log("1" < "5"); //true
console.log("11" < "5"); //true ????
//比较两个字符串时,比较的是字符串的字符编码
console.log("a" < "b");//true
//比较字符编码时是一位一位进行比较
//如果两位一样,则比较下一位,所以借用它来对英文进行排序
console.log("abc" < "bcd");//true
//比较中文时没有意义
console.log("戒" > "我"); //true
//如果比较的两个字符串型的数字,可能会得到不可预期的结果
//注意:在比较两个字符串型的数字时,一定一定一定要转型
console.log("11123123123123123123" < +"5"); //true
相等运算符:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
/*
* 相等运算符用来比较两个值是否相等,
* 如果相等会返回true,否则返回false
*
* 使用 == 来做相等运算
* - 当使用==来比较两个值时,如果值的类型不同,
* 则会自动进行类型转换,将其转换为相同的类型
* 然后在比较
* 不相等
* 不相等用来判断两个值是否不相等,如果不相等返回true,否则返回false
* - 使用 != 来做不相等运算
* - 不相等也会对变量进行自动的类型转换,如果转换后相等它也会返回false
*
*
* ===
* 全等
* - 用来判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换
* 如果两个值的类型不同,直接返回false
* !==
* 不全等
* - 用来判断两个值是否不全等,和不等类似,不同的是它不会做自动的类型转换
* 如果两个值的类型不同,直接返回true
*/
//console.log(1 == 1); //true
var a = 10;
var a = null;
//console.log(a == 4); //false
//console.log("1" == 1); //true
//console.log(true == "1"); //true
//console.log(null == 0); //false
/*
* undefined 衍生自 null
* 所以这两个值做相等判断时,会返回true
*/
//console.log(undefined == null);
/*
* NaN不和任何值相等,包括他本身
*/
//console.log(NaN == NaN); //false
var b = NaN;
//判断b的值是否是NaN
//console.log(b == NaN);
/*
* 可以通过isNaN()函数来判断一个值是否是NaN
* 如果该值是NaN则返回true,否则返回false
*/
// console.log(isNaN(b));
//console.log(10 != 5); //true
//console.log(10 != 10); //false
//console.log("abcd" != "abcd"); //false
//console.log("1" != 1);//false
//console.log("123" === 123);//false
//console.log(null === undefined);//false
console.log(1 !== "1"); //true
</script>
</head>
<body>
</body>
</html>
四、函数
理解函数
普通模式下:
function doAdd(num1, num2 ){I
arguments[1]=10;
alert(arguments [0]+ num2);
}
每次传入参数时,第二的参数都会被修改为10。
严格模式对如何使用arguments对象做出了一些限制。首先,像前面例子中那样的赋值会变得无效。也就是说,即使把 arguments[1]设置为10,num2的值仍然还是 undefined。其次,重写arguments的值会导致语法错误(代码将不会执行)
没有重载
ECMAScript函数不能像传统意义上那样实现重载。而在其他语言(如Java)中,可以为一个函数,编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。
如果在 ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。
function addSomeNumber(num){
return num +100;}
function addsomeNumber(num){
return num +200;}
var result addSomeNumber(100);//300
如前所述,通过检查传入函数中参数的类型和数量并作出不同的反应,可以模仿方法的重载。
模仿重载实现:
function addMethod(object, name, fn)
{
var old = object[name];
object[name] = function()
{
if (fn.length == arguments.length)
return fn.apply(this, arguments);
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
// 不传参数时,返回所有name
function find0()
{
return this.names;
}
// 传一个参数时,返回firstName匹配的name
function find1(firstName)
{
var result = [];
for (var i = 0; i < this.names.length; i++)
{
if (this.names[i].indexOf(firstName) === 0)
{
result.push(this.names[i]);
}
}
return result;
}
// 传两个参数时,返回firstName和lastName都匹配的name
function find2(firstName, lastName)
{
var result = [];
for (var i = 0; i < this.names.length; i++)
{
if (this.names[i] === (firstName + " " + lastName))
{
result.push(this.names[i]);
}
}
return result;
}
function Users()
{
addMethod(Users.prototype, "find", find0);
addMethod(Users.prototype, "find", find1);
addMethod(Users.prototype, "find", find2);
}
var users = new Users();
users.names = ["John Resig", "John Russell", "Dean Tom"];
console.log(users.find()); // 输出[ 'John Resig', 'John Russell', 'Dean Tom' ]
console.log(users.find("John")); // 输出[ 'John Resig', 'John Russell' ]
console.log(users.find("John", "Resig")); // 输出[ 'John Resig' ]
console.log(users.find("John", "E", "Resig")); // 输出undefined
从效果上来说,users对象的find方法允许3种不同的输入: 0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。
难点在于,users.find事实上只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数find0,find1与find2啊!这里的关键在于old属性。
由addMethod函数的调用顺序可知,users.find最终绑定的是find2函数。然而,在绑定find2时,old为find1;同理,绑定find1时,old为find0。3个函数find0,find1与find2就这样通过闭包链接起来了。
根据addMethod的逻辑,当fn.length与arguments.length不匹配时,就会去调用old,直到匹配为止。
五、注意点
1.如果使用类似于C语言的最好始终添加代码块
if(test)
alert(test); //有效但是容易出错
if(test){
alert(test); //推荐使用
}
2.for-in循环
for (var propName in window)(
document.write(propName);}
ECMAScript对象的属性没有顺序。因此,通过for-in循环输出的属性名的顺序是不可预测的。不过所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。
但是,如果表示要迭代的对象的变量值为mu11或 undefined,for-in语句会抛出错误。
ECMAScript5更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。为了保证最大限度的兼容性,建议在使用for-in循环之前,先检测确认该对象的值不是nu11或undefined
3.由于不存在函数签名的特性, ECMAScript函数不能重载。但是可以通过模仿重载的特性,实现重载的效果。