JavaScript 完成 extend

最近在写挪动端的项目,现在还没有援用任何库,所以许多的要领都要本身写。

用惯了jQuery,当函数参数是对象的时刻,定义默许参数的时刻会写一个defaultOptions对象,然后经由过程jQuery.extend将实参扩大到defaultOptions对象上。JavaScript是没有extend这个原生要领的,本日得闲,就本身完成一个吧。

先想一想这个函数须要做什么。jQuery extend文档中形貌的jQuery.extend原型是
jQuery.extend( target [, object1 ] [, objectN ] )

它的寄义是将object1、object2…兼并到target中,并返回兼并过的target。这内里有两个点须要注重一下。

  • 兼并是从后到前的;
  • target的值是被修正了的;
  • 是深拷贝的(如果参数对象中有属性是对象,也是会递归兼并的);

实在若不想原始数据被变动也很简单,只需第一个参数传空对象就好了。

那,直接上代吗吧:

void function(global){
    var extend,
        _extend,
        _isObject;

    _isObject = function(o){
        return Object.prototype.toString.call(o) === '[object Object]';
    }

    _extend = function self(destination, source){
        for (var property in source) {
            if (source.hasOwnProperty(property)) {

                // 若sourc[property]是对象,则递归
                if (_isObject(source[property])) {

                    // 若destination没有property,赋值空对象
                    if (!destination.hasOwnProperty(property)) {
                        destination[property] = {};
                    };

                    // 对destination[property]不是对象,赋值空对象
                    if (!_isObject(destination[property])) {
                        destination[property] = {};
                    };

                    // 递归
                    self(destination[property], source[property]);
                } else {
                    destination[property] = source[property];
                };
            }
        }
    }

    extend = function(){
        var arr = arguments,
            result = {},
            i;

        if (!arr.length) return {};

        for (i = 0; i < arr.length; i++) {
            if (_isObject(arr[i])) {
                _extend(result, arr[i])
            };
        }

        arr[0] = result;
        return result;
    }

    global.extend = extend;
}(window)

如许好像能够了。然则貌似有一个小问题,我们这里是根据参数递次从左到右顺次实行的,然则实在如果末了一个参数有的属性,前面的参数上的该属性都不须要再扩大了。实在前面的一切参数都是将本身身上有的属性而末了一个参数没有的属性补到末了一个参数上。既云云,是否是从参数列表的右边最先扩大更好一些。

修正今后的代码:

void function(global){
    var extend,
        _extend,
        _isObject;

    _isObject = function(o){
        return Object.prototype.toString.call(o) === '[object Object]';
    }

    _extend = function self(destination, source) {
        var property;
        for (property in destination) {
            if (destination.hasOwnProperty(property)) {

                // 若destination[property]和sourc[property]都是对象,则递归
                if (_isObject(destination[property]) && _isObject(source[property])) {
                    self(destination[property], source[property]);
                };

                // 若sourc[property]已存在,则跳过
                if (source.hasOwnProperty(property)) {
                    continue;
                } else {
                    source[property] = destination[property];
                }
            }
        }
    }

    extend = function(){
        var arr = arguments,
            result = {},
            i;

        if (!arr.length) return {};

        for (i = arr.length - 1; i >= 0; i--) {
            if (_isObject(arr[i])) {
                _extend(arr[i], result);
            };
        }

        arr[0] = result;
        return result;
    }

    global.extend = extend;
}(window)

写代码老是那末有意思!这内里能够看到,只需result身上有的属性,都不须要再赋值了,嘿嘿。

固然,现在程度有限,这段代码一定也还有着优化空间,若看官有任何发起,还请不吝赐教。

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