原型模式和基于原型继承的javascript系统

导言:

在以类为中心的面向对象编程语言中,类和对象的关系可以想象成铸模和铸件的关系,对象总是总类中创建而来。而在原型编程思想中,类并不是必须的,对象也不必要从类中创建而来,一个对象是克隆另外一个对象创建而来的,原型模式不仅仅是一种设计模式,也是一种编程范式

1.使用克隆的原型模式

如果要使用原型模式,那么我们只需要负责调用克隆的方法,便能完成克隆对象的功能。原型模式的实现关键是语言本身是否提供了克隆方法,ECMAscript5提供了一个方法可以用来克隆对象这个方法是Object.creat().代码如下:

var Plane = function () {

      this.blood = 100;

      this.attracklevel=1;

      this.defenselevel=0.5

}

var plane = new Plane()

plane.blood = 500;

plane.attracklevel=10

var clonePlane = Object.create(plane)  // 克隆对象

clonePlane.blood //  500

以上代码是通过使用Object.cteate()来克隆一个对象的副本,但是有些浏览器并不支持Object.create()方法,那么这是我们为了做兼容可以进行这样的处理,代码如下:

Object.create = Object.create || function (obj) { // obj是要被克隆的对象

    // 通过构造函数的方式来克隆

    var F = function () {}

    F.prototype = obj;

    return new F()

}

在浏览器控制台运行这段代码:

var a = {name: 'steve'}

var b = Object.create(a) // 得到对象a的一个副本,但是对象a和对象b的地址引用肯定是不相等的

console.log(b)  // 得到的是steve

2.克隆是创建对象的手段

    上面的代码中我们知道了如何通过原型模式来克隆出一个对象,但是原型模式的真正目的并不是创建出一个一模一样的对象,而是提供了便捷的方式去创建某个类型的对象,克隆只是创建对象的过程和手段。

    我们在进行编程的时候有一个非常重要的原则,那就是依赖导致原则,那么什么是依赖倒置原则了?所谓的依赖倒置就是说创建对象的时候避免依赖具体的类型,就像java等静态类型的语言进行编程的时候,类型之间的解耦是非常重要的,通过new XXX的方式创建对象显得很僵硬,因此就有了工厂方法和抽象工厂模式方法来帮助我们解决这个问题,但是这两种方法带来的结果是最终会出现很多平行的工厂类,这就会导致额外的代码,如有一个创建狗的工厂:

function dogFactory (name,age) {

    var obj = new Object();

    obj.name = name;

    obj.age = age

    return obj

}

有一个创建猫的工厂:

function catFactory (name,age) {

var obj = new Object();

obj.name = name;

obj.age = age

return obj

}

很明显创建狗的工厂和创建猫的工厂的内部的代码是一模一样的,只是工厂名字变了,由此可见这两个平行的工厂额外的增加了代码量,这显然是不期望的。在js中,原型模式为我们提供了另外一种创建对象的方式,就是通过克隆对象,而不是像上面一样从一个工厂类中创建对象。通过克隆对象我们就不在关心对象的具体类型是什么了,因此通过原型模式创建对象就会显得非常容易,也不存在类型耦合的问题。其实javascript的对象系统就是通过原型模式来搭建的,所有的对象都是从某个对象上克隆而来的。既然整个对象系统是基于原型搭建的,那么这种原型模式也一定遵循一些编程规范,接下来了解一下原型编程规范的基本规则

3原型编程规范基本规则

1.所有的数据都是对象,例如前面的var F = function(){},这个函数不仅仅是一个函数,他也是一个对象,其实函数在js中就是一等公民,也就是说函数就是对象,具体一点的解释如下:

javascript在设计的时候,模仿java引入了两套类型机制,基本类型和引用类型,基本类型包括

undefined,number,bool,string,function,object,但是这并不是一个好的想法,按照javascript设计者本意的想法是出来undefined,其余的都是对象,为了实现这一目标,number,bool,string这几种基本类型数据可以通过包装类型的方式变成对象类型数据来处理。什么意思了?有点不明白,function ,object是对象是可以接受的,但是number,bool,string 不就是一个数字,一个布尔值,一个字符串吗,怎么能成为对象了,这显然很矛盾,但时当我们知道了包装类型的时候问题就会立马得到解决,所谓的包装类型就是javascript提供了Numer,Bool,String这样的构造函数,通过将上面几个基本类型的首字母换成大写字母就得到了对应的包装类型,如通过var s = String('abc')可以将字符创abc转换为对象类型来处理,

事实上,我们并不能说在javascript中所有的数据都是对象,但可以说绝大部分是对象,那么我们相信在js中一定会有一个根对象存在,其实这个根对象就是Object.prototype(是Object构造器的原型),这个对象是一个空的对象,其实我们遇到的每一个对象最终都是从Object.prototype克隆而来的。如:

创建两个对象obj1和obj2,

var obj1 = {} ;var obj2 = new Object();利用es5提供的getPrototypeOf()来查看这两个对象的原型

console.log(Object.getPrototypeOf(obj1) === Object.prototype) // true

console.log(Object.getPrototypeOf(obj2) === Object.prototype)  // true

2.要得到一个对象不是通过实例化类,而是找到一个对象作为原型并且克隆他。

如:找到一个对象a = {name: 'steve'},将啊作为F的原型来克隆a

var creatObj = function () {

    var F = function () {}

    F.prototype = a

    return new F() // 得到一个a的副本,到这一步我们应该很困惑,为什么没有类的概念,而在这里却用了new,其实这里的F比不是类,而是一个构造函数,这里使用new运算符来创建兑现的过程实际上也只是先克隆Object.prototype对象,然后在进行一些其他额外的操作

}

可已通过下面的代码来理解new运算的过程

// 创建一个构造函数Person

function Person (name) {

        this.name = name

}

// 在构造函数的原型对象上挂在一个方法

Person.prototype.getName = function () {

  return this.name

}

// 创建一个克隆兑现的工厂

var objFactory = function () {

    // 创建一个对象,将其加工处理后最终返回出去

    var obj  =  new Object()

    Consructor = [].shift.call(arguments) // 拿到第一个参数,这里是一个构造函数,shift会改变原数组

    obj._proto_ = Constructor.prototype  // 让obj指向正确的原型

    var ret = Constructor.apply(obj,arguments) // 借用外部传入的构造器给obj设置属性,也就是我前面说的对obj进行加工处理

    return  typeof ret === 'object' ? ret : obj // 既然是对象工厂,那么最终一定要返回出去一个对象

}

var a = objFactory(Person,'steve')

console.log(a.name) // steve

console.log(a.getName()) // steve

console.log(Object.getPrototypeOf(a) === Person.prototype)// true, 很明显得到兑现的原型就是对应构造函数的原型

3.对象会记住他的原型: 所有的对象都有一个_proto_属性,对象就是通过这个属性来记住他的原型的

4.如果对象无法响应某个请求,那么就会把请求委托给他的原型

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容