• oo的一些概念


    http://docs.kissyui.com/5.0/guides/base/oo.html

    JavaScript 语言自成体系,自有一套代码重用的模式,这些常见的代码重用模式可以在《Javascript 设计模式》、《JavaScript 编程模式》中找到理论基础。KISSY 即是实践了这些典型的代码重用模式,并作为 KISSY 代码库的面向对象的核心,向高层代码提供语言的完备性支撑。

    这些理论基础大都来自"javascript 编程模式"一书:

    KISSY 中面向对象的范畴包含两个方面,本篇讲解第一方面

    • 语言层面:JS 语言特有的编程模式
      • 面向对象相关的模式
      • JS 语言增强的工具函数
    • 最佳实践:KISSY 对于面向UI、模块生命周期的封装,包括组件模式、插件模式等

    概要

    JavaScript 语言没有原生类的概念,对象之间共享方法的关键渠道是通过原型。而具备某一类原型方法的'模板对象',通常被称作基类,子类除了调用基类的构造器(手动调用)外,最重要的就是要拥有基类的行为能力(继承基类原型上的方法)。这个过程中涉及到五种典型的行为:

    • 混合 mix
    • 克隆 clone
    • 扩充 augment
    • 继承 extend
    • 合并 merge

    以 kissy 的 API 为例,merge 和 augment 都是基于 mix 方法,本质上利用了 JS 的动态特性,在运行时为对象增减成员;

    extend 方法的实现比较典型,总体思路是子构造器的原型对象指向父构造器的一个实例,具体有一些细节问题要处理。类继承体系中继承的是对象的模板(即类),JS 没有对于对象的更高一层的抽象数据结构,即使有 constructor 这种东西,它本身也只是 function 对象而已。

    mix

    mix (receiver , supplier [ , overwrite = true , whitelist , deep ]) => Object

    将 supplier 对象的成员复制到 receiver 对象上。参数:

    • receiver (object) – 属性接受者对象.
    • supplier (object) – 属性来源对象.
    • overwrite (boolean) – 是否覆盖接受者同名属性.
    • whitelist (Array) – 属性来源对象的属性白名单, 仅在名单中的属性进行复制.
    • deep (boolean) – 是否进行深度 mix (deep copy)

    mix 默认不是递归进行的. 如果其中一个属性为对象或者数组,那么他将会被接下来对象的同名属性对应的值所代替,即值不会被合并。 如果设置了参数 deep = true ,那么会对数组和简单对象KISSY.isPlainObject()递归合并.

    supplier undefined 的属性值不会被复制,不过对象从原型继承下来下的值则会被复制.

    该方法仅适用于 javascript 对象,不要在浏览器对象上调用,例如 node.style

    简单 mix

    require(['util'], function(Util){
        var r = { a: 'a', b: 'b' };
        Util.mix(r, { c: 'c' });
        console.log(r.c); // => 'c'
    
        Util.mix(r, { a: 'a2' }, false);
        console.log(r.a); // => 'a'
    
        Util.mix(r, { e: 'e', f: 'f' }, true, ['f']);
        console.log(r.e); // => undefined
        console.log(r.f); // => 'f'
    })
    

    深度mix

    var object1 = {
      apple: 0,
      banana: {weight: 52, price: 100},
      cherry: 97
    };
    var object2 = {
      banana: {price: 200},
      durian: 100
    };
    
    /* merge object2 into object1, recursively */
    Util.mix(object1,object2,undefined,undefined,true);
    
    console.log(object1); // => { apple: 0, banana: { weight: 52, price: 200 }, cherry: 97, durian: 100 }
    

    mix是最自然也是最简单的为 JS 对象添加特性的方式,具体实现就是将一个对象的(所有或指定)属性指向给另一个对象,在静态语言中是无能为力的。

    虽然 Yahoo 将这种方式学院式地命名为“augmentObject”并且声称使用它的合适场合是在“扩充一个‘静态类’”时。所谓“静态类”这种说法,只能说是中静态类语言的遗毒太深,什么概念都要一一映射至其上。事实上,“静态类”对应 JS 中的概念是“非构造器对象”,比如字面量对象。而之所以 Yahoo 强调“静态类”,那是因为“静态类”和构造器之间间有一个显区别,前者没有 prototype 属性。

    补充一点,“静态类”也可以是构造器,只不过它的 prototype 没有多大意义(比如指向 {})。

    事实上,这个方法是 augment 和 merge 的基础。可以看到,JS 中直接对对象进行各种操作其实非常方便,类什么的都是浮云。

    merge

    merge (s1,s2[,...]) => Object

    将多个对象的成员合并到一个新对象上. 参数中, 后面的对象成员会覆盖前面的。如果用mix混合对象时,receiver 会被改变,如果想要保留原始的 receiver ,可以使用 KISSY.merge()

    var object=Util.merge(object1,object2);
    

    简单例子:

    var a = { a: 'a' },
    b = { b: 'b' },
    c = { b: 'b2', c: 'c' };
    
    var o = Util.merge(a, b, c);
    console.log(o.a); // => 'a'
    console.log(o.b); // => 'b2'
    console.log(o.c); // => 'c'
    

    简单情况下 merge 方法常用来合并配置信息. 推荐使用 Base 处理属性配置.

    extend

    extend (r,s[,px,sx]) => Function

    让函数对象 r 继承函数对象 s,参数

    • r (function) – receiver,将要继承的子类函数
    • s (function|object) – supplier,继承自的父类函数
    • px (object) – prototype members, 需要添加/覆盖的原型成员
    • sx (object) – static members, 需要添加/覆盖的静态成员.

      function Bird(name) { this.name = name; } Bird.prototype.fly = function() { alert(this.name + ' is flying now!'); };

      function Chicken(name) {

        Chicken.superclass.constructor.call(this, name);
      

      } Util.extend(Chicken, Bird,{

        fly:function(){
            Chicken.superclass.fly.call(this)
            alert("it's my turn");
        }
      

      });

      new Chicken('kissy').fly();

    extend 方法是 KISSY 里类继承的实现方式. 书写 JavaScript 代码时, 请忘记传统 OO 里的继承体系。子类方法中可通过 superclass 来访问父类函数的原型, 进而调用父类方法.

    Util.extend 像 Node.js 里的 util.inherits,就是用于声明两个类的继承关系,与 util.inherits 相比,它更为贴心,还会维护 superclass 和 superclass.constructor。

    注意构造函数体内,通过 Chicken 类上的 superclass 属性,子类不再需要显式写明父类的名称, 只需要直接调SubClass.superclass.constructor.call(this, attrs) 即可。

    而在方法内,也可以通过 SubClass.superclass 拿到父类上的方法,类似其他编程语言中的 super 之类。

    augment

    augment(r, s1 [, s2 , ...], ov = true, wl) => Function

    将 s1,s2.... 的 prototype 属性的成员复制到 r.prototype 上。这时被复制的成员来自于一个Fucntion对象,这个对象一般被称为掺元类(mixin class)。比如 KISSY 里的 CustemEvent 就是一个掺元类。掺元类只是被扩充用的。参数说明:

    • r (function) – 将要扩充的函数
    • ...s1 (function|object) – 扩充来源函数或对象. 非函数对象时复制的就是 s 的成员.
    • ov (boolean) – 是否覆盖 r.prototype 同名属性.
    • whitelist (Array) – 属性来源对象的属性白名单, 仅在名单中的属性进行复制.
    var Shoutable = {
        shout: function() { alert('I am ' + this.name + '.'); }
    };
    
    function Dog(name) { this.name = 'Dog ' + name; }
    function Pig(name) { this.name = 'Pig ' + name; }
    
    Util.augment(Dog, Utilhoutable);
    Util.augment(Pig, Shoutable);
    
    new Dog('Jack').shout(); // => I am Dog Jack.
    new Pig('Mary').shout(); // => I am Pig Mary.
    

    augment 方法在 KISSY 里非常基础非常重要. 传统 OO 语言里, 可以通过继承或接口来实现共性方法. 在 JavaScript 里, 通过 mixin 特性, 一切变得更简单. augment 是动态语言 mixin 特性的体现, 灵活运用, 能让代码非常优雅简洁.

    clone

    对象的值的拷贝,绕过引用的拷贝。


    有了 Util.augment,我们可以很方便得扩展类的原型;有了 Util.extend,我们可以很方便地继承;那么 KISSY 对属性 getter、setter 有什么好的解决方案么?答案自然是 Base。

    顾名思义,Base 是个基础类;而这个类,也是通过 Util.augment 等搞定的。在Base小节讲解。

  • 相关阅读:
    protobuf配置与使用
    gvim配置
    html div+css做页面布局
    php info
    开源相关工具汇总
    mem 0908
    linux dd指令
    java面试(2)--大数据相关
    Java基础面试题(1)
    转自ruby迷: 使用Net::SSH和Net::SCP编写Linux服务器管理脚本
  • 原文地址:https://www.cnblogs.com/danghuijian/p/4593715.html
Copyright © 2020-2023  润新知