首页 > 请问以下两种通过原型继承创建一个新对象的方式有何不同,请说明原因?

请问以下两种通过原型继承创建一个新对象的方式有何不同,请说明原因?

方式一:

 function inherit(p) {
        if (p == null) {
            throw TypeError();
        }
        var t = typeof p;
        if(t!=="object" && t!=="function"){
            throw TypeError();
        }
        var o = {};
        for(var prop in p){
            o[prop]=p[prop];
        }
        return o;
    }

方式二:

 function inherit(p) {
        if( t===null){
            throw TypeError();
        }
        var t = typeof p;

        if(t!=="object" && t!== "function"){
            throw TypeError();
        }
        var f = function(){};
        f.prototype=p;
        return new f();
    }


方法1只是逻辑上的原型继承,其实没有用到js的原型链机制


简而言之,区别就是:

而且1中的复制只是复制了可枚举属性。读一下ES规范就会发现:原型这种东西就是为了共享属性而设计的。

再多说一句:

通过原型共享来的属性有个特点,就是:你去读它的时候,它会到原型链上去查找;但你去写它的时候,他会在当前对象上新建一个同名属性,相当于覆盖了原型链上的同名属性。正是这个特点实现了JS面向对象的两个特性:继承(inherit)和重载(override)。也就是,既可以继承祖先的共同性,又可以自定义自身的独特性。

代码@小_秦写的很多了,他的代码正是体现了两者的区别,赞一个。


第1段代码应该返回对象o
2段代码都能实现从p对象继承属性及方法,但是有些差别
这个差别就在于for(var prop in p){的使用,其只能取出p对象中可枚举的属性,而f.prototype=p;就没有这个问题
例如

function inherit1(p) {
    if (p == null) {
        throw TypeError();
    }
    var t = typeof p;
    if(t!=="object" && t!=="function"){
        throw TypeError();
    }
    var o = {};
    for(var prop in p){
        o[prop]=p[prop];
    }
    return o;
}

function inherit2(p) {
    if( t===null){
        throw TypeError();
    }
    var t = typeof p;

    if(t!=="object" && t!== "function"){
        throw TypeError();
    }
    var f = function(){};
    f.prototype=p;
    return new f();
}

function P(){
    //设置属性b不可枚举
    Object.defineProperty(this, 'b', { value: 2, enumerable: false });
}
P.prototype.methodA=function(){
    console.log('methodA');
}

var o=inherit1(new P());
console.log(o.b);//undefined
o.methodA();//methodA

o=inherit2(new P());
console.log(o.b);//2
o.methodA();//methodA

第一段的代码有误吧? 最后居然是 return p ????

在将第一段代码中的 return p 改为 return o 后, 分析如下:

function inherit1(p) {
    if (p == null) {
        throw TypeError();
    }
    var t = typeof p;
    if (t !== "object" && t !== "function") {
        throw TypeError();
    }
    var o = {};//创建一个新的对象
    for (var prop in p) {//然后将 p 中的可遍历的内容, 添加至 o 中
        o[prop] = p[prop];
    }
    return o;//返回 新创建出来的这个对象(所以这里不是能 return p, 否则 前面的操作是无意义的)
}

function inherit2(p) {
    if (t === null) {
        throw TypeError();
    }
    var t = typeof p;

    if (t !== "object" && t !== "function") {
        throw TypeError();
    }

    var f = function() {};//创建一个空函数(当然它也是一个对象)
    f.prototype = p;//修改新创建的这个函数的 prototype 指向 参数 p
    return new f();//返回新创建的这个函数的 实例
}


var p = {//测试数据
    x:1,
    y:function(){
        return this.x;
    }
};

console.log('=========== test1 ==========');
var a = inherit1(p);//通过方法1 得到的结果 a
    /**
        上面的代码, 分解如下:
        var t = {};//创建临时对象
        t.x = p.x;
        t.y = p.y;

        var a = t;
    */

console.log(a.x, a.y(), a.hasOwnProperty('x'));//可以正常使用 p 中的x,y(但请注意 hasOwnProperty这个的结果)

a.x = 222;//尝试修改它
console.log(a.x, a.y(), a.hasOwnProperty('x'));//再次输出(请注意输出结果)
delete a.x;//删除它
console.log(a.x, a.y(), a.hasOwnProperty('x'));//再次输出(请注意输出结果)



console.log('=========== test2 ==========');
var c = inherit2(p);//通过方法1 得到的结果 c
    /**
        上面的代码, 分解如下:
        var t = function(){};
        t.prototype = p;

        var c = new t();
    */

console.log(c.x, c.y(), c.hasOwnProperty('x'));//可以正常使用 p 中的x,y(但请注意 hasOwnProperty这个的结果)

c.x = 222;//尝试修改它
console.log(c.x, c.y(), c.hasOwnProperty('x'));//再次输出(请注意输出结果)
delete c.x;//删除它
console.log(c.x, c.y(), c.hasOwnProperty('x'));//再次输出(请注意输出结果)

执行结果:

=========== test1 ==========
1 1 true
222 222 true
undefined undefined false
=========== test2 ==========
1 1 false
222 222 true
1 1 false
【热门文章】
【热门文章】