复制属性继承(Inheritance by Copying Properties)

让我们看一下另一个继承模式—复制属性继承(inheritance by copying properties)。在这个模式中,一个对象从另一个对象获取功能,简单的通过复制它。
下面是函数extend()简单实现的一个例子:
function extend(parent, child) {
var i;
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
child[i] = parent[i];
}
}
return child;
}

它是一个简单实现,仅仅依次遍历parent的成员并复制它们。在这个实现中,child是可选的;如果你不传递一个已经存在的对象去扩展,那么一个新对象被创建并被返回。

var dad = {name: "Adam"};
var kid = extend(dad);
kid.name; // "Adam"

给出的这种实现就是所谓的对象的"浅复制(shallow copy)"。深度复制另一方面意味着检查你将要复制的属性是否是一个对象或者是一个数组,如果是,递归的遍历它的属性并
同样的复制它们。使用浅复制(因为对象在JavaScript中通过引用传递),如果你改变child的属性,并且这个属性碰巧是一个对象,那么你也会修改(所有的)parent。

这种情况实际上对于方法来说是更可取的(因为函数也是对象并通过引用传递),但作用在其它对象和数组的时候可能会导致意外。设想一下:
var dad = {
counts: [1, 2, 3],
reads: {
paper: true
}
};
var kid = extend(dad);
kid.counts.push(4);
dad.counts.toString(); // "1,2,3,4"
dad.reads === kid.reads; // true

现在让我们修改extend()函数实现深度复制。你要做的就是检查属性的类型是否是个对象,如果是,递归复制它的属性。

你需要的另外一个检查是对象是否是一个真正的对象或者是否是个数组。让我们使用在前面讨论过的数组检查。
那么extend()的深度拷贝版本可能看起来像这样:
function extendDeep(parent, child) {
var i, toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}

现在测试新实现给我们提供给我们的真正的对象的复制,那么child对象不会修改它们的parents:

var dad = {
counts: [1, 2, 3],
reads: {
paper: true
}
};
var kid = extendDeep(dad);
kid.counts.push(4);
kid.counts.toString(); // "1,2,3,4"
dad.counts.toString(); // "1,2,3"
dad.reads === kid.reads; // false
kid.reads.paper = false;
kid.reads.web = true;
dad.reads.paper; // true

这种属性复制模式简单并且被广泛使用;比如Firebug(使用JavaScript写的Firefox扩展)有一个叫做extend()的方法实现了一个浅复制,和jQuery的extend()实现了一个深度复制。YUI3提供一个方法叫做Y.clone(),提供一个深度复制并且通过绑定函数到child对象复制函数(接下来内容会有更多的绑定)。

有价值的是在这种模式中压根就没有原型(prototype),仅关系到对象和它们的属性。

JavaScript学习笔记(三十八) 复制属性继承的更多相关文章

  1. 【Unity 3D】学习笔记三十八:角色控制器

    角色控制器 在unity中,已经帮我们实现的上下左右跳等动作,并将他们封装成了角色控制器.角色控制器保存在unity标准资源包中,能够说是很的强大.能够模拟第一或者第三人称视角.不受刚体的限制,很适用 ...

  2. PHP学习笔记三十八【下载】

    <?php //演示下载一个图片 $file_name="SunSet.jpg"; $file_name=iconv("utf-8","gb23 ...

  3. Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)

    在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...

  4. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  5. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  6. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  7. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  8. angular学习笔记(三十)-指令(5)-link

    这篇主要介绍angular指令中的link属性: link:function(scope,iEle,iAttrs,ctrl,linker){ .... } link属性值为一个函数,这个函数有五个参数 ...

  9. angular学习笔记(三十)-指令(2)-restrice,replace,template

    本篇主要讲解指令中的 restrict属性, replace属性, template属性 这三个属性 一. restrict: 字符串.定义指令在视图中的使用方式,一共有四种使用方式: 1. 元素: ...

随机推荐

  1. C程序设计语言练习题1-14

    练习1-14 编写一个程序,打印输入中各个字符出现频度的直方图. 代码如下: #include <stdio.h> // 包含标准库的信息. int main() // 定义名为main的 ...

  2. Math对象

    <script type="text/javascript"> /* Math对象常用的方法: ceil 向上取整 floor() 向下取整 random() 随机数方 ...

  3. IO通信

    DeviceIoControl 发送控制代码到指定设备驱动程序 参数解释: hDevice Long,设备句柄 dwIoControlCode Long,应用程序调用驱动程序的控制命令,就是IOCTL ...

  4. Laravel 依赖注入原理

    众所周知 Laravel 的文档对于依赖注入只写了如何使用,相信大多数人对于他的实现原理并不太清楚.虽然使用过程中并不需要关心她的原理,但是了解原理让你使用起来更自信.这个帖子就通过一个小 demo ...

  5. Uubntu E: Sub-process /usr/bin/dpkg returned an error code问题的解决办法

      cd /var/lib/dpkg   sudo mv info info.bak   sudo mkdir info      apt-get --reinstall install udev m ...

  6. Ubuntu 下启动/停止/重启mysql服务

    1:sudo start mysql 2:sudo stop mysql 3:sudo restart mysql

  7. 51单片机C语言学习笔记7:关于.c文件和.h文件

    1)h文件作用 1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明: 2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h). 2)h文件里应该有什么 ...

  8. Windows 系统版本判断

    Windows 系统版本判断 博客分类: C/C++   很多情况下,需要软件判断操作系统,其实网上写的都很少,我希望这篇文章能给大家帮助 首先我们要在.h中定义下面的东西 #define PRODU ...

  9. http协议使用实例

    #include <stdio.h>#include <windows.h>#include <wininet.h> #define MAXSIZE 1024#pr ...

  10. Android中ListView通过BaseAdapter实现数据的绑定

    1. public class ListFiles extends Activity { ListView Listview=null; protected void onCreate(Bundle ...