高程笔记一
JavaScript 是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
ECMAScript,由 ECMA-262 定义,提供核心语言功能;
文档对象模型(DOM),提供访问和操作网页内容的方法和接口;
浏览器对象模型(BOM),提供与浏览器交互的方法和接口。
JavaScript 的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari 和 Opera)中都得到了不同程度的支持。其中,所有浏览器对 ECMAScript 第 3 版的支持大体上都还不错,而对ECMAScript 5 的支持程度越来越高,但对 DOM 的支持则彼此相差比较多。对已经正式纳入 HTML5 标准的 BOM 来说,尽管各浏览器都实现了某些众所周知的共同特性,但其他特性还是会因浏览器而异。
<script>定义了下列 6 个属性。
async:可选。表示应该立即下载脚本,但不应妨碍页面中的其他操作, 比如下载其他资源或等待加载其他脚本。只对外部脚本文件有效。
charset:可选。表示通过src属性指定的代码的字符集。由于大多数浏览器会忽略它的值,因此这个属性很少有人用。
defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。 只对外部脚本文件有效。IE7 及更早版本对嵌入脚本也支持这个属性。
language:已废弃。原来用于表示编写代码使用的脚本语言(如JavaScript、JavaScript1.2或VBScript)。大多数浏览器会忽略这个属性,因此也没有必要再用了。
src:可选。表示包含要执行代码的外部文件。
type:可选。可以看成是language的替代属性;表示编写代码使用的脚本语言的内容类型(也称为 MIME 类型)。虽然 text/javascript 和 text/ecmascript 都已经不被推荐使用,但人们一直以来使用的都还是text/javascript。实际上,服务器在传送JavaScript文件时使用的MIME类型通常是application/x–javascript,但在type中设置这个值却可能导致脚本被忽略。另外,在非IE浏览器中还可以使用以下值:application/javascript和application/ecmascript。考虑到约定俗成和最大限度的浏览器兼容性,目前type属性的值依旧还是text/javascript。不过,这个属性并不是必需的,如果没有指定这个属性,则其默认值仍为text/javascript
XHTML运行script
1 | <script type="text/javascript"><![CDATA[ |
html文档模式
标准模式
1 | <!-- HTML 4.01 严格型 --> |
非标准模式
1 | <!-- HTML 4.01 过渡型 --> |
ECMAScript 中有 5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number
和 String。
3 个函数可以把非数值转换为数值:Number()、parseInt()和parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这 3 个函数对于同样的输入会有返回不同的结果。
Number()函数的转换规则如下。
如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
数值转换
有 3 个函数可以把非数值转换为数值:Number()、parseInt()和 parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这3个函数对于同样的输入会有返回不同的结果。Number()函数的转换规则如下。
如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
如果是字符串,遵循下列规则:
如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即”1”会变成1,”123”会变成123,而”011”会变成11(注意:前导的零被忽略了);
如果字符串中包含有效的浮点格式,如”1.1”,则将其转换为对应的浮点数值 同样,也会忽略前导零);
如果字符串中包含有效的十六进制格式,例如”0xf”,则将其转换为相同大小的 十进制整数值;
如果字符串是空的(不包含任何字符),则将其转换为 0;
如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。根据这么多的规则使用Number()把各种数据类型转换为数值确实有点复杂。下面还是给出几个具体的例子吧。
var num1 = Number(“Hello world!”); //NaN
var num2 = Number(“”); //0
var num3 = Number(“000011”); //11
parseInt
1 | var num1 = parseInt("10", 2); //2 (按二进制解析) |
parseFloat
1 | var num1 = parseFloat("1234blue"); //1234 (整数) |
字符String
1 | \n 换行 |
求模运算
求模(余数)操作符由一个百分号(%)表示,用法如下:
var result = 26 % 5; // 等于 1
与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
如果操作数都是数值,执行常规的除法计算,返回除得的余数;
如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
如果被除数是有限大的数值而除数是零,则结果是 NaN;
如果是 Infinity 被 Infinity 除,则结果是 NaN;
如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
如果被除数是零,则结果是零;
如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
减法
1 | var result1 = 5 - true; // 4,因为 true 被转换成了 1 |
全等和不全等
记住:null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值
每个主要算术操作符(以及个别的其他操作符)都有对应的复合赋值操作符。这些操作符如下所示:
1 | 乘/赋值(*=); |
for-in语句
1 | for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。以下是 for-in 语句的语法: |
ECMAScript 对象的属性没有顺序。因此,通过 for-in 循环输出的属性名的顺序是不可预测的。
具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。
js没有重载
ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。
基本类型和引用类型的值
ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。第 3 章讨论了 5 种基本数据类型:Undefined、Null、Boolean、Number 和 String。这 5 种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的①。
在 Web 浏览器中,全局执行环境被认为是 window 对象
数组的栈方法
1 | var colors = new Array(); // 创建一个数组 |
数组的重排序方法
1 | 数组中已经存在两个可以直接用来重排序的方法:reverse()和 sort()。有读者可能猜到了, |
数组的splice
1 | var colors = ["red", "green", "blue"]; |
数组迭代方法
1 | every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。 |
数组的归并方法
这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值。传给reduce()和 reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。
1 | 使用 reduce()方法可以执行求数组中所有值之和的操作,比如: |
js没有重载(深入理解)
将函数名想象为指针,也有助于理解为什么 ECMAScript 中没有函数重载的概念。以下是曾在第 3
章使用过的例子。
函数声明与函数表达式
本节到目前为止,我们一直没有对函数声明和函数表达式加以区别。而实际上,解析器在向执行环
境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行
任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真
正被解释执行。
1 | alert(sum(10,10)); |
作为值的函数
1 | function callSomeFunction(someFunction, someArgument){ |
递归
1 | function factorial(num){ |
函数的apply和bind
每个函数都包含两个非继承而来的方法:apply()和 call()。这两个方法的用途都是在特定的作
用域中调用函数,实际上等于设置函数体内 this 对象的值。首先,apply()方法接收两个参数:一个
是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是
arguments 对象。例如:
1 | function sum(num1, num2){ |
call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call()
方法而言,第一个参数是 this 值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用
call()方法时,传递给函数的参数必须逐个列举出来,如下面的例子所示。
1 | function sum(num1, num2){ |
能够扩充函数赖以运行的作用域
1 | window.color = "red"; |
ECMAScript 5 还定义了一个方法:bind()。这个方法会创建一个函数的实例,其 this 值会被绑
定到传给 bind()函数的值。例如:
1 | window.color = "red"; |
基本包装类型
ECMAScript 还提供了 3 个特殊的引用类型:Boolean、Number 和String。
Object 构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。例如:
var obj = new Object(“some text”);
alert(obj instanceof String); //true
Number 类型还提供了一些用于将数值格式化为字符串的方法。
其中,toFixed()方法会按照指定的小数位返回数值的字符串表示,例如:
var num = 10;
alert(num.toFixed(2)); //“10.00”
toFixed()方法可以表示带有 0 到 20 个小数位的数值。但这只是标准实现的范
围,有些浏览器也可能支持更多位数
var num = 10;
alert(num.toExponential(1)); //“1.0e+1”
以上代码输出了”1.0e+1”;不过,这么小的数值一般不必使用 e 表示法。如果你想得到表示某个
数值的最合适的格式,就应该使用 toPrecision()方法。
var num = 99;
alert(num.toPrecision(1)); //“1e+2”
alert(num.toPrecision(2)); //“99”
alert(num.toPrecision(3)); //“99.0”
string截取
1 | var stringValue = "hello world"; |
在传递给这些方法的参数是负值的情况下,它们的行为就不尽相同了。其中,slice()方法会将传入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0。最后,substring()方法会把所有负值参数都转换为 0。下
1 | var stringValue = "hello world"; |
字符串位置方法
var stringValue = “hello world”;
alert(stringValue.indexOf(“o”, 6)); //7
alert(stringValue.lastIndexOf(“o”, 6)); //4
Global对象
诸如 isNaN()、isFinite()、parseInt()以及 parseFloat(),实际上全都是 Global对象的方法。除此之外,Global 对象还包含其他一些方法。
Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource
Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如
空格。而这两个 URI 编码方法就可以对 URI 进行编码,它们用特殊的 UTF-8 编码替换所有无效的字符,
从而让浏览器能够接受和理解。
encodeURI()主要用于整个URI(例如,http://www.wrox.com/illegalvalue.htm),而encodeURIComponent()主要用于对URI 中的某一段(例如前面URI中的illegal value.htm)进行编码。它们的主要区别在于,encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。
1 | var uri = "http://www.wrox.com/illegal value.htm#start"; |
与 encodeURI()和 encodeURIComponent()方法对应的两个方法分别是 decodeURI()和
decodeURIComponent()。
eval()方法
在 eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字
符串中;它们只在 eval()执行的时候创建
window 对象
另一种取得 Global 对象的方法是使用以下代码:
var global = function(){
return this;
}();
Math对象
1 | 要找到数组中的最大或最小值,可以像下面这样使用 apply()方法。 |
Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课
上学到的舍入规则)
1 | function selectFrom(lowerValue, upperValue) { |
js引用类型
1 | 对象在 JavaScript 中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象, |