🖥️
Log4think
  • Introduction
  • Archive
  • 2016-12-13 JavaScript 中几种不同的基于 prototype 继承方式的区别
  • 2014-09-02 Facebook的Dalvik运行期补丁
  • 2014-08-19 理解AnguarJS中的模板编译
  • 2014-08-13 在Android中使用OSGi框架(Knopflerfish)
  • 2014-08-13 在Android中使用OSGi框架(Apache Felix)
  • 2014-07-30 3rd-party apt-key list for Ubuntu
  • 2014-07-21 'Failed to clone a large git repository: The remote end hung up unexpectedly'
  • 2014-07-02 genymotion Qt error in Ubuntu
  • 2014-04-30 可自动安装依赖的Ubuntu离线包安装工具 gdebi
  • 2014-04-23 解决搜狗输入法Ubuntu 14.04下黑块状态条
  • 2014-04-08 Setup Ghost blog system on Ubuntu
  • 2014-03-28 Trace a process
  • 2014-03-25 Forecast::IO 599 Internal Exception
  • 2014-03-23 Mac Tips
  • 2014-01-17 LD_LIBRARY_PATH shouldn't contain the current directory
  • 2014-01-10 Python on vim
  • 2013-11-12 ibus-pinyin doesn't work in KUbuntu 13.10
  • 2013-11-11 phpMyAdmin login error to remote server
  • 2013-11-04 Get SNMP(v3) working on Ubuntu 12.04
  • 2013-10-30 Accessing Facebook by LWP
  • 2013-10-17 Log4perl多个Appender重复输出日志的问题解决办法
  • 2013-04-19 How to enable ORMLite internal log on Android
  • 2013-02-20 Bash Shortcuts
  • 2013-02-20 '"adb shell dumpsys" parameter list'
  • 2013-01-27 循环有序数组的二分查找
  • 2013-01-23 为Java运行环境导入根证书解决Eclipse的TFS插件的"PKIX path building failed"错误
  • 2013-01-21 ant 中通过重新定义 project.all.jars.path 在 classpath 中引入外部 jar 文件
  • 2012-09-22 Android的滚动条实现细节
  • 2012-02-05 hostname自动变成bogon的问题
  • 2011-07-09 代码段速记 gist.github.com
  • 2011-07-08 A perl Data.Dumper clone for Python
  • 2011-06-22 魔兽世界私服Trinity,从源码开始
  • 2011-06-13 魔兽世界3.3.5 13930登录数据包分析
  • 2011-06-13 魔兽世界 3.3.5 13930 Trinity 认证补丁
  • 2011-05-20 统一业务模型(UBM) in ERP5
  • 2011-03-08 制作ASCII字符动画
  • 2011-01-14 Ubuntu升级导致的udevd错误修复
  • 2011-01-09 行列有序矩阵求第K个数
  • 2011-01-09 字节按位逆序
  • 2011-01-01 编程之美 1.2 中国相帅问题的一个简洁解法
  • 2010-11-26 为Windows 7/Windows Server 2008添加IPX协议
  • 2010-11-12 How to debug with Android Logging
  • 2010-09-16 利用google-code-prettify做网页内源码的语法高亮
  • 2010-09-05 10 Ways We Hurt Our Romantic Relationships
  • 2010-08-30 利用ipkall+xlite+iptel.org开通google voice
  • 2010-08-27 避免Android开发中的ANR
  • 2010-08-27 在Eclipse中查看Android SDK的源代码
  • 2010-08-18 Git中判断一个commit是否在某个branch中
  • 2010-08-04 修正auto-excerpt产生带格式的摘要
  • 2010-03-31 Go 编程语言入门教程
  • 2010-03-13 利用外部VPS主机通过ssh隧道穿透防火墙连接内网
  • 2009-12-30 旋转矩阵
  • 2009-02-10 为什么cpio要比tar好
  • 2008-12-11 ThoughtWorks 的一道笔试题
  • 2008-11-18 长距离打车如何省钱?
  • 2007-02-08 ftp后台自动上传下载
  • 2006-06-12 vi cheatsheet
  • 2006-04-19 修正mysqlcc在MySQL 5.0上常报的 Table 'xxx' doesn't exist 错误
  • 2006-04-01 'Perl中不寻常的 ?: 运算符'
  • 2005-09-13 关于IoC、低耦合、配置文件及其本质意义的思考
  • 2005-09-13 Perl与数据库DBI快速入门
  • 2005-09-12 Perl无废话入门指南
  • 2005-07-16 Solaris 下安装Perl的DBD-mysql模块失败的原因以及解决办法
  • 2004-10-15 SharpDevelop的AddInTree View 插件
  • 2004-10-14 SharpDevelop源码分析 (完整版)
由 GitBook 提供支持
在本页
  • JavaScript 中几种不同的基于 prototype 继承方式的区别
  • 普通属性的继承
  • 对于定义在 prototype 里面的方法呢
  • 要执行所有构造函数
  • 利用 super 变量
  • 类似,但是用 Parent.apply 方法

这有帮助吗?

2016-12-13 JavaScript 中几种不同的基于 prototype 继承方式的区别

上一页Archive下一页2014-09-02 Facebook的Dalvik运行期补丁

最后更新于5年前

这有帮助吗?

JavaScript 中几种不同的基于 prototype 继承方式的区别

普通属性的继承

第一种方式

来自于

function Employee1 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
    this.work = function() {console.log("Employee.work")}
    this.workAsEmployee = function() { this.work() }
}

function WorkerBee1 (projs) {
    console.log('WorkerBee constructor')
    this.projects = projs || [];
    this.work = function() {console.log("WorkerBee.work")}
    this.workAsBee = function() { this.work() }
}
WorkerBee1.prototype = new Employee1;

function Engineer1 (mach) {
    console.log('Engineer constructor')
    this.dept = "engineering";
    this.machine = mach || "";
    this.work = function() {console.log("Engineer.work")}
    this.workAsEngineer = function() { this.work() }
}

Engineer1.prototype = new WorkerBee1;

e1 = new Engineer1()
e1.work()
console.log(Employee1.prototype.isPrototypeOf(e1))
console.log(WorkerBee1.prototype.isPrototypeOf(e1))
console.log(e1)

第二种方式

来自于 YUI 的实现,利用中间对象传递 prototype

function extend(Child, Parent) {
    var F = function () { };
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Object.defineProperty(Child, "super", { "value": Parent.prototype })
}

function Employee2 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
    this.work = function() {console.log("Employee.work")}
    this.workAsEmployee = function() { this.work() }
}

function WorkerBee2 (projs) {
    console.log('WorkerBee constructor')
    this.projects = projs || [];
    this.work = function() {console.log("WorkerBee.work")}
    this.workAsBee = function() { this.work() }
}
extend(WorkerBee2, Employee2);

function Engineer2 (mach) {
    console.log('Engineer constructor')
    this.dept = "engineering";
    this.machine = mach || "";
    this.work = function() {console.log("Engineer.work")}
    this.workAsEngineer = function() { this.work() }
}
extend(Engineer2, WorkerBee2);

e2 = new Engineer2()
e2.work()

console.log(Employee2.prototype.isPrototypeOf(e2))
console.log(WorkerBee2.prototype.isPrototypeOf(e2))
console.log(e2)

可以看到,区别主要在于,直接 Child.prototype = new Parent() 会把定义在 Parent 里面的方法也带到 prototype 里面去。另外,这种方式并没有执行父类的构造函数。

对于定义在 prototype 里面的方法呢

下面对上面的方法定义进行一点改进,把方法定义在 prototype 里,类似正常的 OO 编程中在类里面定义方法。

第一种方式改进

function Employee3 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
}
Employee3.prototype.work = function() {console.log("Employee.work")}
Employee3.prototype.workAsEmployee = function() { this.work() }

function WorkerBee3 (projs) {
    console.log('WorkerBee constructor')
    this.projects = projs || [];
}
WorkerBee3.prototype = new Employee3;
WorkerBee3.prototype.work = function() {console.log("WorkerBee.work")}
WorkerBee3.prototype.workAsBee = function() { this.work() }

function Engineer3 (mach) {
    console.log('Engineer constructor')
    this.dept = "engineering";
    this.machine = mach || "";
}
Engineer3.prototype = new WorkerBee3;
Engineer3.prototype.work = function() {console.log("Engineer.work")}
Engineer3.prototype.workAsEngineer = function() { this.work() }

e3 = new Engineer3()
e3.work()

console.log(Employee3.prototype.isPrototypeOf(e3))
console.log(WorkerBee3.prototype.isPrototypeOf(e3))
console.log(e3)

第二种方式的改进

function extend(Child, Parent) {
    var F = function () { };
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Object.defineProperty(Child, "super", { "value": Parent.prototype })
}

function Employee4 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
}
Employee4.prototype.work = function() {console.log("Employee.work")}
Employee4.prototype.workAsEmployee = function() { this.work() }

function WorkerBee4 (projs) {
    console.log('WorkerBee constructor')
    this.projects = projs || [];

}
extend(WorkerBee4, Employee4);
WorkerBee4.prototype.work = function() {console.log("WorkerBee.work")}
WorkerBee4.prototype.workAsBee = function() { this.work() }

function Engineer4 (mach) {
    console.log('Engineer constructor')
    this.dept = "engineering";
    this.machine = mach || "";
}
extend(Engineer4, WorkerBee4);
Engineer4.prototype.work = function() {console.log("Engineer.work")}
Engineer4.prototype.workAsEngineer = function() { this.work() }

e4 = new Engineer4()
e4.work()

console.log(Employee4.prototype.isPrototypeOf(e4))
console.log(WorkerBee4.prototype.isPrototypeOf(e4))
console.log(e4)

注意观察 constructor 和 __proto__ 属性。

要执行所有构造函数

上述第二种方法,都没有执行父类的构造函数,也就没有真正的继承父类的初始化数据。为了弥补这一点,如下两种写法都可以达到目的。

利用 super 变量

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

function Employee5 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
}
Employee5.prototype.work = function() {console.log("Employee.work")}
Employee5.prototype.workAsEmployee = function() { this.work() }

function WorkerBee5 (projs) {
    console.log('WorkerBee constructor')

    this.super = Employee5;
    this.super();

    this.projects = projs || [];

}
extend(WorkerBee5, Employee5);
WorkerBee5.prototype.work = function() {console.log("WorkerBee.work")}
WorkerBee5.prototype.workAsBee = function() { this.work() }

function Engineer5 (mach) {
    console.log('Engineer constructor')

    this.super = WorkerBee5;
    this.super();

    this.dept = "engineering";
    this.machine = mach || "";
}
extend(Engineer5, WorkerBee5);
Engineer5.prototype.work = function() {console.log("Engineer.work")}
Engineer5.prototype.workAsEngineer = function() { this.work() }

e5 = new Engineer5()
e5.work()

console.log(Employee5.prototype.isPrototypeOf(e5))
console.log(WorkerBee5.prototype.isPrototypeOf(e5))
console.log(e5)

类似,但是用 Parent.apply 方法

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

function Employee6 (name, dept) {
    console.log('Employee constructor')
    this.name = name || "";
    this.dept = dept || "general";
}
Employee6.prototype.work = function() {console.log("Employee.work")}
Employee6.prototype.workAsEmployee = function() { this.work() }

function WorkerBee6 (projs) {
    console.log('WorkerBee constructor')
    Employee6.apply(this)
    this.projects = projs || [];
}
extend(WorkerBee6, Employee6);
WorkerBee6.prototype.work = function() {console.log("WorkerBee.work")}
WorkerBee6.prototype.workAsBee = function() { this.work() }

function Engineer6 (mach) {
    console.log('Engineer constructor')
    WorkerBee6.apply(this)
    this.dept = "engineering";
    this.machine = mach || "";
}
extend(Engineer6, WorkerBee6);
Engineer6.prototype.work = function() {console.log("Engineer.work")}
Engineer6.prototype.workAsEngineer = function() { this.work() }

e6 = new Engineer6()
e6.work()

console.log(Employee6.prototype.isPrototypeOf(e6))
console.log(WorkerBee6.prototype.isPrototypeOf(e6))
console.log(e6)
MDN 对象模型的细节