一、基本
1.标识符:
所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则
组合起来的一或多个字符:
第一个字符必须是一个字母、下划线(_)或一个美元符号($);
其他字符可以是字母、下划线、美元符号或数字。
2.语句:
ECMAScript 中的语句以一个分号结尾;如果省略分号,则由解析器确定语句的结尾
虽然语句结尾的分号不是必需的,但我们建议任何时候都不要省略它。因为加上这个分号可以避免很多错误(例如不完整的输入),开发人员也可以放心地通过删除多余的空格来压缩 ECMAScript 代码(代码行结尾处没有分号会导致压缩错误)。另外,加上分号也会在某些情况下增进代码的性能,因为这样解析器就不必再花时间推测应该在哪里插入分号了。
3.变量:
ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。
4.数据类型:
typeof:
鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型——typeof 就是负责提供这方面信息的操作符。
Undefined:
类型只有一个值,即特殊的 undefined。在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined。
undefined 值是派生自 null 值的,因此 ECMA-262 规定对它们的相等性测试要返回 true:
alert(null == undefined); //true
Null:
类型是第二个只有一个值的数据类型,这个特殊的值是 null。从逻辑角度来看,null 值表示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因。
Boolean:
类型是 ECMAScript 中使用得最多的一种类型,该类型只有两个字面值:true 和 false。
数据类型======转换为true的值======转换为false的值
Boolean=======true===============false
String=======任何非空字符串=========""(空字符串)
Number======任何非零数字值(包括无穷大)====0和NaN
Object========任何对象=========null
Undefined========n/a①=========undefined
n/a(或 N/A),是 not applicable 的缩写,意思是“不适用”
Number:
浮点数:
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; // 有效,但不推荐
var floatNum1 = 1.; // 小数点后面没有数字——解析为 1
var floatNum2 = 10.0; // 整数——解析为 10
极大或极小的数值:
可以用 e 表示法(即科学计数法)表示的浮点数值表示,默认情况下,ECMASctipt 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法表示的数值(例如,0.0000003 会被转换成 3e-7)。
访问 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以得到负和正 Infinity 的值。可以想见,这两个属性中分别保存着-Infinity 和Infinity。
NaN:
Not a Number在 ECMAScript中,任何数值除以 0会返回 NaN①,因此不会影响其他代码的执行。NaN 本身有两个非同寻常的特点。首先,任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN,这个特点在多步计算中有可能导致问题。其次,NaN 与任何值都不相等,包括 NaN 本身。
ECMAScript 定义了 isNaN()函数。这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否“不是数值”。isNaN()在接收到一个值之后,会尝试将这个值转换为数值。某些不是数值的值会直接转换为数值,例如字符串"10"或 Boolean 值。而任何不能被转换为数值的值都会导致这个函数返回 true。
5.操作符
一元操作符:前置后置的++和--,以及+和-
位操作符:按内存中表示数值的位来操作数值:
按位非~:操作数的负值减 1(其二进制值全取反)
var num1 = 25; // 二进制 00000000000000000000000000011001
var num2 = ~num1; // 二进制 11111111111111111111111111100110
alert(num2); // -26
按位与&:与上相同,对其二进制变化(按位与操作就是将两个数值的每一位对齐,有一个为0则0,都为1则1)
按位或 | :与上相同,对其二进制变化(按位与操作就是将两个数值的每一位对齐,都为0则0,有一个为1则1)
按位异或^ :与上相同,对其二进制变化(按位与操作就是将两个数值的每一位对齐,一个1一个0则1,否则0)
左移<<: 操作符会将数值的所有位向左移动指定的位数(不改变正负号)
有符号的右移>>: 操作符会将数值的所有位向右移动指定的位数(改变正负号)
无符号的右移>>>:
无符号的右移>>>:
6.语句
do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。
while 语句属于前测试循环语句,也就是说,在循环体内的代码被执行之前,就会对出口条件求值。因此,循环体内的代码有可能永远不会被执行。
label和break continue:
var num = 0; outermost: for (var i=0; i < 10; i++) { for (var j=0; j < 10; j++) { if (i == 5 && j == 5) { continue outermost; } num++; } } alert(num); //95
var num = 0; outermost: for (var i=0; i < 10; i++) { for (var j=0; j < 10; j++) { if (i == 5 && j == 5) { break outermost; } num++; } } alert(num); //55
7.垃圾收集
JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
1:JavaScript 中最常用的垃圾收集方式是标记清除(mark-and-sweep)
当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。
2:另一种不太常见的垃圾收集策略叫做引用计数(reference counting)。引用计数的含义是跟踪记录每个值被引用的次数。
问题:循环引用。循环引用指的是对象 A 中包含一个指向对象 B 的指针,而对象 B 中也包含一个指向对象 A 的引用
8.有对函数声明和函数表达式加以区别
解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
alert(sum(10,10)); function sum(num1, num2){ return num1 + num2; } 以上代码完全可以正常运行。因为在代码开始执行之前,解析器就已经通过一个名为函数声明提升 (function declaration hoisting)的过程,读取并将函数声明添加到执行环境中。对代码求值时,JavaScript 引擎在第一遍会声明函数并将它们放到源代码树的顶部。所以,即使声明函数的代码在调用它的代码后 面,JavaScript 引擎也能把函数声明提升到顶部。
但:把上面的函数声明改为等价的函数表达式,就会在执行期间导致错误。
alert(sum(10,10)); var sum = function(num1, num2){ return num1 + num2; }; 以上代码之所以会在运行期间产生错误,原因在于函数位于一个初始化语句中,而不是一个函数声 明。换句话说,在执行到函数所在的语句之前,变量 sum 中不会保存有对函数的引用;而且,由于第一 行代码就会导致“unexpected identifier”(意外标识符)错误,实际上也不会执行到下一行。 除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的。
9.当作值的函数
可以从一个函数中返回另一个函数,而且这也是极为有用的一种技术
function createComparisonFunction(propertyName) { return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { return 0; } }; }
var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
data.sort(createComparisonFunction("name"));
alert(data[0].name); //Nicholas
想要根据某个对象属性对数组进行排序。而传递给数组 sort()方法的比较函数要接收
两个参数,即要比较的值。可是,我们需要一种方式来指明按照哪个属性来排序。要解决这个问题,
可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数
argument.callee
function factorial(num){ if (num <=1) { return 1; } else { return num * factorial(num-1) } } arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。 function factorial(num){ if (num <=1) { return 1; } else { return num * arguments.callee(num-1) } }
每个函数都包含两个非继承而来的方法:apply()和 call()。这两个方法的用途都是在特定的作
用域中调用函数,实际上等于设置函数体内 this 对象的值。
call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。
call()方法时,传递给函数的参数必须逐个列举出来,apply是参数数组。
事实上,传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。下面来看一个例子。 window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } sayColor(); //red sayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blue
使用 call()(或 apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。
bind:
ECMAScript 5 还定义了一个方法:bind()。这个方法会创建一个函数的实例,其 this 值会被绑 定到传给 bind()函数的值。例如: window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } var objectSayColor = sayColor.bind(o); objectSayColor(); //blue
10.前面我们已经介绍了大多数内置对象,例如 Object、Array 和 String。ECMA-262 还定义了两个单体内置对象:Global 和 Math。
Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。
一般来说,我们使用 encodeURIComponent() 方法的时候要比使用
encodeURI()更多,因为在实践中更常见的是对查询字符串参数而不是对基础 URI
进行编码。
与 encodeURI()和 encodeURIComponent()方法对应的两个方法分别是 decodeURI()和
decodeURIComponent()。
11.最后一个——大概也是整个 ECMAScript 语言中最强大的一个方法:eval()
eval()方法就像是一个完整的 ECMAScript 解析器,它只接受一个参数,即要执行的 ECMAScript(或 JavaScript)字符串。
诗和远方success