一个javascript prototype继承问题
高洛峰
高洛峰 2017-04-11 11:09:08
[JavaScript讨论组]

不知道为什么会报错,麻烦js大神给排查一下

报错say方法不存在

完整代码:

function person(name,age){
  this.name=name;
  this.age=age;
}
function coder(name,age,job){
  person.call(this,name,age);
  this.job=job;
}
person.prototype.say=function(){
  alert("我叫"+this.name);
}

function phh(){};

var ph=new phh();
phh.prototype=person.prototype;
coder.prototype=ph;
coder.prototype.constructor=coder;
coder.prototype.coding=function(){
  alert("我在"+this.job);
}

var p=new person("leo",32);
p.say();
var v=new coder("momo",23,"敲代码");
v.say(); //此处报方法不存在
v.coding();
高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回复(8)
大家讲道理

至于为什么报错:

var ph = new phh();
phh.prototype = person.prototype;

用构造器构造新对象时,新对象的原型指向当前构造器的原型,如果之后构造器的原型被指向其它对象,这一修改不会在已经构造的对象上有所体现。只有在原地修改对象时(不改变引用,只增添/修改/删除属性时)才会体现出来。

显然在构建 ph 的时候,构造器的原型 phh.prototype 还指向默认值,所以构造出的 ph 就不以 person 为原型了。

ph.__proto__ !== phh.prototype // true

调整下顺序

phh.prototype = person.prototype;
var ph = new phh();
    
ph.__proto__ === phh.prototype // true

顺便,
帮你重构了一下

function Person(name, age) {
    this.name = name;
    this.age = age;
}

function Coder(name, age, job) {
    Person.call(this, name, age);
    this.job = job;
}
Person.prototype.greet = function() {
    console.log("My name is " + this.name);
}

function Phh() {};

Phh.prototype = Person.prototype;
Coder.prototype = new Phh();
Coder.prototype.constructor = Coder;
Coder.prototype.intro = function() {
    console.log("My job is " + this.job);
}

var p = new Person("Leo", 32);
p.greet();
var v = new Coder("Momo", 23, "Coding");
v.greet();
v.intro();

继续重构:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    greet() {
        console.log("My name is " + this.name);
    }
}

class Phh extends Person {}

class Coder extends Phh {
    constructor(name, age, job) {
        super(name, age);
        this.job = job;
    }
    intro() {
        console.log("My job is " + this.job);
    }
}

var p = new Person("Leo", 32);
p.greet();
var v = new Coder("Momo", 23, "Coding");
v.greet();
v.intro();

进一步重构:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    greet() {
        console.log("My name is " + this.name);
    }
}

class Phh extends Person {
    constructor(name, age, job) {
        super(name, age);
        this.job = job;
    }
    intro() {
        console.log("My job is " + this.job);
    }
}

class Coder extends Phh {}

var p = new Person("Leo", 32);
p.greet();
var v = new Coder("Momo", 23, "Coding");
v.greet();
v.intro();

简化:

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    greet() {
        console.log('My name is ' + this.name);
    }
}

class Phh extends Person {
    constructor(name, age, job) {
        super(name, age);
        this.job = job;
    }
    intro() {
        console.log('My job is ' + this.job);
    }
}

class Coder extends Phh {
    constructor(name, age) {
        super(name, age, 'Coding');
    }
}

var p = new Person('Leo', 32);
p.greet();
var v = new Coder('Momo', 23);
v.greet();
v.intro();

输出:

My name is Leo
My name is Momo
My job is Coding

怪我咯

代码太乱了,我实在整理不过来,不过看到问题了:

var ph=new phh();
phh.prototype=person.prototype;

这两行位置对调一下,改成:

phh.prototype = person.prototype;
var ph = new phh();

原因自己再好好想想

巴扎黑

以下是我对@leftstick的答案的理解:

function phh(){}; 声明函数,phh.prototype将指向堆内存中一个区域,假定为区域a
var ph = new phh(); ph的__proto__属性,会通过phh.prototype找到区域a,并指向它(其实就是引用类型的赋值)
phh.prototype = anotherObj phh.prototype将指向一个新的区域,但是ph.__proto__还是指向的区域a


以上问题可以简化成如下代码

var a = {txt: 'haha'};
var b = a;
a = {txt: 'hehe'};
console.log(b.txt);    //console: haha
PHP中文网

v的原型对象是ph,ph的原型对象是Person.prototype。
js查找属性先从当前对象开始查找,然后沿着原型链,一直到Object.prototype 没有找到就报错

巴扎黑

@bf 说的比较明白了,具体可以看下 js 高程中,第六章-创建对象-原型的动态性。
主要是这句出了问题

phh.prototype = person.prototype;

因为原型也是对象,这句切断了构造函数和最初原型之间的联系。

巴扎黑

楼上正解。。。

黄舟

构造函数首字母建议大写!

高洛峰

leo,momo,这是秒味的吧。。。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号