《Javascript高级程序设计》总结

复制基本类型值的时候,会新创建一个。复制引用类型值的时候,只是复制指针,指针指向堆中同一个对象。

5 引用类型

到底是不是数组,可以用.isArray(),instanceof 在多个框架(两个以上全局执行环境)就不好用了

array.push():添加到数组末尾,返回新长度 array.pop():返回数组最后一一项 array.shift():移除并返回第一项 array.unshift():前端添加任意项,返回新长度

sort()排序会将‘15’放在‘5’前面,因为比较第一个字符。可以接收一个用于比较的函数

1
2
3
4
function compare(value1, value2) {
return value2 - value1;
}
arr.sort(compare);

arr.concat()将参数(值或数组)添加到 arr 后面,并返回新数组,arr 不变。 arr.slice(1,4)也不会影响原数组,如果 arr.length=5,只会取到第 234 项,不会取到第 5 项。(不包括结尾元素)

arr.splice()

every(),filter(),forEach(),map(),some()

reduce() reduceRight()

Date.parse() Date.UTC()

RegExp

1
2
3
4
5
6
7
8
9
10
var re = null,
i;
for (i = 0; i < 10; i++) {
re = /cat/g;
re.test('catastrophe');
}
for (i = 0; i < 10; i++) {
re = new RegExp('cat', 'g');
re.test('catastrophe');
}

捕获组

reg.exec()

5.5 Function 类型

解析器会先读取函数声明,并使其在任何代码之前可以访问,而函数表达式则必须到所在代码行才会被解释执行。

caller

使用 call 和 apply 来扩充作用域最大的好处就是,对象不需要与方法有任何的耦合。

5.6 基本包装类型

用 new 操作符创建实例的时候,在执行流离开作用域之前都会一直保留;但是自动创建的基本包装类型的对象,只存在创建的一瞬间。

基本类型的布尔值和 Boolean 对象不一样,后者不建议使用。

num.toString(n)//将 num 转换为 n 进制 num.toFixed(n)//将 num 转换为 n 为小数

6 面向对象的程序设计

对象的属性

属性包括数据属性和访问器属性。

数据属性包含一个数据值的位置。访问器属性不包含数据值。

1
2
3
4
5
6
7
var person = {};
Object.defineProperty(person, 'name', {
configurable: false, //不能再改回true
writable: false,
enumerable: true,
value: 'nicholas',
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var book = {
_year: 2019,//加上_表示只能通过对象方法进行访问的属性
edition: 1
};
Object.defineProperty(book, 'year', {
//get在读取属性的时候调用
get: function() {
return this._year;
},
//set在写入的时候调用
set: function(newValue) {
if (newValue > 2019) {
this._year = newValue;
this.edition += newValue - 2019;
}
}
});
book.year = 2020;
console.log(book.edition);

同时修改多个属性用 Object.defineProperties()

6.2 创建对象

工厂模式

构造函数模式

原型模式

1
2
3
4
5
6
7
8
9
function Person() {}
Person.prototype.name = 'zhaosi';
Person.prototype.age = '37';
Person.prototype.sayName = function () {
console.log(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.hasOwnProperty(‘name’):如果返回 true,则 name 存在于 person1 实例中,否则存在于原型中。

Object.keys(Person.prototype) 所有可枚举

Object.getOwnPropertyNames() 所有可枚举不可枚举

更简单的原型语法

如果把上述代码改成 Person.prototype={}对象字面量的形式,因为这种写法本质上完全重写了默认的 prototype 函数,constructor 不再指向 Person 了

如果 constructor 属性很重要,那么

1
2
3
4
Person.prototype={
name:'',
constructor:Person //确保通过该属性访问到适当的值
}

注意:这种方法会使 constructor 变成可枚举,可以通过 defineProperty 变成不可枚举

1
2
3
4
Object.defineProperty(Person.prototype, 'constructor', {
enumerable: false,
value: Person
});

更好的方式是组合使用构造函数模式和原型模式,构造函数用来定义实例属性,原型定义方法和共享的属性

动态原型(很完美)

1
2
3
4
5
6
7
8
9
10
11
function Person(name, age) {
this.name = name;
this.age = age;
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function() {
console.log(this.name);
};
}
}
var friend = new Person('zhaosi', 29);
friend.sayName();

寄生构造函数模式

继承

原型链继承

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

借用构造函数(伪造对象 或 经典继承)

组合继承(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
alert(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
alert(this.age);
};

原型式继承

寄生式继承

不能做到函数复用,与构造函数模式相似

寄生组合式继承(最理想)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
alert(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
function inheritPrototype(subType, superType) {
var prototype = Object(superType.prototype); //创建超类型原型的一个副本
prototype.constructor = subType; //为创建的副本添加constructor属性(重写原型失去了默认的constructor属性)
subType.prototype = prototype; //将创建的副本赋值给子类型的原型
}
inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function () {
alert(this.age);
};

7 函数表达式

7.2 闭包

闭包是指有权访问另一个函数作用域中的变量的函数

不足:多查找作用域链中的一个层次,就会在一定程度上影响查找速度。

7.4

7.4.0 特权方法

1
2
3
4
5
6
7
8
9
10
11
12
function PrivateObject() {
var privateVariable = 10;
function privateFunction() {
return '11';
}
this.publicMethod = function () {
privateVariable++;
return privateFunction;
};
}
var newPublic = new PrivateObject();
console.log(newPublic.publicMethod());

每个实例都会创建同一组新方法

7.4.1 静态私有变量

在原型上添加方法,会导致每个实例都没有自己的私有变量。

7.4.2 模块模式

10 DOM

每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象(动态,随着 DOM 改变而改变)

节点层次

node

hasChildNodes() ownerDocument

appendChild(newNode)//添加至最后 insertBefore(newNode,targetNode) replaceChild(newNode,targetNode) removeChild(targetNode) cloneNode(true||false)//true:深复制,复制节点和整个子节点树;false:浅复制,只复制节点

document

var html=document.documentElement // var body=document.body// var doctype=document.doctype//<!DOCTYPE>

document.domain: loose && tight

11 DOM 扩展

querySelector() && querySelectorAll()

前者返回与模式匹配的第一个元素,后者是一个 NodeList 实例

mathesSelector()

childElementCount && firstElementChild && previousElementSibling && nextElementSibling

相比于 firstChild,添加‘element‘之后,就不会纠结元素间的空格了

classList

someElement.classList.add(value)||contains(value)||remove(value)||toggle(value)

toggle 是存在则删除,不存在则添加

document.activeElement && document.hasFocus()

scrollIntoView()

DOM2 和 DOM3

setUserData()

getPropertyValue()

document.defaultView.getComputedStyle()

13 事件

13.2 事件处理

addEventListener() 和 removeEventListener():三个参数:要处理的事件名,函数,布尔值(true 为捕获阶段调用函数,默认 false 为冒泡)

event.currentTarget && event.target && this

preventDefault()

13.4 事件类型

clientX(clientY) && pageX(pageY) && screenX(screenY)

视口 && 页面(没有滚动的时候 页面==视口) &&相对于整个屏幕

keydown:任意键触发,按住不放会重复触发 keypress:字符键触发,按住不放会重复触发(esc 也会触发) keyup:释放触发

textInput:可编辑区域才能触发;输入实际字符才能触发(退格不能)

inputMethod:表示把文本输入到文本框的方式(键盘输入,粘贴,拖放等)

13.4.5 复合事件

IME(Input Method Editor 输入法编辑器)可以让用户输入在物理键盘上找不到的字符,eg 日文 compositionstart compositionupdate(插入新字符) compositionend

13.4.7 HTML5 事件

contextmenu

beforeunload(卸载页面)

DOMContentLoaded:形成 DOM 树就会触发,不会管 JS CSS 文件,让用户尽早与页面交互

event.preventDefault()取消默认行为

13.5 内存和性能

事件委托

1
2
3
4
5
6
7
8
9
10
11
12
13
var list = document.getElementById('ul');
EventUtil.addHandler(list, 'click', function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch (target.id) {
case 'doSomething':
document.title = 'doSomething';
break;
case 'goSomewhere':
document.title = 'goSomewhere';
break;
}
});

13.6 模拟事件

initMouseEvent

initKeyboardEvent

14 表单脚本

14.2 文本框脚本

访问剪切板 clipboardData 对象有三个方法:getData(),setData(),clearData()

eg:如果一个文本框只接受数值,就要检测粘贴过来的值

1
2
3
4
5
6
7
EventUtil.addHandler(textbox, 'paste', function(event) {
event = EventUtil.getEvent(event);
var text = EventUtil.getClipboardText(event);
if (!/^\d*$/.test(text)) {
EventUtil.preventDefault(event);
}
});

检测表单是否有效(require 没填,pattern 不符合等等),可以用 checkValidity()方法,而 validity 则会告诉你为什么无效

14.4 表单序列化

20 JSON

20.2 解析与序列化

toJSON()

21 Ajax 与 Comet

21.1 XMLHttpRequest 对象

open

xhr.open(“get”,”example.php”,false)

fasle 代表同步,true 代表异步

readyState

xhr.readyState: 0:未初始化。尚未调用 open() 1:启动。调用了 open(),但是未调用 send() 2:发送。调用 send(),但是未收到响应 3:接收。收到部分响应数据。 4:完成。收到全部响应数据。

setRequestHeader

xhr.open(“get”,”example.php”,true) xhr.setRequestHeader(‘MyHeader’,”MyHeaderValue”) xhr.send(null)

getAllResponseHeaders

xhr.getAllResponseHeaders()

1
2
3
4
5
6
7
8
function addUrlParam(url, param, value) {
url += url.indexOf('?') == -1 ? '?' : '&';
url += encodeURIComponent(param) + '=' + encodeURIComponent(value);
console.log(url);
return url;
}

addUrlParam('example.php', 'book', 'Professional JavaScript');

21.2 XMLHttpRequest 2 级

21.2.1 FormData

1
2
var data = new FormData();
data.append('name', 'Nicholas');

21.4 跨资源共享

CORS:Cross-Origin Resource Sharing

21.5 其他跨域技术

21.5.1 图像 Ping

21.5.2 JSONP

JSONP:JSON with padding(参数式 JSON)

21.5.3 Comet

Ajax 是页面向服务器请求数据,Comet 是 S 向 C 推送数据

Comet:长轮询和 HTTP 流

21.5.4 服务求发送事件

SSE

21.5.5 Web Sockets

ws wss

对于 CSRF 攻击,发送 post 而不是 get||检查 url||基于 cookie 验证都没有用,很容易伪造

22 高级技巧

22.1 高级函数

Object.prototype.toString.call(value)==’[object Function]’ 或者 Array 或者 RegExp 等等

使用构造函数创建实例的时候,如果没有用 new 创建,而是直接调用构造函数 Person(),Person 函数里面的 this 会指向全局。

22.1.3 惰性载入

22.3 高级定时器

1
2
3
setTimeout(() => {
setTimeout(arguments.callee, interval);
}, interval);

在前一个定时器执行完代码之前,不会向队列中插入新的定时器代码,确保不会有任何缺失的间隔;还可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。

22.3.3 节流

22.4 自定义事件

23 离线应用与客户端存储

23.3 数据存储

23.3.3 Web 存储机制

存在 sessionStorage 中的数据可以跨页面刷新而存在,浏览器崩溃后重启依然可用(ie 除外)

因为 sessionStorage 对象绑定于某个服务器会话,所以当文件在本地运行的时候是不可用的。

存在 sessionStorage 中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制

sessionStorage 中的 setItem()和 getItem()

针对会话的小段数据的存储:sessionStorage

跨越会话的存储要用 localStorage

24 最佳实践

24.2.1 注意作用域

减少全局查找

用 var doc=document 将 document 存起来,再用 document.getElementByID。。。

避免 with 语句

with 会创建自己的作用域,所以会增加其中执行代码的作用域链长度

24.2.2 选择正确的方法

减少属性查找

对象上的任何属性查找都要比访问变量或者数组花费更长时间

1
2
var value = 5;
var sum = 10 + value;
1
2
var values = [5, 10];
var sum = values[0] + values[1];
1
2
var values = { first: 5, second: 10 };
var sum = values.first + values.second;

前两种要比第三种好

优化循环

1
2
3
for (var i = 0; i < values.length; i++) {}

for (var i = values.length - 1; i >= 0; i--) {}

第二行比第一行好

do-while 比 for 和 while 好,因为可以避免最初终止条件的计算

还有循环体内,也要优化

Duff 装置技术:(升级版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var iterations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;
if (leftover > 0) {
do {
ProcessingInstruction(values[i++]);
} while (--leftover > 0);
}
do {
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
} while (--iterations > 0);

避免双重解释

实例化一个新的解释器有不容忽视的开销

其他

用原生方法,而不是自己写(如 Math 要快得多)

switch 比 if-else 快,最好将 case 按照最可能到最不可能排序

位运算比布尔和算数运算快。

最小化语句数

优化 dom

最小化现场更新

使用 innerHTML

使用 innerHTML 比使用标准 DOM 快得多(构建好一个 innerHTML 字符串,然后一次性调用)

HTMLCollection

返回 HTMLCollection 对象 1 进行了对 getElementsByTagName()调用 2 获取了元素 childNodes 属性 3 获取了元素 attributes 属性 4 访问了特殊的集合 document.forms,document.images 等

25 新兴的 API

25.2 Page Visibility API

document.hidden document.visibilityState

25.3 Geolocation API

navigator.geolocation 对象,包含 3 个方法 getCurrentPosition()

25.4 File API

FileReader 类型

webkitSlice() 读取部分内容

用 XHR 上传文件

Web Timing

Web Worker

var worker=new Worker('stufftodo.js')

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2018-2020 Jee
  • Visitors: | Views:

如果您觉得此文章帮助到了您,请作者喝杯咖啡吧~

支付宝
微信