第一章 面向对象的JavaScript

前言


《JavaScript设计模式与开发实践》是由腾讯的前端团队Alloy Team出品的一本关于js设计模式的书籍。全书主要分为3大部分:基础知识、设计模式和设计原则和编程技巧。基础知识主要是介绍了js语言的面向对象思想、多态、封装、原型、闭包、高阶函数等;设计模式以没中模式一个章节介绍了16种经常在js开发中用的设计模式;设计原则和编程技巧,从新的高度讲解常用到的开发和设计技巧。

本文主要基于全书第一部分: js基础知识的阅读经验,进行总结。

动态语言和鸭子类型

静态语法: 一种需要进行编译的语言,其在编译时决定了数据的类型,同时在编译时能够发现程序中的错误。它能够让程序员按照相应的约束进行开发,但是会在一定程度上降低开发效率。

动态语言:运行时才能决定数据的类型。编码简洁,程序员可以把更多的精力放到逻辑实现上去。

鸭子模型: 走起路来想鸭子,叫起来像鸭子,那么它就是鸭子。 鸭子模型知道我们只关注对象的行为,而不是关注对象本身,也就是关注has-a,而不是is-a。

鸭子模型可以指导我们在动态语言中实现一个原则:面向接口编程而不是面向实现编程。如:一个对象如有push和pop方法,并且这些方法提供了正确的实现,它就可以当做栈来使用。在静态语言中,面向接口编程是一件不容易的事情,需要通过抽象类型奖对象向上转型(java里的interface?)。

多态

多态的主旨思想是: 把“做什么”和“谁去做以及怎么做”分离开,也就是将“不变的事情”和“可能变的事情”分离开。如下面的例子:

    var makeSound = function(animal){
        if(animal instanceof Duck){
            console.log("嘎嘎嘎");
        }else if(animal instanceof Chikcen){
            console.log("咯咯咯");
        }
    };
    var Duck = function(){};
    var Chicken = function(){};
    
    makeSound(new Duck());
    makeSound(new Chicken());
    

上述代码中没有把不变的事情(动物会叫)和可能变得事情(不同动物以及不不同动物的叫声)区分开来,如果加以区分,就会成为下面的样子:

    var makeSound = function(animal){
        animal.sound();
    }
    
    var Duck = function(){};
    Duck.prototype.sound = function(){
        console.log("嘎嘎嘎");
    }
    
    var Chicken = function(){};
    Chicken.prototype.sound = function(){
        console.log("咯咯咯");
    }
    makeSound(new Duck());
    makeSound(new Chicken());

这样以后才增加新的动物时就可以只关注变化的东西,而不要在去处理不要变化的东西了,如增加狗叫:

    var Dog = function(){};
    Dog.prototype.sound = funciton(){
        console.log("汪汪汪");
    }
    makeSound(new Dog());

静态语言(如java)实现多态的基本思想是基类定义此方法,然后子类给以不同的实现,在进行调用时通过对象的多态实现方法的调用。

总结起来: 多态最根本的作用就是通过把过程化的条件分支语句转成对象的多态性,从而消除这些条件分支语句;它时刻在提醒我们做什么和怎么去做是可一个分开的。

在设计模式中,命令模式、组合模式以及策略模式都是多态的典型代表,这些可以在后续的文章中讲述。

封装

封装可以分为:封装数据、封装实现、封装数据和封装变化。

封装数据主要体现在局部作用域,对外隐藏,如下面的代码段:

    js:
    var myObj = function(){
        var name = "ahu";
        return {
            getName: function(){
                return name;
            }
        }
    }
    console.log(myObj.name) // undefined
    console.log(myObj.getName()) // ahu
    
    java:
    public Class myObj{
        private name;
        public myObj(name){
            this.name = name;
        }
        public getName(){
            return name;
        }
    }
    
    myObj nameInfo = new myObj("ahu");
    nameInfo.getName() // ahu

封装实现:对象对它自己的行为负责,其他对象或者用户不关心它的内部实现。这样使得对象之间的耦合松散,对象之间通过暴露的API接口进行通信。例如迭代器方法(js中的each方法),它负责遍历对象,其内部实现改变了,但只要功能不变,对用户来说都是不变的。

封装类型: 封装类型是通过抽象类和接口来实现的,如:java的多态

封装变化: 找到变化并封装之是《设计模式》的出发点,23种的设计模式被划分为:创建型模式、结构性模式和行为型模式。创建型模式的目的是封装创建对象的变化;结构型模式封装的是对象之间的组合关系;行为型模式封装的是对象的行为变化。

原型模式(继承)

原型模式在设计模式上来看,是一种创建对象的模式。原型模式很大程序上是基于clone来实现的,clone是创建对象的一种手段。 如ECMAScript5中提供了Object.create实现对象的clone,不支持此方法的浏览器可以用下面的方法进行兼容:

    Objcet.create = Object.create || function(_obj){
        var F = function(){};
        F.prototype = _obj;
        return new F();
    }

js中的原型继承,其遵循以下基本原则:

  • 所有的数据都是对象(其实js此处实现并不好,基础类型number、string、boolean、undefined需要进行封装才能得到对象)
  • 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并clone它
  • 对象会记住它的原型(proto属性指向了构造函数的constructor)
  • 如果对象无法响应某个请求,它会把这个请求委托给它自己的原型(原形链搜索)

如下程序:

    function person(name){ // person不是类 而是一个构造器 js中的函数,既可以作为普通函数调用,也可以作为构造器调用
        this.name = name;
    }
    Person.prototype.getName = function(){
        return this.name;
    }
    
    var aa = new Person("ahu") // new时 此时函数是一个构造器
    
    // new操作和一下过程是等同的
    var ObjectFactory = function(){
        var obj = new Object(), // 从Object.prototype上clone一个空的对象
        Constructor = [].shift(call).agruments; // 获得构造器,如上面的Person
        obj.__proto__ = ConStructor.prototype; // 指向正确的原型, 这也是在一些框架中经常出现:AA.prototype.constructor = AA 的修正
        var ret = Constructor.apply(obj, arguments); // 确保构造器总是返回一个对象
        
        return  typeof ret === 'object' ?ret :obj;
    }
    
    var bb = ObjectFactory(person, "ahu");
    console.log(Object.getPrototypeOf(a) === Person.prototype);  // true

套用Peter Norving的一句话:设计模式是对语言不足的补充, 如果要是有设计模式, 不如去找一门更好的语言。

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

推荐阅读更多精彩内容