Javascript中extend方法的实现

今天来分析下extend方法在各种js框架下的设计。这个函数的功能基本都是实现对象的拷贝功能,即将一个对象的所有属属性拷贝到另外一个对象上去,这个函数使用的频率也很高,如果我们要将一个类的所有方法拷贝到另外方法上去,使用这个方法很方便的。

  • 百度tangram js 框架
baidu.extend =
baidu.object.extend = function (target, source) {
    for (var p in source) {
        if (source.hasOwnProperty(p)) {
            target[p] = source[p];
        }
    }

    return target;
};
仅有2个参数,extend(target,source),第一个参数是目标对象,第二个参数是原对象 ,对原对象中的每个属性进行判断,如果是,那么将他拷贝到目标的对象上去。
  • JQuery
jQuery.extend = jQuery.fn.extend = function() {
    var options, name, src, copy, copyIsArray, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;
    //如果第一个值为bool值,那么就将第二个参数作为目标参数,同时目标参数从2开始计数
    if (typeof target === "boolean") {
        deep = target;
        target = arguments[1] || {};
        // skip the boolean and the target
        i = 2;
    }
    // 当目标参数不是object 或者不是函数的时候,设置成object类型的
    if (typeof target !== "object" && !jQuery.isFunction(target)) {
        target = {};
    }
    //如果extend只有一个函数的时候,那么将跳出后面的操作
    if (length === i) {
        target = this;
        --i;
    }
    for (; i < length; i++) {
        // 仅处理不是 null/undefined values
        if ((options = arguments[i]) != null) {
            // 扩展options对象
            for (name in options) {
                src = target[name];
                copy = options[name];
                // 如果目标对象和要拷贝的对象是恒相等的话,那就执行下一个循环。
                if (target === copy) {
                    continue;
                }
                // 如果我们拷贝的对象是一个对象或者数组的话
                if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
                    if (copyIsArray) {
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];
                    } else {
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }
                    //不删除目标对象,将目标对象和原对象重新拷贝一份出来。 
                    target[name] = jQuery.extend(deep, clone, copy);
                    // 如果options[name]的不为空,那么将拷贝到目标对象上去。
                } else if (copy !== undefined) {
                    target[name] = copy;
                }
            }
        }
    }
    // 返回修改的目标对象
    return target;
};

jquery的实现原理和tangram差不多, 也是讲原对象的属性分别拷贝到目标对象上去, 不过jq可以接受的参数比tangram要多, 他可以接受无限和参数, 如果第一个参数为true的话, 将执行深度拷贝, 将原对象和目标对象中的某些属性值合并起来。
  • protype.js
function extend(destination, source) {
    for (var property in source)
      destination[property] = source[property];
    return destination;
  } 

也是遍历原 对象的各种属性,然后将他拷贝到目标对象上去。实现的方式和tangram类似。
  • dojo
dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
        // summary:
        //      Adds all properties and methods of props to constructor's
        //      prototype, making them available to all instances created with
        //      constructor.
        for(var i=1, l=arguments.length; iarguments[i]);
        }
        return constructor; // Object
    } 



    var extraNames, extraLen, empty = {};
    for(var i in {toString: 1}){ extraNames = []; break; }
    dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf",
        "propertyIsEnumerable", "toLocaleString", "toString", "constructor"];
    extraLen = extraNames.length;
    dojo._mixin = function(/*Object*/ target, /*Object*/ source){
        // summary:
        //      Adds all properties and methods of source to target. This addition
        //      is "prototype extension safe", so that instances of objects
        //      will not pass along prototype defaults.
        var name, s, i;
        for(name in source){
            // the "tobj" condition avoid copying properties in "source"
            // inherited from Object.prototype.  For example, if target has a custom
            // toString() method, don't overwrite it with the toString() method
            // that source inherited from Object.prototype
            s = source[name];
            //fixed by yupeng 判断元素是否是对象的属性
            if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
                target[name] = s;
            }
        }
        // IE doesn't recognize some custom functions in for..in
        if(extraLen && source){
            for(i = 0; i < extraLen; ++i){
                name = extraNames[i];
                s = source[name];
                if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
                    target[name] = s;
                }
            }
        }
                return target; // Object
    } 

    dojo首先会封装一个_mixin方法,该方法起到的作用其实就是extend该起到的作用,然后再背部调用_mixin()方法,封装的extend方法可以接受多个参数,同时将原对象的每个属性都拷贝到目标对象的原型方法上。 

转自:yupeng博客

你可能感兴趣的:(JavaScript,jQuery)