JavaScript代码复用模式详解


Posted in Javascript onNovember 07, 2014

代码复用及其原则

代码复用,顾名思义就是对曾经编写过的代码的一部分甚至全部重新加以利用,从而构建新的程序。在谈及代码复用的时候,我们首先可以想到的是继承性。代码复用的原则是:

优先使用对象组合,而不是类继承

在js中,由于没有类的概念,因此实例的概念也就没多大意义,js中的对象是简单的键-值对,可以动态的创建和修改它们。

但在js中,我们可以使用构造函数和new操作符来实例化一个对象,这与其他使用类的编程语言在语法上有其相似之处。

例如:

var trigkit4 = new Person();

js在调用构造函数Person时似乎看起来是一个类,但其实际上仍然是一个函数,这让我们产生了一些假定在类的基础上的开发思路和继承模式,我们可以称之为“类式继承模式”。

传统的继承模式是需要class关键字的,我们假定以上的类式继承模式为现代继承模式,这是一种不需要以类的方式考虑的模式。

类式继承模式

看下面两个构造函数Parent()Child()的例子:

<script type="text/javascript">
    function Parent(name){
        this.name = name || 'Allen';
    }
    Parent.prototype.say = function(){
        return this.name;
    }
    function Child(name){}
    //用Parent构造函数创建一个对象,并将该对象赋值给Child原型以实现继承
    function inherit(C,P){
        C.prototype = new P();//原型属性应该指向一个对象,而不是函数
    }
    //调用声明的继承函数
    inherit(Child,Parent);
</script>

当使用new Child()语句创建一个对象时,它会通过原型从Parent()实例获取它的功能,比如:

var kid = new Child();
kid.say();
//Allen

原型链

讨论一下类式继承模式下原型链的工作原理,我们将对象看做是内存中某处的块,该内存块包含数据以及指向其他块的引用。当用new Parent()语句创建一个对象时,就会创建如下图左边的这样一个块,这个块保存了name属性,如果想访问say()方法,我们可以通过指向构造函数Parent()prototype(原型)属性的隐式链接__proto__,便可访问右边区块Parent.prototype

JavaScript代码复用模式详解

那么,当使用var kid = new Child()创建新对象时会发生什么?如下图:

JavaScript代码复用模式详解

使用new Child()语句所创建的对象除了隐式链接__proto__外,它几乎是空的。这种情况下,__proto__指向了在inherit()函数中使用new Parent()语句所创建的对象

当执行kid.say()时,由于最左下角的区块对象并没有say()方法,因此他将通过原型链查询中间的区块对象,然而,中间的区块对象也没有say()方法,因此他又顺着原型链查询到最右边的区块对象,而该对象正好有say()方法。完了吗?

执行到这里的时候并没有完,在say()方法中引用了this.name,this指向构造函数所创建的对象,在这里,它指向了new Child()这个区块,然而,new Child()中并没有name属性,为此,将查询中间区块,而中间区块正好有name属性,至此,原型链的查询完毕。

更详细的讨论请查看我这篇文章:javascript学习笔记(五)原型和原型链详解

共享原型

本模式的法则在于:可复用的成员应该转移到原型中而不是放置在this中。因此,处于继承的目的,任何值得继承的东西都应该放在原型中实现。所以,可以将子对象的原型与父对象的原型设置为相同即可,如下示例所示:

function inherit(C,P){
    C.prototype = P.prototype;
}

JavaScript代码复用模式详解

子对象和父对象共享同一个原型,并且可以同等的访问say()方法。然而,子对象并没有继承name属性

原型继承

原型继承是一种“现代”无类继承模式。看如下实例:

<script type="text/javascript">
    //要继承的对象
    var parent = {
        name : "Jack"  //这里不能有分号哦
    };
    //新对象
    var child = Object(parent);
    alert(child.name);//Jack
</script>

在原型模式中,并不需要使用对象字面量来创建父对象。如下代码所示,可以使用构造函数来创建父对象,这样做的话,自身的属性和构造函数的原型的属性都将被继承。

<script type="text/javascript">
    //父构造函数
    function Person(){
        this.name = "trigkit4";
    }
    //添加到原型的属性
    Person.prototype.getName = function(){
        return this.name;
    };
    //创建一个新的Person类对象
    var obj = new Person();
    //继承
    var kid = Object(obj);
    alert(kid.getName());//trigkit4
</script>

本模式中,可以选择仅继承现有构造函数的原型对象。对象继承自对象,而不论父对象是如何创建的,如下实例:

<script type="text/javascript">
    //父构造函数
    function Person(){
        this.name = "trigkit4";
    }
    //添加到原型的属性
    Person.prototype.getName = function(){
        return this.name;
    };
    //创建一个新的Person类对象
    var obj = new Person();
    //继承
    var kid = Object(Person.prototype);
    console.log(typeof kid.getName);//function,因为它在原型中
    console.log(typeof kid.name);//undefined,因为只有该原型是继承的
</script>
Javascript 相关文章推荐
javascript来定义类的规范小结
Nov 19 Javascript
jQuery控制输入框只能输入数值的小例子
Mar 20 Javascript
jquery制作 随机弹跳的小球特效
Feb 01 Javascript
举例讲解JavaScript substring()的使用方法
Nov 09 Javascript
基于JavaScript实现购物网站商品放大镜效果
Sep 06 Javascript
BootStrap 实现各种样式的进度条效果
Dec 07 Javascript
解析Vue2 dist 目录下各个文件的区别
Nov 22 Javascript
详解Vue Elememt-UI构建管理后台
Feb 27 Javascript
JavaScript设计模式之单例模式简单实例教程
Jul 02 Javascript
jquery树形插件zTree高级使用详解
Aug 16 jQuery
json_decode 索引为数字时自动排序问题解决方法
Mar 28 Javascript
jquery实现简单拖拽效果
Jul 20 jQuery
JavaScript中的style.cssText使用教程
Nov 06 #Javascript
JavaScript组合拼接字符串的效率对比测试
Nov 06 #Javascript
5个书写JavaScript代码的坏习惯,看看你中枪了没?
Nov 06 #Javascript
javascript解析json实例详解
Nov 05 #Javascript
JavaScript中发布/订阅模式的简单实例
Nov 05 #Javascript
JavaScript不刷新实现浏览器的前进后退功能
Nov 05 #Javascript
Javascript检查图片大小不要让大图片撑破页面
Nov 04 #Javascript
You might like
PHP 采集程序 常用函数
2008/12/18 PHP
PHP获取当前url的具体方法全面解析
2013/11/26 PHP
php读取富文本的时p标签会出现红线是怎么回事
2014/05/13 PHP
PHP中UNIX时间戳和日期间的转换与计算实例
2014/11/19 PHP
PHP实现图片防盗链破解操作示例【解决图片防盗链问题/反向代理】
2020/05/29 PHP
Tips 带三角可关闭的文字提示
2010/10/06 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
jQuery中DOM树操作之使用反向插入方法实例分析
2015/01/23 Javascript
PHP+MySQL+jQuery随意拖动层并即时保存拖动位置实例讲解
2015/10/09 Javascript
WebGL利用FBO完成立方体贴图效果完整实例(附demo源码下载)
2016/01/26 Javascript
jQuery fancybox在ie浏览器下无法显示关闭按钮的解决办法
2016/02/19 Javascript
基于Bootstrap漂亮简洁的CSS3价格表(附源码下载)
2017/02/28 Javascript
vue中使用localstorage来存储页面信息
2017/11/04 Javascript
判断jQuery是否加载完成,没完成继续判断的解决方法
2017/12/06 jQuery
JavaScript实现职责链模式概述
2018/01/25 Javascript
原生JS实现多个小球碰撞反弹效果示例
2018/01/31 Javascript
基于vue-cli 打包时抽离项目相关配置文件详解
2018/03/07 Javascript
react-router4按需加载(踩坑填坑)
2019/01/06 Javascript
angular 服务随记小结
2019/05/06 Javascript
微信小程序云开发之使用云存储
2019/05/17 Javascript
python实现rest请求api示例
2014/04/22 Python
python使用socket连接远程服务器的方法
2015/04/29 Python
详解Python中break语句的用法
2015/05/14 Python
python生成多个只含0,1元素的随机数组或列表的实例
2018/11/12 Python
python matplotlib库直方图绘制详解
2019/08/10 Python
Python基于Socket实现简单聊天室
2020/02/17 Python
Python加载数据的5种不同方式(收藏)
2020/11/13 Python
纯CSS3实现绘制各种图形实现代码详细整理
2012/12/26 HTML / CSS
澳大利亚宠物食品和药物在线:Jumbo Pets
2018/03/24 全球购物
ASOS比利时:英国线上零售商及自有品牌
2018/07/29 全球购物
学习心理学的体会
2014/11/07 职场文书
2014幼儿园家长工作总结
2014/11/10 职场文书
酒店总经理岗位职责
2015/04/01 职场文书
导游词之晋城蟒河
2019/12/12 职场文书
再也不用花钱买漫画!Python爬取某漫画的脚本及源码
2021/06/09 Python
Python用any()函数检查字符串中的字母以及如何使用all()函数
2022/04/14 Python