Mootools.js 是怎样完成类,以及类的相干属性和作用

完成类的步骤

  • 第一步是运用new Class新建类,初始化的牢固函数是initialize,不能运用别的称号
  • 子类也是运用new Class新建,父类在子类中,运用Extends:parentClass来继续,Extends与子类的要领名,统一级别
  • 子类中与父类的同名要领,假如须要在父类的同名要领上拓展,须要在子类的同名要领内,运用this.parent(args)
  • 假如须要在类的表面增添要领,能够运用implement要领
// 运用 Class.create 建立类
    var Person = new Class({
        // 初始函数牢固为 initialize,
        initialize:function(name) {
            this.name = name;
            this.friends = ['jack', 'mark'];
        },
        getName: function(){
            console.log("My name is " + this.name);
        },
        setFriends:function(friend){
            this.friends.push(friend);
        },
        getFriends:function(){
            console.log(this.friends)
        }
    });

    // 运用 implement 给类增加要领,子类能够继续该要领
    Person.implement({
        getAge:function(age){
            console.log("My age is " + age);
        }
    })

    // 子类经由历程 new Class 建立类
    var Chinese = new Class({
        // 子类经由历程 Extends 来继续父类
        Extends:Person,
        initialize:function(name, addr){
            this.parent(name);
            this.addr = addr;
        },
        getAddr:function(){
            console.log("My address is " + this.addr);
        }
    });

    var Japanese = new Class({
        Extends:Person,
        initialize:function(name){
            this.parent(name);
        }
    })

    // 实例化类
    var men = new Chinese('allen', 'BeiJing');
    men.getName(); // My name is allen
    men.getAge(23); // My age is 23
    men.getAddr(); // My address is BeiJing

    // 以下考证 - 子类继续父类的属性,修改了以后,其他子类再次继续父类,父类的属性的值为什么不会转变
    var allen = new Person();
    allen.getFriends(); // ["jack", "mark"]

    var women = new Japanese();
    women.setFriends("lisa");
    women.getFriends(); // ["jack", "mark", "lisa"]

    var men = new Chinese();
    men.setFriends('peter');
    men.getFriends(); //["jack", "mark", "peter"]

    var wallen = new Person();
    wallen.getFriends(); //["jack", "mark"]

JS是怎样完成类的要领,有几个主要的题目须要搞清楚

  • JS是怎样建立类的
  • 子类是怎样完成继续父类属性和要领的
  • 子类继续父类的属性,修改了以后,其他子类再次继续父类,父类的属性的值为什么不会转变
  • 子类和父类的同名函数,运用this.parent(args)在函数中运用,是怎样做到在子类中的同名函数共存的
  • 怎样完成,不在类中,而是运用implement往类中增加要领的

下面来经由历程Mootools.jsclass来具体分析


(function(){

    // 新建一个 Class 的类,new Type 也是一个函数
var Class = this.Class = new Type('Class', function(params){
    // 假如传入的 参数是要领,就把该函数看成初始化的要领
    if (instanceOf(params, Function)) params = {initialize: params};

    var newClass = function(){
        // 消除属性里对其他对象的援用
        reset(this);
        // 假如当前类正在构建,就返回当前类,不做任何操纵
        if (newClass.$prototyping) return this;
        // $caller 和 $family 是什么啊
        this.$caller = null;
        this.$family = null;
        // 有初始化函数的话,就传入参数到该初始化函数,没有就返回本身
        var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
        // 这句又是什么意思,一个 $caller ,一个 caller
        this.$caller = this.caller = null;
        return value;
        // extend(this) 把类的要领,都增加到当前新建的类中
        // implement(params) 把 params 的一切要领都增加到当前类中
    }.extend(this).implement(params);

    //指定 constructor ,以便运用 instanceOf 来考证
    newClass.$constructor = Class;
    newClass.prototype.$constructor = newClass;
    // 指定当前类的父类是哪个
    newClass.prototype.parent = parent;

    return newClass;
});

/*
    在子类具有和父类同名要领时,运用 this.parent(args) 要领来挪用父类的该要领
 */
var parent = function(){
    // :: 假如当前要领没有被挪用,那末就说,parent 要领没有被挪用
    if (!this.$caller) throw new Error('The method "parent" cannot be called.');
    // 当前函数被挪用的名字 function person(age) { this.age = age },则 age 被挪用的就是 person 函数,就是获得 person 这个名字
    var name = this.$caller.$name,
        // $owner 当前类对象, 获得当前类对象的父类对象
        parent = this.$caller.$owner.parent,
        // 获得父类雷同名字的要领
        previous = (parent) ? parent.prototype[name] : null;
    if (!previous) throw new Error('The method "' + name + '" has no parent.');
    // 父类的该同名函数,增加到当前子类中
    return previous.apply(this, arguments);
};

// 消除属性里对其他对象的援用
// 这个消除的例子,能够看 http://hmking.blog.51cto.com/3135992/675856
var reset = function(object){
    for (var key in object){
        var value = object[key];
        switch (typeOf(value)){
            case 'object':
                var F = function(){};
                F.prototype = value;
                object[key] = reset(new F);
                break;
            case 'array': object[key] = value.clone(); break;
        }
    }
    return object;
};

var wrap = function(self, key, method){
    if (method.$origin) method = method.$origin;
    var wrapper = function(){
        // 假如要领是是被庇护的,或许这个要领没有 caller ,就不能被挪用
        if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
        var caller = this.caller, current = this.$caller;
        this.caller = current; this.$caller = wrapper;
        // 将 method 绑定到当前对象中
        var result = method.apply(this, arguments);
        this.$caller = current; this.caller = caller;
        return result;
        // 经由历程extend ,把当前函数的属性附加到 self 里去
    }.extend({$owner: self, $origin: method, $name: key});
    return wrapper;
};

var implement = function(key, value, retain){
    //  Mutators 的 key 只要 Extends 和 Implements
    if (Class.Mutators.hasOwnProperty(key)){
        value = Class.Mutators[key].call(this, value);
        if (value == null) return this;
    }

    if (typeOf(value) == 'function'){
        // 隐蔽的要领子类就不要再继续运用了
        // $hidden 和 $protected 去看函数那章
        if (value.$hidden) return this;
        this.prototype[key] = (retain) ? value : wrap(this, key, value);
    } else {
        // merge 应该是同名的函数,如许就直接增加进去就好
        Object.merge(this.prototype, key, value);
    }

    return this;
};

// 为了将父类的的属性继续到子类,会运用中心变量,将父类传递给中心变量,再经由历程中心变量传递给子类
var getInstance = function(klass){
    // 谁知当前当前类正在构建
    klass.$prototyping = true;

    var proto = new klass;
    // 这里就删除 $prototyping ,也就是构建的历程就是上面这一行咯
    delete klass.$prototyping;
    return proto;
};

// 这里有 overloadSetter ,所以,多是 Class.implement 要领,来给类分外增加函数的
Class.implement('implement', implement.overloadSetter());

Class.Mutators = {

    // 传给 extends 的参数是 parent
    Extends: function(parent){
        // 指向当前类的父类是 parent 参数
        this.parent = parent;
        // 运用 getInstance 获得父类的悉数要领
        this.prototype = getInstance(parent);
    },

    Implements: function(items){
        Array.convert(items).each(function(item){
            var instance = new item;
            for (var key in instance) implement.call(this, key, instance[key], true);
        }, this);
    }
};

})();
/*
 Extends 实际上是分两部分,运用 Extends 的时刻,是把父类的一切属性和要领,经由历程 getInstance 来附加到当前类中
 然后当前类的要领中,能够运用 this.parent(args) 要领,来把父类的同名要领加载进来

 Implements 要领中没有指代 this.parent = parent ,所以假如当前类写了和父类同名的要领,就会掩盖父类的要领
 Implements 只是给当前类增加更多的要领
 */

JS面向对象系列

    原文作者:catchonme
    原文地址: https://segmentfault.com/a/1190000010431809
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞