js 对象继承

最近在看阮老大的对象继承,Javascript面向对象编程(二):构造函数的继承

,但是我自己跑了下代码,发现几个问题,不知道是哪里不对。三个问题:
1、构造函数apply方式

        //打印object
        function logObj(obj) {
            console.log('new OBJECT LOG-------------------------------');
            for(var prop in obj) {
                console.log(`${prop} == ${obj[prop]}`);
            }
        }
        function Person(name, sex) {
            this.name = name;
            this.sex = sex;
            this.fav = 'read';
        }
        Person.prototype.say = function() { //公用方法
            console.log(`I'm ${this.name},and my sex is ${this.sex}`);
        }
                function People(name,sex,nation){
                    Person.apply(this,arguments);
                    this.nation = nation;
                }
                var me = new People('li','man','China');
                console.log(me);
                me.say();//报错未定义

apply构造函数继承的方式,拿不到person的say共有方法.
2、另外一种继承方式,

                function People(nation) {
                    this.nation = nation;
                }
                People.prototype = new Person();
                console.log(People.prototype.constructor);  
                People.prototype.constructor = People;
                var me = new People('China');
                logObj(me);

通过继承父类实例倒是可以拿到属性和公用方法,但是父类属性是undefined.子类实例构造函数参数中,又该如何重修改父类的属性呢,比如name,难道只能是通过me.name来修改吗
3、直接继承原型



        function extend(Child, Parent) { 
            var F = function() {};
            F.prototype = Parent.prototype;
            Child.prototype = new F();
            Child.prototype.constructor = Child;
        }

        function People(nation) {
            this.nation = nation;
        }
        extend(People, Person);
        var he = new People('China');
        logObj(he);
        console.log(he.name);//undefined
        console.log(he.fav);  //undefined

发现这种继承方式可以拿到共有方法say,但是继承不到父级Class的属性name和sex,fav。

感觉每个都不对啊,后面还有个拷贝继承,添加新属性的时候都报错了,说明原型链上就没有啊

//深拷贝
        var Chinese = {    
            nation: '中国',
            fav: 'read'  
        }; 
        var Doctor = {    
            career: '医生'  
        }

        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;  
        }
        var Doctor = deepCopy(Chinese);
        Chinese.birthPlaces = ['北京', '上海', '香港'];  
        Doctor.birthPlaces.push('厦门'); //报错
        logObj(Chinese);
        logObj(Doctor);
阅读 2.3k
3 个回答
apply构造函数继承的方式,拿不到person的say共有方法.
首先要理解构造函数,new和构造函数内部的this是什么
function Person(name, sex) {
    this.name = name;
    this.sex = sex;
    this.fav = 'read';
}

new Person() 内部首先是创建了一个Object实例person {},this指向的就是这个{},最后return 这个person 实例;
单独执行Person时,这个this没有意义,严格模式下报错,非严格模式下指向window;

function People(name,sex,nation){
    Person.apply(this,arguments);
    this.nation = nation;
}

Person.apply(this,arguments)只是执行Person这个方法,并且将Person方法内部的this替换为People方法中的this,相当于复制了

this.name = name;
this.sex = sex;
this.fav = 'read';

这种方式构造函数的prototype相互独立,两个类型并没有继承关系,无法让 instanceof 为 true;
为了弥补这一缺点,就要引入第二张方法,让People.prototype指向Person实例。
两个方法结合应该是这样:

 function People(name,sex,nation){
    Person.apply(this,arguments);
    this.nation = nation;
}
People.prototype = new Person();
console.log(People.prototype.constructor);  
People.prototype.constructor = People;

这样就继承了父类原型上的方法,而属性则是自己拷贝过来的。
如果我们完全重写自己的构造函数,并只继承父类的方法,则适合用第三种方法(比如说父类中的属性都是私有的情况);
拷贝继承说是继承,其实就是个对象复制,跟继承完全没啥关系了;
js中的继承都是通过原型链实现的,个人感觉这种实现方式有点“虚”,你有兴趣可以对比一下虚表继承。

你应该是对这几个方法有误解:它们不是等效的继承方式的不同实现,而是各有各缺陷的实现方式。你注意到的正是这些方式的缺陷。

class People extends Person {} 不就解决了,何必那么纠结。JavaScript 本来就不是标准 OOP,而是通过原型来实现的 OOP,难免存在各种缺陷。既然 ES6 都提供了 extends,何必再去纠结那些缺陷呢。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题