深入理解JavaScript系列(46):代码复用模式(推

模式1:原型继承

原型继承是让父对象作为子对象的原型,从而达到继承的目的:

复制代码 代码如下:


function object(o) {
    function F() {
    }

F.prototype = o;
    return new F();
}

// 要继承的父对象
var parent = {
    name: "Papa"
};

// 新对象
var child = object(parent);

// 测试
console.log(child.name); // "Papa"


// 父构造函数
function Person() {
    // an "own" property
    this.name = "Adam";
}
// 给原型添加新属性
Person.prototype.getName = function () {
    return this.name;
};
// 创建新person
var papa = new Person();
// 继承
var kid = object(papa);
console.log(kid.getName()); // "Adam"


// 父构造函数
function Person() {
    // an "own" property
    this.name = "Adam";
}
// 给原型添加新属性
Person.prototype.getName = function () {
    return this.name;
};
// 继承
var kid = object(Person.prototype);
console.log(typeof kid.getName); // "function",因为是在原型里定义的
console.log(typeof kid.name); // "undefined", 因为只继承了原型


同时,ECMAScript5也提供了类似的一个方法叫做Object.create用于继承对象,用法如下:

复制代码 代码如下:


/* 使用新版的ECMAScript 5提供的功能 */
var child = Object.create(parent);

var child = Object.create(parent, {
    age: { value: 2} // ECMA5 descriptor
});
console.log(child.hasOwnProperty("age")); // true

而且,也可以更细粒度地在第二个参数上定义属性:

复制代码 代码如下:


// 首先,定义一个新对象man
var man = Object.create(null);

// 接着,创建包含属性的配置设置
// 属性设置为可写,可枚举,可配置
var config = {
    writable: true,
    enumerable: true,
    configurable: true
};

// 通常使用Object.defineProperty()来添加新属性(ECMAScript5支持)
// 现在,为了方便,我们自定义一个封装函数
var defineProp = function (obj, key, value) {
    config.value = value;
    Object.defineProperty(obj, key, config);
}

defineProp(man, 'car', 'Delorean');
defineProp(man, 'dob', '1981');
defineProp(man, 'beard', false);

所以,继承就这么可以做了:

复制代码 代码如下:


var driver = Object.create( man );
defineProp (driver, 'topSpeed', '100mph');
driver.topSpeed // 100mph


但是有个地方需要注意,就是Object.create(null)创建的对象的原型为undefined,也就是没有toString和valueOf方法,所以alert(man);的时候会出错,但alert(man.car);是没问题的。

模式2:复制所有属性进行继承

这种方式的继承就是将父对象里所有的属性都复制到子对象上,一般子对象可以使用父对象的数据。

先来看一个浅拷贝的例子:

复制代码 代码如下:


/* 浅拷贝 */
function extend(parent, child) {
    var i;
    child = child || {};
    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            child[i] = parent[i];
        }
    }
    return child;
}

var dad = { name: "Adam" };
var kid = extend(dad);
console.log(kid.name); // "Adam"

var dad = {
    counts: [1, 2, 3],
    reads: { paper: true }
};
var kid = extend(dad);
kid.counts.push(4);
console.log(dad.counts.toString()); // "1,2,3,4"
console.log(dad.reads === kid.reads); // true

代码的最后一行,你可以发现dad和kid的reads是一样的,也就是他们使用的是同一个引用,这也就是浅拷贝带来的问题。

我们再来看一下深拷贝:

复制代码 代码如下:


/* 深拷贝 */
function extendDeep(parent, child) {
    var i,
        toStr = Object.prototype.toString,
        astr = "[object Array]";

child = child || {};

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgfggy.html