1. 执行环境及作用域
- 执行环境定义了变量或函数有权访问的其他数据,决定它们各自的行为,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和对象也都保存在对象中。
- 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推进一个环境栈中,函数执行后,栈将其环境推出,把控制权返回给之前的执行环境。
2. 原型链:通过将一个类型的实例赋值给另一个构造函数的原型实现。
继承:
父类:
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
- 原型链继承:可在不必预先定义构造函数的情况下继承,将父类的实例作为子类的原型
function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.eat('fish')); console.log(cat.sleep()); console.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true
- 寄生式继承:类似原型式继承,基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。
- 构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
- 实例继承:为父类实例添加新特性,作为子类返回
function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // false
- 拷贝继承:
function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } Cat.prototype.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
- 组合继承:通过调用父类构造函数,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true
- 寄生组合继承:通过寄生的方式,砍掉父类的实例属性,这样,在调用两次弗雷德构造的时候,就不会初始化两次实例方法/属性,避免组合继承的缺点。
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true Cat.prototype.constructor = Cat; // 需要修复下构造函数
3. 创建对象:
- 工厂模式:抽象了创建具体对象的过程,对对象添加属性、方法。然后返回对象,可创建多个相似对象,不能解决对象识别问题。
- 构造函数模式:可以创建自定义引用类型,可以像创建内容对象实例一样使用new操作符。成员不可复用。
- 原型模式:使用构造函数的prototype属性来指定那些应该共享的属性和方法。创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象。不必再构造函数中定义对象实例的信息,而可以将这些信息直接添加到原型对象中。
4. 闭包:有权访问另一个函数作用域中的变量函数。创建方式:在函数内部创建另一个函数。
闭包只能取得包含函数中任何变量的最后一个值。