本文记录了我在学习前端上的笔记,方便以后的复习和巩固。
3.1.4 严格模式
严格模式是JavaScript
定义了一种不同的解析和执行模型。在严格模式下ECMAScript3中的一些不确定行为将得到处理,而且对某些不安全的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:
"use strict";
这段代码看起来像字符串,而且也没赋值给任务变量,但其实它是一个编译指示(pragma),用于告诉支持的JavaScript引擎切换到严格模式。这是为不破坏ECMAScript3而特意选定的语法。
在函数内部的上方包含这条编译提示,也可以指定函数在严格模式下执行:
function doSomething() {
"use strict";
//函数体
}
3.2 关键字和保留字
ECMAScript5关键字:
break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with
ECMAScript5非严格模式保留字:
class、enum、extends、super、const、export、import
在严格模式下,第5版还对一下保留字施加了限制:
implements、package、public、interface、private、static、let、protected、yield
3.3 变量
局部变量被函数调用后,当前函数退出后就会被销毁,例如:
function test(){
var message = "hi"; //局部变量
}
test();
alert(message); //错误
全局变量就不会:
function test(){
message = "hi"; //全局变量
}
test();
alert(message); // "hi"
这样,只要调用过一次test()函数,这个变量就有了定义,就可以在函数外部任何地方被访问到。但全局变量的做法不推荐。因为在局部作用域中定义的全局变量很难维护。严格模式
下不能定义名为eval
或arguments
的变量,否则会导致语法错误。
3.4 数据类型
ECMAScript中有五种简单数据类型:
Undefined
Null
Boolean
Number
String
还有一种复杂数据类型——Object
注意:ECMAScript6还新增了一种数据类型符号对象 -
(Symbol)
- 符号对象简介
3.4.1 typeof操作符
用于检测给定变量的数据类型——typeof
就是负责提供这方面信息的操作符。对一个值使用typeof
操作符可能返回下列某个字符串:
"undefind"——如果这个值未定义;
"boolean"——如果这个值是布尔值;
"string"——如果这个值是字符串;
"number”——如果这个值是数值;
"object" ——如果这个值是对象或null;
"function"——如果这个值是函数
下面是几个使用typeof操作符的例子:
var message = "some string";
alert(typeof message); //"string"
alert(typeof (message)); //"string"
alert(typeof 95); //"number"
注意:调用typeof null 会返回 "object",因为特殊值null被认为是一个空的对象引用。
3.4.2 Undefind类型
Undefined
类型只有一个值即undefind
。在使用var声明变量后但未对其加以初始化时,这个变量的值就是undefined
,例如:
var message;
alert(message == undefined); //true
var message1 == undefined
alert(message1 == undefined); //true
typeof操作符对未初始化和未声明的变量都返回undefined
3.4.3 Null类型
Null
类型是第二个只有一个值的数据类型,这个特殊的值是null
。从逻辑角度看,null
值表示一个空对象指针,而这也正是使用typeof
操作符检测null值会返回"object"
的原因
var car = null;
console.log(typeof car); //"object"
如果定义的变量是为了以后要保存对象,那么最好该变量初始化为null值。
if(car != null){
//对car对象执行某些操作
}
undefined值是派生自null的值得所以:
console.log(null == undefined); //true
3.4.4 Boolean类型
该类型只有两个字面值: true
和false
。
虽然Boolean
类型只有两个字面值,但是可以调用Boolean()函数把值转换为对应的Boolean值:
var message = "Hello World!";
var messageAsBoolean = Boolean(message);
转换规程:
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | n/a | undefined |
3.4.5 Number类型
//十进制
var intNum = 55; //整数
//八进制
var octalNum1 = 070;//八进制56
var octalNum1 = 079;//无效的八进制数值——解析为79
var octalNum1 = 08;//无效的八进制数组——解析为8
//十六进制
var hexNum1 = 0xA; //十六进制的10
var hexNum2 = 0x1f; //十六进制的31
八进制:第一位必须是零(0),然后是八进制数字序列(0~7).如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值当成十进制解析。
十六进制:前两位必须是0x,后跟任何十六进制数字(0~9,A~F)。
注意:在算数计算时,所有的八进制和十六进制表示的数值最终都将被转换成十进制。
1.浮点数值
浮点数值中必须包含个小数点
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1 //有效但不推荐
由于保存浮点数值需要的空间是整数数值的两倍,因此ECMAScript会不失时机的将浮点数值转换成整数值。
var floatNum1 = 1.; //小数点后面没有数字——解析为1
var floatNum2 = 10.0 //整数——解析为10
对于极大或极小的数值,可以用e表示法。
var floatNum = 3.125e7; //31250000
浮点数值最高精度是17位小数,但在进行算数计算时它的精度远远不如整数。例如0.1加0.2不是0.3 ,而是0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值。例如:
if(a + b == 0.3){ //不要这样做测试
alert("You got 0.3");
}
在这个例子中如果两个数是0.05和0.25或者是0.15和0.15都不会有问题。因此永远不要测试某个特定的浮点数值。
3.NaN
NaN,既非数值,是这个特殊的数值,这个数值用于表示一个本来要返回的数值的操作数未返回数值的情况(这样就不会抛出错误了)。
NaN本身有两个非同寻常的特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN。其次NaN与任何值都不想等,包括NaN本身。例如:
console.log(NaN == NaN); //false
针对NaN这两个特点,ECMAScript定义了isNaN()函数。这个函数接受一个参数,该参数可以是任何类型,2️⃣函数会帮我们确定这个参数是否"不是数值"。
isNaN()接受到第一值后,会尝试将这个值转换为数值。任何不能被转换的数值的值都会导致这个函数返回true。例如:
console.log(isNaN(NaN)); //true
console.log(isNaN(10)); //false(10是一个数值)
console.log(isNaN("10")); //false(可以被转换成数值10)
console.log(isNaN("blue")); //true(不能转换成数值)
console.log(isNaN(true)); //flase(可以被转换成数值1)
isNaN
也适用于对象,在基于对象调用isNaN()
函数时,会首先调用valueOf()
方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用toString()方法
,再测试返回值
4.数值转换
有3分函数可以把非数值转换为数值:
Number()
——可用于任何数据类型parseInt()
——专门用于把字符串转换成整数数值parseFloat()
——专门用于把字符串转换成浮点数值
Number()函数的转换规则如下
如果是
Boolean
值,true
和false
将分别被转换为1和0.如果是数字值,只是简单的传入和返回
如果是
null
值,返回0如果是
undefined
,返回NaN
var num1 = Number("Hello world!"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); //11
var num4 = Number("true"); //1
parseInt()
由于Number()
在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的事parseInt()
函数。
var num1 = parseInt("1234bule"); //1234
var num2 = parseInt(""); //NaN
var num3 = parseInt("0xA"); //10(十六进制数)
var num4 = parseInt("22.5"); //22
var num5 = parseInt("070"); //56(八进制数)
var num6 = parseInt("70"); //70(十进制数)
var num7 = parseInt("0xf"); //15(十六进制数)
//在ES3和ES5存在分歧。例如:
var num = parseInt("070"); //ES3认为是56(八进制) ES5认为是70(十进制)
//parseInt()函数有第二个参数:转换时使用的基数(进制)
var num = parseInt("0xAF", 16) //175(按十六进制解析)
//使用了16进制参数,字符串可以不带0x
var num1 = parseInt("AF", 16) //175
var num1 = parseInt("AF") //NaN
不知道基数意味着让
parseInt()
决定如何解析字符串,因此为了避免错误的解析,建议无论在什么情况都明确指定基数。
parseFloat()
var num1 = parseFloat("123bule"); //1234(整数)
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.125e7"); //31250000
3.4.6 String类型
1.字符字面量
String
数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其他用途的字符。
2.字符串的特点
ECMAScript中的字符串是不可变的,也就是说,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后在用另一个包含新值得字符串填充该变量例如:
var lang = "Java";
lang = lang + "Script"; //JavaScript
3.转换为字符串
toString()方法
var age = 11;
var ageAsString = age.toString; //字符串"11";
var found = true;
var foundAsString = found.toString; //字符串"true";
数值、布尔值、对象、字符串值都有toString()
方法。但null
和undefined
值没有这个方法。toString()
方法也跟上面的parseInt()
方法类似一样有一个参数:输出数值的基数;
var num = 10;
console.log(num.toString()); //"10"
console.log(num.toString(2)); //"1010"
console.log(num.toString(8)); //"12"
console.log(num.toString(10)); //"10"
console.log(num.toString(16)); //"a"
在不知道要转换的值是不是null或undefined的情况下,还可以使用转型函数String(),这个函数能够将任何类型的值转换成字符串。String()函数遵循下列转换规则:
如果值有toString()方法,则调用该方法(没有参数)并返回相应的结果;
如果值是null,则返回"null";
如果值是undefined,则返回"undefined"。
下面看几个例子:
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
console.log(String(value1)); //"10"
console.log(String(value2)); //"true"
console.log(String(value3)); //"null"
console.log(String(value4)); //"undefined"
3.4.7 Object类型
ECMAScript
中的对象其实就是一组数据和功能的集合。对象可以通过执行new
操作符后跟要创建的对象类型的名称来创建。而创建Object
类型的实例并为其添加属性和方法,就可以创建自定义对象,如下所示:
var o = new Object();
如果不给构造函数传递参数,则可以省略后面的括号,但是这做法不推荐
var o = new Object; //有效,但不推荐省略圆括号
仅仅创建Object
的实例并没有什么用处,但关键是要理解一个重要的思想:即在ECMAScript
中,Object
类型是所有它的实例的基础。换句话说,Object
类型所具有的任何属性和方法也同样存在于更具体的对象中。
Object的每个实例都具有下列属性和方法:
constructor:保存着用于创建当前对象的函数。对于前面的例子而已,
构造函数(constructor)
就是Object()
;返回一个指向创建了该对象原型的函数
引用。该属性的值就是那个函数本身
。hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在,其中,作为参数的
属性名(propertyName)
必须以字符串的形式指定例如:o.hasOwnProperty("name");
isPrototypeOf(Object):用于检查传入的对象是否是当前对象的原型
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用
for-in
语句来枚举。与hasOwnProperty()
方法一样,作为参数的属性名必须以字符串形式指定。toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值、或布尔值表示。通常与
toString()方法
的返回值相同。
由于在ECMAScript
中Object
是所有对象的基础,因此所有对象都具有这些基本的属性和方法。
3.5 操作符
ECMA-262
描述了一组用于操作数据值的操作符,包括算数操作符(如加号和减号)、位操作符、关系操作符和相等操作符。ECMAScript
操作符的与众不同之处在于,它们能够使用于很多值,例如字符串、数字值、布尔值、甚至对象。不过在应用于对象时,相应的操作符通常都会调用对象的valueOf()
和(或)toString()
方法,以便取得可以操作的值。
3.5.1 一元操作符
1.递增和递减操作符
执行前置递增和递减操作时,变量的值都是在语句被求值以前改变的。
var age = 29;
var anotherAge = --age + 2;
console.log(age); //28
console.log(anotherAge); //30
由于前置递增和递减操作与执行语句的优先级相等,因此整个语句会从左至右被求值。
var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2;//21
var num4 = num1 + num2; //21
num4相应的加法操作使用了num减去1之后的值
后置递增和递减操作符语法不变,他们的区别就是前置递增和递减被操作时变量的值都是在语句被求值以前改变的。而后置是求值之后才执行的。
把递增操作符放在后面并不会改变语句的结果。
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2;//22
var num4 = num1 + num2; //21
递增和递减操作符对任何值都使用,字符串,布尔值,浮点数值,对象
3.5.3 布尔操作符
1.逻辑非
逻辑非操作符由一个叹号( ! )表示,可以应用于ECMAScript
中的任何值。无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将她的操作数转换为一个布尔值,然后再对其求反。
逻辑非操作符也可以用于将一个值转换为与其对应的布尔值。而同时使用两个逻辑非操作符。实际上就会模拟Boolean()
转型函数的行为。其中,第一个逻辑非操作会基于无论什么操作数返回一个布尔值,而第二逻辑非操作则对该布尔值求反,于是就得到了这个值正对应的布尔值。当然,最终的结果与对这个值使用Boolean()
相同
2.逻辑与
逻辑与操作符由两个和号(&&)表示,有两个操作数,如下面的例子所示:
var result = true && false;
逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值;此时它遵循下列规则:
如果第一个操作数是对象,则会返回第二个操作数;
如果第二个操作数是对象,则只有在第一个操作数的求值结果为
true
的情况下才会返回该对象;如果两个操作数都是对象,则返回第二个操作数;
如果有一个操作数是
null
,则返回null
;如果有一个操作数是
NaN
,则返回NaN
;如果有一个操作数是
undefined
,则返回undefined
。
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。对于逻辑与而言,如果第一个操作数是false
,则无论第二个操作数是什么值,结果都不再可能是true
了。例子:
var found = true;
var result = (found && someUndefinedVariable) //这里会发生错误
alert(result) 这一行不会执行
上面例子发生错误,因为变量someUndefinedVariable
没有声明。由于变量found
的值是true
,所以逻辑与操作符会继续对变量someUndefinedVariable
求值。所以逻辑与操作符会继续对变量someUndefinedVariable
求值。但someUndefinedVariable
没定义所以就导致错误。将found的值设置为false,就不会发生错误了。
3.逻辑或
逻辑或操作符由两个和号(||)表示,有两个操作数,如下面的例子所示:
var result = true || false;
与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值;此时它遵循下列规则:
如果第一个操作数是对象,则会返回第一个操作数;
如果第一个操作数的求值结果为
false
,则返回第二个操作数。如果两个操作数都是对象,则返回第一个操作数;
如果有两个操作数是
null
,则返回null
;如果有两个操作数是
NaN
,则返回NaN
;如果有两个操作数是
undefined
,则返回undefined
。
与逻辑与操作符相似,逻辑或操作符也是短路操作符。如果第一个操作数的求值结果为true,就不会对第二个操作值求值了,跟逻辑与是相反的。
3.5.6
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)
与ECMAScript
中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。一下就是相应的规则。
如果两个操作符都是数值,则执行数值比较;
如果两个操作数都是字符串,则比较两个字符串对应的字符编码值;
如果一个操作数是数值,则另一个操作数转换为一个数值,然后执行数值比较;
如果一个操作数是对象,则调用这个对象的
valueOf()
方法,并用得到的结果根据前面的规则执行比较。如果对象没有valueOf()
方法,则调用toString()
方法,并用得到的结果根据前面的规则执行比较;如果一个操作数是布尔值,则将他转换为数值,然后执行比较。
任何数与
NaN
比较都返回false
3.5.7 相等操作符
1.相等和不相等
== 两个数相等 返回true
!= 两个数不相等 返回ture
要比较相等性之前,不能将null和undefined转换成其他任何值。
如果两个操作数都是对象,则比较它们是不是同一个对象,如果两个操作数都指向同一个对象则true,不是则false;
注意:
null
和undefined
是相等的,NaN
不等于NaN
2.全等和不全等
全等和相等类似,两者最大区别是全等比较时不转换成数值。
全等和不全等的比较都是在操作数未经转换的情况下比较。
注意:
null == undefined
返回true
,因为他们类似的值;但null === undefined
返回false
,因为他们是不同类型的值
3.5.8 条件操作符
variable = boolean_expression ? true_value : false_value;
var max = (num1 > num2) ? num1 : num2;
3.6语句
3.6.1 if语句
if(condition) statement1 else statement2
if(i > 25) {
alert("Greater than 25.");
}else{
alert("Less than of equal to 25.");
}
3.6.2 do-while
var i = 0;
do {
i+=2;
}while(i < 10);
console.log(i);
3.6.3 while
var i = 0;
while(i < 10) {
i += 2;
}
3.6.4 for 语句
var count = 10;
for(var i = 10; i < count; i++){
console.log(i);
}
由于ECMAScript中不存在块级作用于,因此在循环内部定义的变量也可以在外部访问到。
注意:
for语句
中的初始化表达式、控制表达式和循环后表达式都是可选的。将这三个表达式全部省略,就会创建一个无限循环。
3.6.5 for-in语句
var data = [1,3,2,4,5];
for(var propName in data){
console.log(data[propName]); //1,3,2,4,5
console.log(propName); //0,1,2,3,4
}
for(var propName in window){
console.log(propName); //window对象属性名
}
注意:ECMAScript对象属性没有顺序。因此通过for-in循环输出的属性名的顺序是不可预测的。
注意:建议在使用for-in之前,先检测确认该对象的值不是null或undefined。
3.6.6 label语句
使用label
语句可以再代码中添加标签,以便将来使用。
start: for (var i = 0; i < count; i++){
alert(i);
}
这个例子中定义的start标签可以在将来有break
或continue
语句引用。加标签的语句一般都要与for语句等循环语句配合使用
3.6.7 break和continue语句
break:
var num = 0;
for(var i = 1; i < 10; i++){
if(i % 5 == 0){
break;
}
num++;
}
console.log(num); //4
continue:
var num = 0;
for(var i = 1; i < 10; i++){
if(i % 5 == 0){
continue;
}
num++;
}
console.log(num); //8
label可以和break和continue:
var num = 0;
outermost: //循环外标签
for(var i = 1; i < 10; i++){
for(var j= 0; j < 10; j++){
if(i == 5 && j == 5){
//正常来说break只能跳出一层循环,但外面使用了label语句的标签outrmost可以直接跳出全部循环到outermost的位置;
break outermost;
}
num++;
}
}
console.log(num); //55
3.6.8 with语句
with
语句的作用是将代码的作用域设置到一个特定的对象中。with
语句的语法如下:
with (expression) statement;
定义with语句的目的主要是为了简化多次编写同一个对象的工作,如下:
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = localion.href;
上面几行代码都包括location
对象。如果使用with
语句如下:
width(location){
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
注意:严格模式不允许使用
with
语句,会视为语法错误。with
语句大量使用会导致性能下降,同时也会给调试代码造成困难,因此在开发大型项目时,不建议使用with
语句
3.6.9 switch语句
var num = 25;
switch (true){
case num < 0:
console.log("0");
break;
case num >= 0 && num <= 10:
console.log("0");
break;
default:
console.log("0");
}
注意:
switch
语句在比较值时使用的是全等操作符。
3.7 函数
return语句也可以不带任何返回值。在这种情况下,函数在停止执行后将返回undefined值。
推荐做法:是要么让函数使用都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候不反回,会给调试代码带来不便
3.7.1 理解参数
在函数体内可以使通过arguments
对象来访问这个参数的数组,从而获取传递给函数的每一个参数。
通过访问argments
对象的length
属性可以获知有多少个参数传递给了函数
function doAdd(num1,num2){
arguments[1] = 10;
console.log(arguments[1]); //10
console.log(num2); //10
console.log(arguments[0] + num2); //20
console.log(arguments.length); //2 也可以访问arguments对象的length属性可以获取有多少个参数传递给函数
}
doAdd(10,20);
每次执行这个doAdd()
函数都会重写第二参数,将第二个参数的值修改为10
。因为arguments
对象中的值会自动反映到对应的命名函数,所以修改arguments[1]
,也就修改了num2
,结果它们的值都会变成10
,不过,这并不是说读取这个两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。你也可以反过来修改num2
的值效果也是一样的。
function doAdd(num1,num2){
num2 = 10;
console.log(arguments[1]); //10
}
doAdd(10,20);
arguments对象可以与命名参数一起使用,如:
function doAdd(num1, num2){
if(arguments.length == 1){
console.log(num1 + 10)
}else{
console.log(argments[0] + num2);
}
}
arguments
对象只是与数组类似(它并不是Array
的实例).arguments
的值永远与对应命名参数的值保持同步没有传递值得命名参数将自动被赋予
undefined
值。
严格模式下不允许重写命名参数或者
arguments
的值,虽然可以执行,但是命名参数与arguments
对应的值将不再同步
3.7.2 没有重载
ECMAScript
函数没有签名,因为其参数是由包括零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。
最后,如有错误和疑惑请指出,多谢各位大哥
如果在ECMAScript
中定义了两个名字相同的函数,则该名字只属于后定义的函数。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。