JavaScript 實現 extend

最近在寫移動端的項目,目前尚未引用任何庫,因此不少的方法都要本身寫。jquery

用慣了jQuery,當函數參數是對象的時候,定義默認參數的時候會寫一個defaultOptions對象,而後經過jQuery.extend將實參擴展到defaultOptions對象上。JavaScript是沒有extend這個原生方法的,今日得閒,就本身實現一個吧。api

先想一想這個函數須要作什麼。jQuery extend文檔中描述的jQuery.extend原型是
jQuery.extend( target [, object1 ] [, objectN ] )函數

它的含義是將object一、object2...合併到target中,並返回合併過的target。這裏面有兩個點須要注意一下。優化

  • 合併是從後到前的;
  • target的值是被修改了的;
  • 是深拷貝的(如果參數對象中有屬性是對象,也是會遞歸合併的);

其實若不想原始數據被更改也很簡單,只要第一個參數傳空對象就行了。prototype

那,直接上代嗎吧:code

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身上有的屬性,都不須要再賦值了,嘿嘿。ip

固然,目前水平有限,這段代碼確定也還有着優化空間,若看官有任何建議,還請不吝賜教。文檔

相關文章
相關標籤/搜索