@yacent
2016-07-22T09:46:06.000000Z
字数 10613
阅读 894
JavaScript
@author: Nichokas C.Zakas 尼古拉斯 泽卡斯
intruduction of JavaScript
JavaScript
是一种专为与网页交互而设计的脚本语言,由以下三部分组成
- ECMAScript 由ECMA-262定义,提供核心语言功能
- DOM 提供访问和操作网页内容的方法和接口
- DOM1: 由DOM核心(DOM Core) 和 DOM HTML构成
- DOM2: 添加了新的类型和接口,如DOM事件接口,DOM样式等
- DOM3: 引入统一方式加载和保存文档,增加验证文档的方法
- BOM 提供与浏览器交互的方法的和接口
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的平稳退化。使用条件(二者有一即可)
- 浏览器不支持脚本
- 浏览器支持脚本,但禁用了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>How to use NoScript</title>
<script type="text/javascript" src=""></script>
<script type="text/javascript" src=""></script>
</head>
<body>
<noscript>
<p>本页面需要浏览器支持(启用)JavaScript</p>
</noscript>
</body>
</html>
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的内存空间是相互独立的。虽然
name
和arguments[0]
的值相等,但其为不同的内存空间。- 在ECMAScript中,没有函数重载,但可以模仿出重载。即检测参数的个数来进行不同的操作
variable | action scope | memory
变量
- 基本类型和引用类型
- 基本类型:
Undefined
null
boolean
number
string
,保存在 栈内存中- 引用类型:
object
保存在 堆内存中- 可以为引用类型的变量动态地添加属性和方法
- 复制变量名
- 基本类型:复制后,两个变量相互独立。各占不同的内存
- 引用类型:复制后,指向同一内存空间,故改变其中一变量的属性,另一变量相同属性同时变化。
- 检测类型
- typeof:用于确定是哪种基本类型
- instanceof:用于检测某引用类型对象是什么类型的对象
执行环境及作用域
- 在Web浏览器中,全局执行环境被认为是window对象
- 没有块级作用域
- 变量在if语句的代码块中,依然可以被语句外使用
- 声明变量时,使用var声明的变量会自动添加到最接近的环境中
- 函数内部,最接近的环境就是函数的局部环境
- 在没有使用var的前提下,变量会被添加到全局环境中
垃圾收集
- 标记清除法
- 引用计数
- 存在循环引用问题而导致无法释放内存
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
- 如下 进行一个 升序函数的 定义
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
数组 操作方法
- concat():创建当前数组一个副本,将接收的参数添加到这个副本的末尾,并返回新构建的数组。(该操作不改变原数组)
- slice():接收两个参数,返回 起始 到 结束(不包括结束位置)的数组项 (该操作不改变原数组)
- splice():接收三个参数(起始位置、要删除的项数、要插入的项),其返回一个数组,该数组包含被删除的数组项。(若未删除项,则返回空数组)
数组迭代方法
- every():对数组每项都运行给定函数,若该函数每一项都返回true,则返回true
- some():对数组每项都运行给定函数,若该函数只要有一项都返回true,则返回true
- filter():对数组每项都运行给定函数,返回该函数会返回true的项组成的数组
- map():对数组每项都运行给定函数,返回 每次函数调用结果 组成的数组
- foreach:对数组每项都运行给定函数,不返回任何东西
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var somenumbers = numbers.some(function(item, index, array) {
return (item > 2);
}); // 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.$1
、RegExp.$2
……,当使用了exec() 或者 test()之后,该属性被自动填充,即可使用,相当于下面代码的matches[0]
、matches[1]
/*code for RegExp_1*/
var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi; // 有两个捕获组
var matches = pattern.exec(text);
matches[0]; // "mom and dad and baby"
matches[1]; // "and dad and baby"
matches[2]; // "and baby"
/*code for RegExp_2*/
var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches = pattern.exec(text);
matches[0]; // cat
var matches = pattern.exec(text);
matches[0]; // cat
// change pattern from /.at/ to /.at/g
var matches = pattern.exec(text);
matches[0]; // cat
var matches = pattern.exec(text);
matches[0]; // bat
Function 类型
函数名实际上一个指向函数对象的指针
函数的定义
- 函数声明
- 函数表达式
- 二者区别:解析器会率先读取函数声明,并使其在执行任何代码之前可用,解析器会进行一个函数声明提升的过程,即让函数声明的方式可以再定义前就使用
/*函数的定义*/
function sum(num1, num2) {
return num1 + num2;
}; // 函数声明
var sum = function(num1, num2) {
return num1 + num2;
}; // 函数表达式
alert(sum(10, 10))
function sum(sum1, sum2) {
return sum1 + sum2;
}; // 函数提升
函数内部属性
- arguments 对象
- 拥有
callee
属性:该属性是一个指针,指向拥有这个arguments对象的函数- this 对象
- 根据其执行环境来确定 对象引用主体
- caller
- 该属性保存着调用当前函数的函数的引用,若在全局作用域中调用当前函数,其值为null
----------------------callee----------------------
/* arguments 的 callee属性
* 可以减少紧密耦合的现象
*/
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
};
/* 正常使用上面函数不会出现问题
* 但倘若,进行函数赋值并对函数主体进行重写后,可能会出错
*/
var trueFactorial = factorial;
factorial = function() {
return 0;
};
alert(trueFactorial(5)); // 0
/* 解决办法,用callee进行重写
*/
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
};
----------------------caller----------------------
function outer() {
inner();
};
funtion inner() {
alert(arguments.callee.caller);
};
outer(); // 显示inner函数内容
函数的属性和方法
- length:用以标记函数参数的数量
- prototype:保存所有引用类型的实例方法所在地方(chapter 6 中详细介绍)
prototype属性不可枚举
- 在特定的作用域中调用函数:等价于设置函数体内this对象的值
- apply():接收两个参数,一个是期中运行函数的作用域,一个是参数数组(第二个参数可以是Array数组,也可是arguments对象)
- call():接收参数方法与apply不同,传递给call的参数必修逐个列出
- bind:创建一个函数的实例,其this值会被绑定到传给bind()函数的值
function sum(num1, num2) {
return num1 + num2;
}
function callSum1(num1, num2) {
return sum.apply(this, [num1, num2]); // apply方法
return sum.call(this, num1, num2); // call方法
}
/* 扩充函数赖以运行的作用域
*/
window.color = "red";
var o = { color : "blue"};
function sayColor() {
return this.color;
}
sayColor(); // red
sayColor.call(this); // red
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(/[^\,]+/),其中^表示 非 的意义
/* replace方法,第二个参数传入函数的形式*/
function htmlEscape(text) {
return text.replace(/[<>"&]/g, function(match, pos, originalText) {
switch(match) {
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
}
});
};
DOM2 DOM3
DOM0 拓展
- H5 与 CSS相关的
- getElementsByClassName
- classList
- add()
- remove()
- contains()
- toggle()
- selectorAPI
- querySelector()
- querySelectorAll()
- children属性 vs childNodes
- 前者忽略子节点中的空白文本节点
DOM2 DOM3 拓展
- document.defaultView.getComputedStyle(elem, null) 可获得元素的最终样式
- document.implementation.hasFeature("StyleSheet", "2.0") 可检测浏览器是否支持某些特性
- 元素大小 : 可获得 浏览器窗口的大小
- document.documentElement.clientWidth
- document.documentElement.clientHeight
event
事件
- 事件冒泡和捕获方式
- 事件冒泡流
- 事件捕获流
- DOM事件流
- 捕获阶段
- 目标阶段
- 事件冒泡
- 事件绑定
- DOM
btn.click = function() {}
- DOM2
- addEventListner(event, func, false)
- removeEventListner(event, func, false)
- why use
addEventListner()
: 可以添加多个事件处理程序- For IE
- attachEvent()
- detachEvent()
- 事件对象(event)
- 常用的属性和方法:
- event.target
- event.preventDefault()
- event.stopPropogation()
- event.stopImediatePropagation()
- 区别于 currentTarget、target、this
- this始终等于currentTarget
- currentTarget 指被赋予事件的对象元素
- target 实际的操作的元素
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) 服务器发送事件
var source = new EventSource("myevent.php");
source.onmessage = function(event) {
var data = event.data;
// 处理相应的数据
}
Web-Socket:在客户端和服务器之间建立一条双向的、全双工的持久连接,使服务器的状态更新能够实时地推送到客户端上。
// S → C
var socket = new WebSocket(ws://www.example.com/server.php);
socket.send(JSON.stringify(message));
// C → S
socket.onmessage = function(event) {
var data = event.data;
}
高级技巧
检查对象为原生还是自定义: Object.prototype.toString.call()
作用域安全的构造函数:即要检查this是否为构造函数本身而非window
function Person(name, age, job) {
if (this instanceof Person) {
// ....
} else {
return new Person(name, age, job);
}
}
函数绑定:
function bind(fn, context) {
return function() {
return fn.apply(context, arguments);
}
}
防篡改对象:
修改可拓展性:即对象不可拓展
var person = {name : "Nic"};
Object.preventExtensions(person);
密封对象:即对象不可拓展,并且不可删除,但可写
var person = {name : "Nic"};
Object.seal(person);
冻结对象:即对象不可拓展,并且不可删除,也不可写
var person = {name : "Nic"};
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