zoukankan      html  css  js  c++  java
  • JavaScript设计模式与开发实践 面向对象

    1 动态类型语言

      静态类型语言编译时就已经确定变量类型,动态类型语言的变量类型要到程序运行时,变量被赋予某个值后,才会有类型。

      静态语言的优点:首先,编译时就能发现类型不匹配错误,其次如果程序明确规定数据类型,编译器还能针对这些信息对程序进行优化,提高程序执行速度。

        静态语言的缺点:迫使程序员按照强契约编写程序,并且增加更多代码。

      

      动态语言的优点:编写的代码更少,程序员能把精力放到业务逻辑。

      动态语言的缺点:无法保证变量的类型,再程序运行时可能发现类型相关错误。

      动态类型无需进行类型检测,我们可以尝试钓鱼任何对象的任意方法,不用考虑它原本是否被设计为拥有该方法。

    2 多态

      多态的实际含义:同意操作作用于不同的对象上,可以产生不同的解释和不同的结果。也就是,给不同的对象发送同一个消息,这些对象会根据这个消息分别给出不同反馈。

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

      这段代码体现了多态性,但再增加一个动物后需要改动makeSound函数。

      多态的思想是将不变的事物和可变的事物分开。把不变的部分隔离,把可变的封装,,这给予我们扩展程序的能力。

        //把不变的部分隔离,即动物都会发出叫声
        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 = function(){
            console.log( '汪汪汪' );
        };
    
        makeSound( new Dog() ); // 汪汪汪

      多态最根本的作用是通过把过程化的条件分局转化为对象的多态性,从而消除条件分句。将行为分布在各个对象中,并让对象各自负责自己的行为,正是面向对象设计的优点。

        var googleMap = {
            show: function(){
                console.log( '开始渲染谷歌地图' );
            }
        };
    
        var baiduMap = {
            show: function(){
                console.log( '开始渲染百度地图' );
            }
        };
    
       //  使用条件分句
        var renderMap = function( type ){
            if ( type === 'google' ){
                googleMap.show();
            }else if ( type === 'baidu' ){
                baiduMap.show();
            }
        };
    
        renderMap( 'google' ); // 输出:开始渲染谷歌地图
        renderMap( 'baidu' ); // 输出:开始渲染百度地图
        //使用多态
        var renderMap = function( map ){
            if ( map.show instanceof Function ){
                map.show();
            }
        };
    
        renderMap( googleMap ); // 输出:开始渲染谷歌地图
        renderMap( baiduMap ); // 输出:开始渲染百度地图

      

    3 封装

      封装的目的是将信息隐藏。封装包括封装数据、封装实现、封装类型和封装变化。封装不仅仅是隐藏数据,还包括隐藏实现细节、设计细节以及隐藏对象的类型等。

      封装数据:JavaScript没有public、private、protected等,只能用变量作用域实现封装特性,只能模拟public和private。

      封装实现:封装使得对象之间的耦合松散,对象之间只通过暴露的API接口通信。修改一个对象时,只要对外的接口没有变化,就不会影响程序的其他功能。

      封装类型:JavaScript没有对抽象类和接口的支持.

      封装变化:《设计模式》总结了23种设计模式,分别被划分为创建新模式、结构型模式和行为型模式。创建型模式,要创建一个对象是一种抽象行为,具体创建什么对象是可以变化的,

            创建型模式的目的是封装对象的变化。结构型模式封装的是对象直接的组合关系。行为型模式封装的是对象的行为变化。

    4 原型模式和基于原型继承的JavaScript对象系统

    原型编程范型的部分基本规则:

    • 所有的数据都是对象
    • 要得到一个对象,不少通过实例化类,而是找到一个对象作为原型并克隆它
    • 对象会记住它的原型
    • 如果对象无法响应某个请求,会把这个请求委托给它的原型

    1 所有的数据都是对象

    JavaScript的基本类型包括undefined、number、string、boolean、object、function。除了undefined,number、boolean、string都可以通过包装类编程对象类型,JavaScript的根对象是Object.prorotype。

    2 要得到一个对象,不少通过实例化类,而是找到一个对象作为原型并克    function Person( name ){

    this.name = name;
        };
    
        Person.prototype.getName = function(){
            return this.name;
        };
    
        var a = new Person( 'sven' )
        console.log( a.name ); // 输出:sven
        console.log( a.getName() ); // 输出:sven
    //ES5中的Object.getPrototypeOf可以看对象 console.log( Object.getPrototypeOf( a ) === Person.prototype ); // 输出:true

    当使用new调用函数,函数就是一个构造器,先克隆Object.prototype对象,再进行其他操作。

    在Chrome和Firefox等暴露了对象__proto__属性的浏览器理解new运算的过程

        var objectFactory = function(){
            var obj = new Object(), // 从Object.prototype 上克隆一个空的对象
            Constructor = [].shift.call( arguments ); // 取得外部传入的构造器,此例是Person
            obj.__proto__ = Constructor.prototype; // 指向正确的原型
            var ret = Constructor.apply( obj, arguments ); // 借用外部传入的构造器给obj 设置属性
            return typeof ret === 'object' ? ret : obj; // 确保构造器总是会返回一个对象
        }; 

    3 对象会记住它的原型

    某个对象的_proto_属性默认会指向它的构造器的原型对象,即Constructor.prototype。正是因为对象要通过__prototype__属性记住它的构造器的原型,模拟new创建对象时需要手动给obj对象设置正确的__proto__指向。

  • 相关阅读:
    Android Layout XML属性
    linux]ubuntu挂载U盘
    Android之NDK开发
    Android 创建永不Kill的Service
    如何编写可移植的c/c++代码
    Android写日志文件类
    Android Activity去除标题栏和状态栏
    linux .bash_profile和.bashrc的什么区别
    ListView.setOnItemClickListener、setOnCreateContextMenuListener无效 为什么
    WCF 第四章 绑定 使用队列技术进行通信
  • 原文地址:https://www.cnblogs.com/surahe/p/5988897.html
Copyright © 2011-2022 走看看