第一章 第一个单页应用
1.1.3(page8) 下图展示了业务逻辑和HTML的生成是如何从服务端迁移到客户端的。
第二章 温故javascript
对象字面量:是指用大括号括起来的一组以逗号分隔的属性所定义的对象
var spa = {
title: 'single page web applications',
authors: ['mike mikowski', 'josh powell'],
buy_now: function() {
console.log('book');
}
}
可以在函数中声明全局变量,只要省略var关键字即可
function prison () {
prisoner_1 = 'i have escaped!'
var prisoner_2 = 'I am locked in!'
}
prison();
console.log(prisoner_1); // 输出i have escaped!
console.log(prisoner_2); // 输出: prisoner_2 is not defined
#####2.2 变量提升
在Javascript中,当变量被声明时,声明会被提升到它所在函数的顶部,并被赋予undefined值。故:最好的方式将变量声明写在函数顶部
function prison() {
console.log(prisoner); // 输出'undefined'
var prisoner;
prisoner = 'lmh'
console.log(prisoner); // 输出'lmh'
}
prison();
变量是沿着作用域链往上查找:先查看局部作用域,局部未定义再依次向外全局搜索
var prison1 = 'lmh'
var prison2 = 'zf'
function prison() {
console.log(prison1); // undefined,因为局部有定义,局部作用域的优先级高
console..log(prison2); // 'zf',局部未定义,向外全局搜索,使用全局变量
var prison1;
}
prison();
2.3 高级变量提升和执行环境对象
JavaScript引擎在进入作用域时 ,会对代码分两轮处理。第一轮,初始化变量;第二轮,执行代码。
第一轮,初始化变量分三部
- 声明并初始化函数参数。
- 声明局部变量,包括将匿名函数赋给一个局部变量,但并不初始化它们。
- 声明并初始化函数。
var prison1 = 'lmh'
function prison(prison1) {
console.log(prison1); // 输出zf,变量在声明前有值
var prison1;
console.log(prison1); // 输出zf,变量在声明前有值
}
prison('zf');
JavaScript是如何保存变量的?
JavaScript引擎把变量作为属性保存在一个对象上,这个对象称为执行环境对象。
JavaScript引擎在执行环境对象中访问作用域内的变量,查找的顺序叫做作用域链,它和原型链一起,描述了JavaScript访问变量和属性的顺序。
浏览器的顶层对象是window对象;在node.js中,顶层对象叫做global。
JavaScript对象是基于原型的,其他语言(java、c)是基于类的对象。
2.5原型链
原型链步骤:
- 定义原型对象
- 定义对象的构造函数
- 将构造函数关联到原型
- 实例化对象
// step 1
var proto = {
sentence: 4,
probation: 2
};
// step 2
var prisoner = function(name, id) {
this.name = name;
this.id = id
}
//step 3
prisioner.prototype = proto;
//step 4
var firstPrisoner = new prisoner('lmh', 'zf');
var secondPrisoner = new prisoner('aaa',bbb');
使用Object.create来代替new操作符实现原型链
Object.create把原型作为参数并返回一个对象,使用这种方式,可以在原型对象上定义共同的属性和方法,然后使用它来创建多个共享相同属性的对象。
var proto = {
sentence: 4,
probation: 2
};
var firstPrisoner = Object.create(proto);
firstPrisoner.name = 'lmh';
firstPrisoner.id = '12';
var secondPrisoner = Object.create(proto);
secondPrisoner.name='zf';
secondPrisoner.id = '13';
上面的实例需要手动为每个对象设置name和id是痛苦的,因为会有重复的代码而显得不整洁。应使用Object.create的工厂模式。(原型的最优实现方案)
var proto = {
sentence: 4,
probation: 2
};
var makePrisoner = function(name, id) {
var prisoner = Object.create(proto);
prisoner.name = name;
prisoner.id = id;
return prisoner;
};
var firstPrisoner = makePrisoner('lmh', 13);
var secondPrisoner = makePrisoner('zf', 12);
注意:Object.create在IE6、7、8中不兼容,应使用下面的方法定义:
var objectCreate = function(arg) {
if (!arg) return {};
function obj() {};
obj.prototype = arg;
return new obj;
};
Object.create = Object.create || objectCreate;
原型链的作用域:
var proto = {
sentence: 4,
probation: 2
};
var makePrisoner = function(name, id) {
var prisoner = Object.create(proto);
prisoner.name = name;
prisoner.id = id;
return prisoner;
};
var firstPrisoner = makePrisoner('lmh', 13);
console.log(firstPrisoner); // 输出{sentence: 4, probation: 2, name: 'lmh', id: 13}
console.log(firstPrisoner._proto_); // 输出{sentence: 4, probation: 2}
console.log(firstPrisoner._proto_._proto_); // 输出{}
console.log(firstPrisoner._proto_._proto_._proto_); // 输出null
console.log(firstPrisoner._proto_._proto_._proto_._proto_); // error: firstPrisoner._proto_._proto_._proto_._proto_ is null
firstPrisoner.sentence = 10;
console.log(firstPrisoner.sentence); // 输出10
console.log(firstPrisoner._proto_.sentence); // 输出4,因为对象的原型并没有改变
proto.sentence = 10;
console.log(firstPrisoner.sentence); // 输出10
console.log(firstPrisoner._proto_.sentence); // 输出10
2.6函数
自执行匿名函数被用来控制变量的作用域,阻止变量被泄漏到代码中的其他地方(阴止污染全局变量);自执行函数,能解决全局变量被第三方库或者甚至是自己无意编写的代码所覆盖的问题。将值作为参数传给自执行匿名函数,就可以保证这个参数的值在执行环境中是你所期望的值,因为外部代码不能影响到它。
var prison = (function() {
var prisoner_name = 'lmh',
jail_term = '20';
return {
prisoner: prisoner_name + '-' + jail_term,
sentence: jail_term
}
})();
console.log(prison.jail_term) // 输出undefined,因为它不是自执行匿名函数返回的对象上的属性
prison.jail_term = 'zf';
console.log(prison.jail_term) // 输出zf
console.log(prison.prisoner); // 输出lmh-20
prison.prisoner没被更新,有几个原因。首先,jail_term不是prison对象或者原型上的属性,它是执行环境中创建的对象变量,prison变量保存了这个变量,并且执行环境已不复存在,因为函数已经执行结束。其次,这些属性只在匿名函数执行时设置一次,永远不会被更新。为了能更新它们,我们必须把属性转变为方法,每次调用它们时都会访问变量。如下:
var prison = (function() {
var prisoner_name = 'lmh',
jail_term = '20';
return {
prisoner: function() {
return prisoner_name + '-' + jail_term;
}
sentence: function(term) {
jail_term = term;
}
};
})();
console.log(prison.prisoner()); // 输出'lmh-20'
prison.sentence('18');
console.log(prison.prosoner()); // 输出'lmh-18'
2.6.4闭包
闭包是阻止垃圾回收器将变量从内存中移除的方法,使得在创建变量的执行环境的外面能够访问到该变量。