JavaScript 面向对象编程(三):非构造函数对象的继承
JavaScript 面向对象编程(三):非构造函数对象的继承
一、什么是"非构造函数"的继承?
比如,现在有一个对象,叫做"中国人"。
var Chinese = {
nation:'中国'
};
还有一个对象,叫做"医生"。
var Doctor ={
career:'医生'
}
请问怎样才能让"医生"去继承"中国人",也就是说,我怎样才能生成一个"中国医生"的对象?
这里要注意,这两个对象都是普通对象,不是构造函数,无法使用构造函数方法实现"继承"。
二、object()方法
json格式的发明人Douglas Crockford,提出了一个object()函数,可以做到这一点。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
这个object()函数,其实只做一件事,就是把子对象的prototype属性,指向父对象,从而使得子对象与父对象连在一起。
使用的时候,第一步先在父对象的基础上,生成子对象:
var Doctor = object(Chinese);
然后,再加上子对象本身的属性:
Doctor.career = '医生';
这时,子对象已经继承了父对象的属性了。
alert(Doctor.nation); //中国
注意:打印一下Doctor看一下

Doctor.nation是在__proto__下面的对象,为什么会直接被找到呢?
答案是:
当一个对象需要引用一个属性时,JavaScript引擎首先会从这个对象自身的属性表中寻找这个属性标识,
如果找到则进行相应读写操作,如果没有在自身的属性表中找到
则在_proto_属性引用的对象(原型对象)的属性表中查找,如此往复,直到找到这个属性或者_proto_属性指向null为止(object prototype )。
三、浅拷贝
除了使用"prototype链"以外,还有另一种思路:把父对象的属性,全部拷贝给子对象,也能实现继承。
下面这个函数,就是在做拷贝:
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
使用的时候,这样写:
var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国
但是,这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。
请看,现在给Chinese添加一个"出生地"属性,它的值是一个数组。
Chinese.birthPlaces = ['北京','上海','香港'];
通过extendCopy()函数,Doctor继承了Chinese。
var Doctor = extendCopy(Chinese);
然后,我们为Doctor的"出生地"添加一个城市:
Doctor.birthPlaces.push('厦门');
发生了什么事?Chinese的"出生地"也被改掉了!
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门
所以,extendCopy()只是拷贝基本类型的数据,我们把这种拷贝叫做"浅拷贝"。这是早期jQuery实现继承的方式。
四、深拷贝
所谓"深拷贝",就是能够实现真正意义上的数组和对象的拷贝。它的实现并不难,只要递归调用"浅拷贝"就行了。
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('厦门');
这时,父对象就不会受到影响了。
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港
目前jquery库使用的就是这种方法,深拷贝进行继承的。
关于JavaScript的面向对象编程三节课已经全部完成,
本随笔是参考阮一峰的文章。http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
转发请附文章来源。
JavaScript 面向对象编程(三):非构造函数对象的继承的更多相关文章
- (三)Javascript面向对象编程:非构造函数的继承
Javascript面向对象编程:非构造函数的继承 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使 ...
- 转载:javascript面向对象编程:非构造函数的继承
一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese = { nation:'中国' }; 还有一个对象,叫做&qu ...
- Javascript面向对象编程:非构造函数的继承
今天是最后一个部分,介绍不使用构造函数实现"继承". 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Ch ...
- JavaScript面向对象编程(一)原型与继承
原型(prototype) JavaScript是通过原型(prototype)进行对象之间的继承.当一个对象A继承自另外一个对象B后,A就拥有了B中定义的属性,而B就成为了A的原型.JavaScri ...
- Javascript 面向对象编程2:构造函数的继承
这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例.对象之间的"继承"的五种方法.比如,现在有一个"动物"对象 ...
- JavaScript面向对象编程(10)高速构建继承关系之对象拷贝
前面的样例我们是通过构造器创建对象.而且希望该对象继承来自另外一个构造器的对象 我们也能够直接面向一个对象来达成继承的目的.使用下属步骤: 1.拷贝一个对象 2.给新对象加入属性 /** * 通过拷贝 ...
- JavaScript面向对象编程(9)高速构建继承关系之整合原型链
前面我们铺垫了非常多细节.是为了让大家更加明晰prototype的使用细节: 如今能够将前面的知识整合起来,写一个函数用于高速构建基于原型链的继承关系了: function extend(Child, ...
- JavaScript 面向对象编程(三)如何写类和子类
在JavaScript面向对象编程(一)原型与继承和JavaScript面向对象编程(二)构造函数和类中,我们分别讨论了JavaScript中面向对象的原型和类的概念.基于这两点理论,本篇文章用一个简 ...
- JavaScript面向对象编程(二)构造函数和类
new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...
随机推荐
- Oracle 11G R2在用EXP 导出时,空表不能导出解决办法
11G中有个新特性,当表无数据时,不分配segment,以节省空间 解决方法: 1.insert一行,再rollback就产生segment了. 该方法是在在空表中插入数据,再删除,则产生segmen ...
- 【ABP开发】:asp.net core 中使用mysql
EntityFrameworkCore项目--Nuget包管理,卸载包: Microsoft.EntityFrameworkCore.SqlServer: EntityFrameworkCore项目和 ...
- photoshop中魔棒工具的使用
魔术棒工具一般用于纯色背景快速扣图,打开魔术棒工具,设定容差,点击选定背景,清除,文件-保存为png格式图片.ok! 魔棒工具是photoshop中提供的一种比较快捷的抠图工具,对于一些分界线比较明显 ...
- TensorFlow入门测试程序
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist=input_data. ...
- Hello World 十大秘密
#include <stdio.h> int main(int argc, char* argv[], char* env[]) { printf("Hello World\n& ...
- 原生JS实现图片拖拽移动与缩放
看一下最终效果,图片可以拖动,可以缩放 把代码贴出来,可以直接粘贴使用,大致的思想就是鼠标按下的时候获取当时的鼠标位置,要减去left和top值,移动的时候获取位置减去初始的值就得到移动的时候的lef ...
- pageX,clientX,offsetX,screenX,offsetLeft,style.left,offsetWidth,scrollWidth的区别以及使用详解
https://www.cnblogs.com/echolun/p/9231760.html
- js arguments 和 reduce求和
1.js arguments arguments 是一个对应于传递给函数的参数的类数组对象 function sum(){ ; ; i < arguments.length; i++){ sum ...
- VSCode创建自定义用户片段
1.选择相应的用户片段类型(以"Java"为例) 首选项 -> 用户代码片段 -> java 2.设置模板 prefix 触发快捷提示的字符串前缀 body 代码片段主 ...
- tcp的半连接与完全连接队列(二)
队列及参数 server端的半连接队列(syn队列) 在三次握手协议中,服务器维护一个半连接队列,该队列为每个客户端的SYN包开设一个条目(服务端在接收到SYN包的时候,就已经创建了request_s ...