[关闭]
@yacent 2016-07-22T09:46:06.000000Z 字数 10613 阅读 894

JavaScript 高级程序设计

JavaScript


@author: Nichokas C.Zakas 尼古拉斯 泽卡斯


Chapter 1 intruduction of JavaScript

JavaScript 是一种专为与网页交互而设计的脚本语言,由以下三部分组成

  • ECMAScript 由ECMA-262定义,提供核心语言功能
  • DOM 提供访问和操作网页内容的方法和接口
    • DOM1: 由DOM核心(DOM Core) 和 DOM HTML构成
    • DOM2: 添加了新的类型和接口,如DOM事件接口,DOM样式等
    • DOM3: 引入统一方式加载和保存文档,增加验证文档的方法
  • BOM 提供与浏览器交互的方法的和接口

Chapter 2 The usage of the JS in HTML

<script> 元素的 属性

  • async: 表示应该立即下载脚本,但不妨碍页面中的其他操作,即异步
  • charset: 表示通过src属性指定的代码的字符集
  • defer: 表示脚本可以延迟到文档完全被解析和显示之后再执行
  • src: 表示包含执行代码的外部文件
  • type: 表示编写代码使用的脚本语言的内容类型(也成为MIME类型)
    常用: <script type="text/javascript" src=""></script>
    实际上,服务器在传送JavaScript文件时使用的MIME类型为application/x-javascript,但在type中设置这个值可能会导致脚本被忽略。
    所以默认的type值还是text/javascript

<script> 元素,若src属性存在,即链接外部文件,则<script></script>标签之间不应该存在别的JavaScript代码,其会被 忽略

<script> 元素,放置位置,应该在<body> 底部,这样可以加快网页加载速度。若放在<head> 头上,则需要解析完所有的JavaScript代码之后才进行页面的呈现。当然,也可以用<script> 自带的属性defer进行脚本延迟。即先下载,后等页面呈现完之后才执行脚本<script type="text/javascript" defer="defer" src=""></script>,但不推荐这种做法,推荐将标签直接放在body底部

<script>元素的async 属性,不让页面等待脚本下载和执行,从而异步加载页面其他内容,但是async 属性并不能保证不同脚本之间的执行顺序,所以各个脚本之间必须是无依赖关系的。

通过外部文件调用JS的好处如下

  • 可维护性
  • 可缓存 (如果不同的js文件放在同一个文件夹中,浏览器会根据路径对同一个文件夹的内容只下载一次,此能加快页面加载的速度)
  • 适应未来

<noscript> 元素的作用: 可以指定在不支持脚本的浏览器中显示其替代内容,实现JavaScript的平稳退化。

使用条件(二者有一即可)

  • 浏览器不支持脚本
  • 浏览器支持脚本,但禁用了
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>How to use NoScript</title>
  6. <script type="text/javascript" src=""></script>
  7. <script type="text/javascript" src=""></script>
  8. </head>
  9. <body>
  10. <noscript>
  11. <p>本页面需要浏览器支持(启用)JavaScript</p>
  12. </noscript>
  13. </body>
  14. </html>

Chapter3 basic conceptions

语句结尾使用 分号 的原因:

  • 代码压缩的时候不会出错(代码压缩会将多余空格去除)
  • 提供解析器性能,不必花时间推测哪里应插入分号

基本数据类型

Undefined Null Boolean Number String Object (引用类型值)

null:空对象指针, typeof null -> object

Number

  • 浮点数, 0.1 + 0.2 结果为0.30000000000000004,而不是0.3,故永远不要测试某个特定的浮点数值,因为754标准会产生舍入误差
  • Number.isFinite()用于检测参数是否位于MIN与MAX之间
  • NaN
    • 任何NaN的操作(NaN/10)都会返回NaN
    • NaN与任何值都不相等,包括其自己
    • 检测是否为NaN, 用isNaN(),其会将参数先尝试转换为数值[ valueOf()、toString() ]
  • 数值转换:将非数值转换为数值
    • Number() 参数接受任何数据类型
      • boolean,true 和false分别转换为 1 和 0
      • null值 返回 0
      • undefined 返回 NaN
      • 字符串
        • 空字符串 返回 0
        • 忽略前导0,其后必须全为数字
    • parseInt() 专门将字符串转换成数值
      • 第一个字符不为数字字符或者负号,则为NaN
      • 接受两个参数 parseInt(number, radix)
    • parseFloat() 专门将字符串转换成数值

String

  • 将值转换为字符串的两种方式
    • toString() 除Undefined null 外,都有toString()方法
    • String() 其会检测变量是否有toString()方法,有则调用并输出,无则单纯输出其字面量,对undefined 和 null 也适用

Object

第五章详细描述


操作符

  • 一元操作符
    • 一元 + / - 操作符, 相当于Number()的功能 eg: +"1.1" -> 1.1
  • 位操作符(~ 非 & 与 | 或 ^ 异或 << 算术左移(补0) >> 算术右移(补 符号位) >>> 逻辑右移(补0))
  • 关系操作符
    • 字符串比较的时候,是对应位置的每个字符的字符编码值
    • 任何数与 NaN 进行比较,结果都返回false
  • 相等操作符(区分 =====)

函数

  • 严格模式下,对函数有一些限制
    • 不能把函数命名为eval 或 arguments
    • 不能把参数命名为eval 或 arguments
    • 不能出现两个命名参数同名的情况
  • 理解参数
    • ECMAScript不介意传入参数的个数,即便函数写了两个参数,也可以只传入一个或者多个参数。因为ECMAScript中的参数在内部是用一个数组(arguments)来表示的。
      function sayHi(name, msg) alert("Hello " + name + msg)
      等价于 function sayHi() alert("Hello " + arguments[0] + atguments[1])
    • 传入参数 和 arguments的内存空间是相互独立的。虽然namearguments[0] 的值相等,但其为不同的内存空间。
    • 在ECMAScript中,没有函数重载,但可以模仿出重载。即检测参数的个数来进行不同的操作

Chapter 4 variable | action scope | memory

变量

  • 基本类型和引用类型
    • 基本类型:Undefined null boolean number string,保存在 内存中
    • 引用类型:object 保存在 内存中
    • 可以为引用类型的变量动态地添加属性和方法
  • 复制变量名
    • 基本类型:复制后,两个变量相互独立。各占不同的内存
    • 引用类型:复制后,指向同一内存空间,故改变其中一变量的属性,另一变量相同属性同时变化。
  • 检测类型
    • typeof:用于确定是哪种基本类型
    • instanceof:用于检测某引用类型对象是什么类型的对象

执行环境及作用域

  • 在Web浏览器中,全局执行环境被认为是window对象
  • 没有块级作用域
    • 变量在if语句的代码块中,依然可以被语句外使用
  • 声明变量时,使用var声明的变量会自动添加到最接近的环境中
    • 函数内部,最接近的环境就是函数的局部环境
    • 在没有使用var的前提下,变量会被添加到全局环境中

垃圾收集

  • 标记清除法
  • 引用计数
    • 存在循环引用问题而导致无法释放内存

Chapter 5 reference type

Object 类型

创建对象的两种方式

  • new操作符后跟object构造函数 var person = new Object()
  • 对象字面量表示法 var person = {name : 'Nic', age : '29'}
    • 逗号用以分隔不同的属性
    • 最后一个属性后不能添加逗号,否则会在IE7及更早版本 和 Opera中导致错误
    • 在使用对象字面量的时候,实际上不会调用object构造函数

访问属性的方式

  • 点表示法 person.name (推荐使用)
  • 方括号语法 person["name"]
    • 可以通过变量来访问属性 var pro = "name"; person[pro]
    • 属性名中包含会导致语法错误的字符或者使用关键字或保留字,都可用方括号法进行访问 person["first name"] = "nic"

Array 类型

与其他语言不同,ECMAScript数组的每一项可以保存任何类型的数据

创建对象的两种方式

  • new 操作符后跟Array构造函数 (可省略new)
    • var colors = new Array()
    • var colors = new Array(20) 创建length为20的数组
    • var colors = new Array("red", "blue") 创建包含2个字符串的数组
  • 数组字面量表示法 var colors = ["red", "blue"]
    • 不要这么声明及定义 var colors = ["red", "blue", ]
      • 在IE中,会将其解读为3个项的数组
      • 在其他浏览器则会将其解读为2个项的数组

检测是否为数组

  • instanceof 是在假定只有一个全局执行环境下,才能正确执行得出结果
  • ECMAScript新增 Array.isArray() 用于辨别是否为数组(推荐使用)

数组转为字符串

  • toLocaleString()
  • toString()
  • valueOf()
  • join("|")
  • 数组中的某一项是null 或者 undefined,则在调用以上方法时,返回结果以 空字符串 进行显示

利用数组实现 栈 队列 数据结构

  • push:可接收任意数量的参数,逐个添加到末尾,并返回修改后数组的长度
  • pop:从数组末尾移除一项,减少length值,并返回移除的项
  • shift:移除数组中的第一个项并且返回该项
  • unshift:在数组前添加任意个项并返回新数组的长度

数组 重排序 方法

  • reverse() 逆序
  • sort()
    • 默认情况下,按升序进行排序数组项
    • 为实现升序,会为数组每一项调用toString()方法,进行 字符串的比较 (←本质)
  • sort() 传递比较函数作为其参数
    • boolean原则及意义:第一个参数应位于第二个参数前, 则返回 -1;同理,一在二后,返回 1;相等则返回 0
    • 如下 进行一个 升序函数的 定义
  1. function compare(value1, value2) {
  2. if (value1 < value2) {
  3. return -1;
  4. } else if (value1 > value2) {
  5. return 1;
  6. } else {
  7. return 0;
  8. }
  9. }

数组 操作方法

  • concat():创建当前数组一个副本,将接收的参数添加到这个副本的末尾,并返回新构建的数组。(该操作不改变原数组)
  • slice():接收两个参数,返回 起始 到 结束(不包括结束位置)的数组项 (该操作不改变原数组)
  • splice():接收三个参数(起始位置、要删除的项数、要插入的项),其返回一个数组,该数组包含被删除的数组项。(若未删除项,则返回空数组)

数组迭代方法

  • every():对数组每项都运行给定函数,若该函数每一项都返回true,则返回true
  • some():对数组每项都运行给定函数,若该函数只要有一项都返回true,则返回true
  • filter():对数组每项都运行给定函数,返回该函数会返回true的项组成的数组
  • map():对数组每项都运行给定函数,返回 每次函数调用结果 组成的数组
  • foreach:对数组每项都运行给定函数,不返回任何东西
  1. var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
  2. var somenumbers = numbers.some(function(item, index, array) {
  3. return (item > 2);
  4. }); // true

RegExp 类型

正则表达式的组成 var expression = / pattern / flags ;

其中标志(flags)用以表明正则表达式的行为

  • g:全局(global)
  • i:大小写不区分(case insensitive)
  • m:多行模式(multiline)

创建正则表达式的方法

  • 字面量方法:var pattern = /[bc]at/i
  • 使用RegExp构造函数:接收参数都为 字符串 -> var r = new RegExp("[bc]at", "i")

正则表达式的方法

  • exec():返回一个数组,专门为捕获组而设计 var pattern = /mom( and dad( and baby)?)?/gi
    • exec返回的是一个Array的实例数组(code for RegExp_1)
      • 无匹配项时,返回null
      • 有匹配项时,若无捕获组,则数组始终只包含一项;若有捕获组,则0代表整串,接下来n代表第n个捕获组
    • 无捕获组的情况下,每次数组只返回一项(code for RegExp_2)
      • 在无全局标志(g)情况下,每次数组的匹配结果都一样
      • 在有全局标志(g)情况下,匹配会沿着测试字符串不断搜寻至末尾
  • test():返回true / false,只需要知道匹配or不匹配,而不需要知道其内容。常用于 进行验证用户输入内容是否合法

RegExp 构造函数属性

RegExp有多大9个用于存储捕获组的构造函数属性,访问方式为 RegExp.$1RegExp.$2 ……,当使用了exec() 或者 test()之后,该属性被自动填充,即可使用,相当于下面代码的 matches[0]matches[1]

  1. /*code for RegExp_1*/
  2. var text = "mom and dad and baby";
  3. var pattern = /mom( and dad( and baby)?)?/gi; // 有两个捕获组
  4. var matches = pattern.exec(text);
  5. matches[0]; // "mom and dad and baby"
  6. matches[1]; // "and dad and baby"
  7. matches[2]; // "and baby"
  8. /*code for RegExp_2*/
  9. var text = "cat, bat, sat, fat";
  10. var pattern = /.at/;
  11. var matches = pattern.exec(text);
  12. matches[0]; // cat
  13. var matches = pattern.exec(text);
  14. matches[0]; // cat
  15. // change pattern from /.at/ to /.at/g
  16. var matches = pattern.exec(text);
  17. matches[0]; // cat
  18. var matches = pattern.exec(text);
  19. matches[0]; // bat

Function 类型

函数名实际上一个指向函数对象的指针

函数的定义

  • 函数声明
  • 函数表达式
  • 二者区别:解析器会率先读取函数声明,并使其在执行任何代码之前可用,解析器会进行一个函数声明提升的过程,即让函数声明的方式可以再定义前就使用
  1. /*函数的定义*/
  2. function sum(num1, num2) {
  3. return num1 + num2;
  4. }; // 函数声明
  5. var sum = function(num1, num2) {
  6. return num1 + num2;
  7. }; // 函数表达式
  8. alert(sum(10, 10))
  9. function sum(sum1, sum2) {
  10. return sum1 + sum2;
  11. }; // 函数提升

函数内部属性

  • arguments 对象
    • 拥有 callee 属性:该属性是一个指针,指向拥有这个arguments对象的函数
  • this 对象
    • 根据其执行环境来确定 对象引用主体
  • caller
    • 该属性保存着调用当前函数的函数的引用,若在全局作用域中调用当前函数,其值为null
  1. ----------------------callee----------------------
  2. /* arguments 的 callee属性
  3. * 可以减少紧密耦合的现象
  4. */
  5. function factorial(num) {
  6. if (num <= 1) {
  7. return 1;
  8. } else {
  9. return num * factorial(num - 1);
  10. }
  11. };
  12. /* 正常使用上面函数不会出现问题
  13. * 但倘若,进行函数赋值并对函数主体进行重写后,可能会出错
  14. */
  15. var trueFactorial = factorial;
  16. factorial = function() {
  17. return 0;
  18. };
  19. alert(trueFactorial(5)); // 0
  20. /* 解决办法,用callee进行重写
  21. */
  22. function factorial(num) {
  23. if (num <= 1) {
  24. return 1;
  25. } else {
  26. return num * arguments.callee(num - 1);
  27. }
  28. };
  29. ----------------------caller----------------------
  30. function outer() {
  31. inner();
  32. };
  33. funtion inner() {
  34. alert(arguments.callee.caller);
  35. };
  36. outer(); // 显示inner函数内容

函数的属性和方法

  • length:用以标记函数参数的数量
  • prototype:保存所有引用类型的实例方法所在地方(chapter 6 中详细介绍) prototype属性不可枚举
  • 在特定的作用域中调用函数:等价于设置函数体内this对象的值
    • apply():接收两个参数,一个是期中运行函数的作用域,一个是参数数组(第二个参数可以是Array数组,也可是arguments对象)
    • call():接收参数方法与apply不同,传递给call的参数必修逐个列出
  • bind:创建一个函数的实例,其this值会被绑定到传给bind()函数的值
  1. function sum(num1, num2) {
  2. return num1 + num2;
  3. }
  4. function callSum1(num1, num2) {
  5. return sum.apply(this, [num1, num2]); // apply方法
  6. return sum.call(this, num1, num2); // call方法
  7. }
  8. /* 扩充函数赖以运行的作用域
  9. */
  10. window.color = "red";
  11. var o = { color : "blue"};
  12. function sayColor() {
  13. return this.color;
  14. }
  15. sayColor(); // red
  16. sayColor.call(this); // red
  17. sayColor.call(o); // blue 即将this的值设置为对象o

基本包装类型

  • Boolean类型
  • Number类型
    • toFixed():接收一个参数,指定输出结果中小数的位数
    • toExponential():接收一个参数,指定输出结果中小数的位数
    • toPrecision():根据参数来决定调用toFixed() or toExponential()
  • String类型
    • 字符方法
      • charAt():接收一个参数,以单字符字符串的形式返回
      • charCodeAt():返回指定位置字符的ASCII码值
    • 字符串操作方法
      • concat 等价于 +
      • slice
      • substr
      • substring
    • 字符串位置方法
      • indexOf():接受两个参数,第一个参数为搜索的字符串,第二个为起始位置,若无匹配,返回 -1
      • lastIndexOf():同上
    • trim():创建一个字符串的副本,删除前置及后缀的所有空格
    • 大小写转换方法
      • toLowerCase
      • toLocaleLowerCase
      • toUpperCase
      • toLocaleUpperCase
    • 字符串匹配方法
      • match():接受一个参数,参数为正则表达式 / RegExp对象 本质是调用了exec()函数,所以结果与调用exec一样
      • replace():接受两个参数,第一个参数可以 字符串 或者 正则表达式,第二个参数为一个 字符串 或者 函数若要替换所有子字符串,提供正则表达式,并且指定全局(g)标志
      • split():基于指定的分隔符,将一个字符串分割成多个子字符串,并将结果存入 数组 返回。text.split(/[^\,]+/),其中^表示 非 的意义
  1. /* replace方法,第二个参数传入函数的形式*/
  2. function htmlEscape(text) {
  3. return text.replace(/[<>"&]/g, function(match, pos, originalText) {
  4. switch(match) {
  5. case "<":
  6. return "&lt;";
  7. case ">":
  8. return "&gt;";
  9. case "&":
  10. return "&amp;";
  11. case "\"":
  12. return "&quot;";
  13. }
  14. });
  15. };

Chapter 12 DOM2 DOM3

DOM0 拓展

  1. H5 与 CSS相关的
    • getElementsByClassName
    • classList
      • add()
      • remove()
      • contains()
      • toggle()
  2. selectorAPI
    • querySelector()
    • querySelectorAll()
  3. children属性 vs childNodes
    • 前者忽略子节点中的空白文本节点

DOM2 DOM3 拓展

  1. document.defaultView.getComputedStyle(elem, null) 可获得元素的最终样式
  2. document.implementation.hasFeature("StyleSheet", "2.0") 可检测浏览器是否支持某些特性
  3. 元素大小 : 可获得 浏览器窗口的大小
    • document.documentElement.clientWidth
    • document.documentElement.clientHeight

Chapter 13 event

事件

  1. 事件冒泡和捕获方式
    • 事件冒泡流
    • 事件捕获流
  2. DOM事件流
    • 捕获阶段
    • 目标阶段
    • 事件冒泡
  3. 事件绑定
    • DOM
      btn.click = function() {}
    • DOM2
      • addEventListner(event, func, false)
      • removeEventListner(event, func, false)
      • why use addEventListner(): 可以添加多个事件处理程序
    • For IE
      • attachEvent()
      • detachEvent()
  4. 事件对象(event)
    • 常用的属性和方法:
      • event.target
      • event.preventDefault()
      • event.stopPropogation()
      • event.stopImediatePropagation()
    • 区别于 currentTarget、target、this
      • this始终等于currentTarget
      • currentTarget 指被赋予事件的对象元素
      • target 实际的操作的元素

Chapter 21 ajax & Comet

ajax
Get: open的url必须是格式化之后,符合编码的,所以在自己构造url的时候,最好是使用 encodeURIComponent()
Post: 发送数据前,要将数据序列化 serialize();在xhr2当中,可以使用 new FromData() 来进行实现序列化


CORS(Cross-origin Resource Sharing) 跨源/跨域资源共享
即在github上搭建了一个静态的页面,若要向自己的服务器请求资源,因为处于不同的源,所以原本是不能成功的,而在服务器上设置 Access-control-Allow-Origin 之后,可以允许github静态页面上向服务器发送数据请求

跨域常用技术
JSONP:通过动态的插入<script>标签,请求外部js文件,将返回的JSON数据传入到回调函数当中进行处理,并显示到页面上。

Comet(服务器推送) → 适用于实时更新的应用(体育比赛、股票报价等等)
实现方式:长轮循 或者是 HTTP流


SSE(Server Send Event) 服务器发送事件

  1. var source = new EventSource("myevent.php");
  2. source.onmessage = function(event) {
  3. var data = event.data;
  4. // 处理相应的数据
  5. }

Web-Socket:在客户端和服务器之间建立一条双向的、全双工的持久连接,使服务器的状态更新能够实时地推送到客户端上。

  1. // S → C
  2. var socket = new WebSocket(ws://www.example.com/server.php);
  3. socket.send(JSON.stringify(message));
  4. // C → S
  5. socket.onmessage = function(event) {
  6. var data = event.data;
  7. }

Chapter 22 高级技巧

检查对象为原生还是自定义: Object.prototype.toString.call()


作用域安全的构造函数:即要检查this是否为构造函数本身而非window

  1. function Person(name, age, job) {
  2. if (this instanceof Person) {
  3. // ....
  4. } else {
  5. return new Person(name, age, job);
  6. }
  7. }

函数绑定:

  1. function bind(fn, context) {
  2. return function() {
  3. return fn.apply(context, arguments);
  4. }
  5. }

防篡改对象:
修改可拓展性:即对象不可拓展

  1. var person = {name : "Nic"};
  2. Object.preventExtensions(person);

密封对象:即对象不可拓展,并且不可删除,但可写

  1. var person = {name : "Nic"};
  2. Object.seal(person);

冻结对象:即对象不可拓展,并且不可删除,也不可写

  1. var person = {name : "Nic"};
  2. Object.freeze(person);

Web 存储机制
localStorage sessionStorage cookies globalStorage

设置属性的方法主要有两种
1. sessionStorage.book = "Nic";
2. sessionStorage.setItem("book", "Nic");

通用方法:
1. setItem
2. getItem
3. removeItem
4. clear
5. key

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注