JavaScript忍者秘籍

JavaScript忍者秘籍

入门

了解市场上的JavaScript库,如jQuery,prototype,base2

掌握跨浏览器开发。

掌握测试方法。

测试

运用日志记录和断点进行调试。console.log()

函数

  • 函数为什么如此重要
  • 函数为什么是第一型对象
  • 浏览器如何调用函数
  • 函数声明
  • 参数赋值之谜
  • 函数上下文

第一型(first-class)对象

函数可以共处,可以被视为任意类型的JavaScript变量,被任意变量进行引用,或进行传递。

浏览器的事件轮询是单线程的,遵循FIFO顺序(先进先出)。

window.onload()调用函数

函数作用域

函数调用

  • 作为一个函数被调用
  • 作为一个方法被调用,在对象上进行调用,支持面向对象编程
  • 作为构造器进行调用
  • 通过apply()或call()进行调用

参数声明

  • 如果声明的参数数量大于实际传递的参数数量,则没有对应参数的形参会声明为undefined
  • 如果声明的参数数量小于实际传递的参数数量,超出的参数则不会配给形参名称
  • 隐式参数:argument,this

构造器

挥舞函 数

  • 匿名函数为什么如此重要
  • 函数调用时的引用形式,包括递归
  • 函数引用的存储
  • 函数上下文的利用
  • 处理可变长度的参数列表
  • 判断一个对象是否是函数

匿名函数

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
window.onload = function(){console.log("hi");};

var ninja = {
shout:function(){
console.log("hi");
};
};
ninja.shout();

setTimeout(
function(){
console.log("hi");
},500);

对象中的方法递归

1
2
3
4
5
6
var ninja = {
chirp:function(n){
return n > 1?ninja.chirp(n-1)+"-chirp":"chirp";
}
};
assert(ninja.chirp(3) == "chirp-chirp-chirp","。。。");

存储一组独立的函数

闭包

一个简单的闭包

1
2
3
4
5
6
7
<script type="text/javascript">
var outerValue = 'ninja';
function outerFunction(){
console.assert(outerValue == "ninja","i can see the ninja");
}
outerFunction();
</script>

一个不那么简单的闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type="text/javascript">
var outerValue = 'ninja';
var later;

function outerFunction(){
var innerValue = 'samurai';

function innerFunction(){
console.assert(outerValue,"i can see ninja");
console.assert(innerValue,"i can see samurai");

}
later = innerFunction;
}
outerFunction();
later();
</script>

使用闭包模拟私有变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
function Ninja(){
var feints = 0;
this.getFeints = function(){
return feints;
};

this.feint = function(){
feints++;
};

}
var ninja = new Ninja();
ninja.feint();

console.assert(ninja.getFeints()==1,"internal feint count");
console.assert(ninja.feints==undefined,"data is inaccessible");

</script>

另一个使用闭包的最常见情形就是处理回调或使用定时器。

原型与面向对象

  • 利用函数实现构造器
  • 探索原型
  • 利用原型实现对象的扩展
  • 避免常见的问题
  • 构建可继承的类

利用原型方法创建一个新实例

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
function Ninja(){};

Ninja.prototype.swingSword = function(){
return true;
};
//函数作为函数进行调用
var ninja1 = Ninja();
console.assert(ninja1 === underfined,"no instance of ninja created")
//函数作为构造器进行调用
var ninja2 = new Ninja();
console.assert(ninja2&&ninja2.swingSword&&ninja2.swingSword(),"instance exists and method is callable");
</script>

继承与原型链

通过prototype,让ninja拥有person的跳舞能力。但ninja不是一个Person

1
2
3
4
5
6
7
8
9
10
11
12
<script type="text/javascript">
function Person(){ };
Person.prototype.dance = function(){};
function Ninja(){};
Ninja.prototype = {dance:Person.prototype.dance};

var ninja = new Ninja();
console.log(ninja instanceof Ninja);
console.log(ninja instanceof Person);
console.log(ninja instanceof Object);

</script>

创建一个原型链

SubClass.prototype = new SuperClass()

Ninja.prototype = new Person()

1
2
3
4
5
6
7
8
9
10
11
12
<script type="text/javascript">
function Person(){ };
Person.prototype.dance = function(){};
function Ninja(){};
Ninja.prototype = new Person();

var ninja = new Ninja();
console.log(ninja instanceof Ninja);
console.log(ninja instanceof Person);
console.log(ninja instanceof Object);

</script>

通过HTMLElement的原型,给元素添加一个新方法

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
HTMLElement.prototype.remove = function(){
if (this.parentNode) this.parentNode.removeChild(this);
};

var a = document.getElementById("a");
a.parentNode.removeChild(a);
document.getElementById("b").remove();

console.log(!document.getElementById("a"));
console.log(!document.getElementById("b"));

</script>

陷阱

给Object原型添加额外属性会发生的行为

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
Object.prototype.keys = function(){
var keys = [];
for(var p in this) keys.push(p);
return keys;
}

var obj = {a:1,b:2,c:3};
console.log(obj.keys().length);//结果返回了4

</script>

使用hasOwnProperty进行修改

1
2
3
4
5
6
7
8
9
10
11
12
<script type="text/javascript">
Object.prototype.keys = function(){
var keys = [];
for(var p in this)
if(this.hasOwnProperty(p)) keys.push(p);
return keys;
}

var obj = {a:1,b:2,c:3};
console.log(obj.keys().length);//结果返回了4

</script>

扩展数字

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
Number.prototype.add = function(num){
return this+num;
}
var n = 5;
console.log(n.add(3));
console.log((5).add(3));
console.log(5.add(3));//报错,因为语法解析器不能处理字面量的情况
</script>

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<script type="text/javascript">
var Person =Object.subClass({
init:function(isDancing){
this.dancing = isDancing;
},
dance:function(){
return this.dancing;
}
});
var Ninja = Person.subClass({
init:function(){
this._super(false);
},
dance:function(){
return this._super();
},
swingSword:function(){
return true;
}
});

var person = new Person(true);
console.log(person.dance());

var ninja = new Ninja();
console.log(ninja.dance());
console.log(ninja.swingSword());

console.log(person instanceof Person);

console.log(ninja instanceof Ninja);
console.log(ninja instanceof Person);

</script>

正则表达式

驯服线程和定时器

定时器

定时器的操作方法

方法 格式 描述
setTimeout id = setTimeout(fn,delay) 启动一个定时器,在一段时间delay之后执行传入的callback,并返回该定时器的唯一标识
clearTimeout clearTimeout(id) 如果定时器还未触发,则可取消该定时器
setInterval id = setInterval(fn,delay) 启动一个定时器,在每隔一段时间delay之后都执行传入的callback,并返回该定时器的唯一标识
clearInterval clearInterval(id) 传入间隔定时器标识,取消间隔定时器

运行时代码求值

  • 运行时代码求值如何工作的

  • 代码求值的不同技术

  • 在应用程序中代码求值

  • 函数反编译

  • 命名空间

  • 压缩与混淆

  1. 求值方式包括
    • eval()函数
    • 函数构造器
    • 定时器
    • <script>元素

with语句

开发跨浏览器策略

洞悉特性、属性和样式

不老事件

DOM操作

CSS选择器引擎