跳到主要内容

1 篇博文 含有标签「闭包」

查看所有标签

· 阅读需 6 分钟

闭包与继承组合学习,加深记忆。

闭包

通过一个函数,能够访问另一个函数作用域的变量的函数

function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();//Mozilla

function a(x) {
var y = 4;
function b() {
console.log(x+y)
}
return b
}
var c = a(3)
c() // 7

构造函数继承

call apply方式 构造函数绑定

function Animal() {
this.species = '动物'
}
function Cat(name, color) {
Animal.apply(this, arguments)
this.name = name
this.color = color
}
var cat1 = new Cat('大俊', '黑色')
console.log(cat1.species) //动物

使用call和apply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题.

prototype模式

function Animal() {
this.species = '动物'
}
function Cat(name, color) {
this.name = name
this.color = color
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat
var cat1 = new Cat('大俊', '黑色')
console.log(cat1.species) //动物

问题是不能给父构造函数传递参数, 父子构造函数的原型对象之间有共享问题.

直接继承prototype

function Animal() {}
Animal.prototype.species = '动物'
function Cat(name, color) {
this.name = name
this.color = color
}
Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat
var cat1 = new Cat('大俊', '黑色')
console.log(cat1.species) //动物
console.log(Animal.prototype.constructor) //Cat

缺点是 Cat.prototype和Animal.prototype,现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。 只能继承父构造函数的原型对象上的成员, 不能继承父构造函数的实例对象的成员, 同时父构造函数的原型对象和子构造函数的原型对象上的成员有共享问题

利用空对象作为中介

function Animal() {}
Animal.prototype.species = '动物'
function Cat(name, color) {
this.name = name
this.color = color
}
var F = function () {}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat
var cat1 = new Cat('大俊', '黑色')
console.log(cat1.species)//动物
//封装
function extend(Child, Parent) {
var F = function () {}
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.uber = Parent.prototype//为子对象设一个uber属性,
// 这个属性直接指向父对象的prototype属性为了实现继承的完备性,纯属备用性质。
}
//使用
extend(Cat, Animal)
var cat1 = new Cat('大俊', '黑色')
console.log(cat1.species)//动物

拷贝继承

function Animal() {}
Animal.prototype.species = '动物'
function Cat(name, color) {
this.name = name
this.color = color
}
function extend2(Child, Parent){
var p = Parent.prototype
var c = Child.prototype
for(var x in p){
c[x] = p[x]
}
c.uber = p
}
extend2(Cat, Animal)
var cat1 = new Cat()
console.log(cat1.species)

拷贝继承的问题,如果继承过来的成员是引用类型的话,那么这个引用类型的成员在父对象和子对象之间是共享的,也就是说修改了之后, 父子对象都会受到影响.

非构造函数继承

object()方法

var Animal = {
species: "动物"
}
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var Cat = object(Animal);
Cat.name = "大俊";
console.log(Cat.species)//动物

浅拷贝

var Animal = {
species: "动物"
}
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
var Cat = extendCopy(Animal);
Cat.name = "大俊";
console.log(Cat)//动物

这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。
var Animal = {
species: "动物"
}
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
Animal.do = ["吃", "喝"];
var Cat = extendCopy(Animal);
Cat.do.push("睡觉");
console.log(Cat.do)//["吃", "喝", "睡觉"]
console.log(Animal.do)//["吃", "喝", "睡觉"]

3、深拷贝

深拷贝,就是能够实现真正意义上的数组和对象的拷贝。递归调用"浅拷贝"就行了。

var Animal = {
species: "动物"
}
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
Animal.do = ["吃", "喝"];
var Cat = deepCopy(Animal);
Cat.do.push("睡觉");
console.log(Cat.do)//["吃", "喝", "睡觉"]
console.log(Animal.do)//["吃", "喝"]

学习地址 http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html;