2016年12月21日 星期三

(css)(行內)與(position:absolute)的特性


行內的特性
test
test

行內只能靠 font-size, padding調整高度 line-height 無法作用

行內的size會被父親的大小給影響

一旦賦予(absolute)就會變成(block)


block一旦設定(position:absolute)若沒設定寬度
寬度就會變成(inline-block)的特性

(css)類選擇器對nth-child(1)無用的狀況

<section class="featured video">
    <h1>VIDEO</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO (3)</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO</h1>
</section>
<section class="featured module">
    <h1>NOT A VIDEO (6)</h1>
</section>
section.module:nth-child(1) => 會選到 <section class="featured video">
class無用

2016年12月20日 星期二

(js)deepCopy

module.exports = deepCopy;

/**
 * 可複製3種格式({}, [], Map)
 *
 * g8
 */
function deepCopy(data) {
    // debugger;

    var toString = Object.prototype.toString;
    var clone;
    var type = _getType(data);

    // 若(data)是(不含子孫物件)
    if (data == null || (type != 'array' && type != 'map' && !_isPlainObject(data))) {
        clone = data;
        return clone;
    }
    /* ---------------------------------- */
    // data含有子孫物件
    if (type == 'map') {
        clone = new Map();
    } else if (type == 'array') {
        clone = [];
    } else {
        clone = {};
    }

    copyChild(clone, data);
    //////////////////////////////////////////////////
    /**
     * 會進來的(data)一定是有子孫元素
     */
    function copyChild(target, data) {
        // debugger;
        var clone;
        var dataType = _getType(data);
        var tar_getType = _getType(target);
        /* ---------------------------------- */
        if (tar_getType != dataType) {
            throw new Error('要拷貝的數據型態不同');
        } else if (dataType == 'map') {
            // 若是(Map)
            data.forEach(function(child, key) {
                var childType = _getType(child);

                if (childType != 'array' && childType != 'map' && !_isPlainObject(child)) {
                    // 若子物件是單純數據
                    target.set(key, child);
                } else {
                    // 若(child)物件還攜帶有子孫

                    // (clone)必須與(child)同型態
                    clone = _getInitClone(childType);
                    /* ------------------------ */
                    // 遞回,把child拷貝到 clone
                    copyChild(clone, child);
                    target.set(key, clone);
                }
            });

        } else if (dataType == 'array') {
            // 若是(array)

            data.forEach(function(child, key) {
                var childType = _getType(child);

                if (childType != 'array' && childType != 'map' && !_isPlainObject(child)) {
                    // 若子物件是單純數據

                    target[key] = child;

                } else {
                    // 若子物件還攜帶有子孫

                    // (clone)必須與(child)同型態
                    clone = _getInitClone(childType);
                    /* ------------------------ */
                    // 遞回,把child拷貝到 clone
                    copyChild(clone, child);
                    target[key] = clone;
                }
            });

        } else if (_isPlainObject(data)) {
            // 若(data)是(PlainObject)
            for (var key in data) {
                if (data.hasOwnProperty(key)) {
                    var child = data[key];
                    var childType = _getType(child);

                    if (childType != 'array' && childType != 'map' && !_isPlainObject(child)) {
                        // 若子物件是單純數據

                        target[key] = child;

                    } else {
                        // 若子物件還攜帶有子孫

                        // (clone)必須與(child)同型態
                        clone = _getInitClone(childType);
                        /* ------------------------ */
                        // 遞回,把child拷貝到 clone
                        copyChild(clone, child);
                        target[key] = clone;
                    }
                }
            }
        } else {
            throw new Error('data have no child');
        }
    };
    /* ---------------------------------- */
    return clone;
    ////////////////////////////////////////////////////////////////////////////

    function _getInitClone(type) {
        var clone;
        switch (type) {
            case 'array':
                clone = [];
                break;
            case 'map':
                clone = new Map();
                break;
            default:
                clone = {};
                break;
        }
        return clone;
    };
    /* ====================================================================== */
    function _getType(obj) {
        var type = toString.call(obj) || '';
        type = type.replace(/(^\s?\[object\s?)|(\]\s?$)/gi, '').toLowerCase();
        return type;
    };
    /* ====================================================================== */
    /**
     * 只能是{}
     */
    function _isPlainObject(obj) {
        if (!obj || _getType(obj) !== "object") {
            return false;
        }

        var constructorName = '';
        try {
            constructorName = obj.constructor.toString();
        } catch (error) {}

        // 'Object() {[native code]}'
        if (!/function\s*Object\(\s*\)\s*\{\s*\[native\s*code\]\s*\}\s*$/gi.test(constructorName)) {
            return false;
        }
        return true;
    };
};

2016年12月19日 星期一

(js)generator範例

function getFirstName() {
            setTimeout(function() {
                gen.next('a');
            }, 1000);
        }

        function getSecondName(data) {
            setTimeout(function() {
                data.age = 15;
                gen.next(data + ' b');
            }, 1000);
        }


        function* sayHello() {
            var a = yield getFirstName();
            console.dir(a);

            var b = yield getSecondName(a);
            console.dir(b);
        }

        var gen = sayHello();

        gen.next();

2016年12月16日 星期五

(js)Number()與ParseInt()的差異

<< true >>
parseInt():  NaN
Number():  1
-----------------------
<< null >>
parseInt():  NaN
Number():  0
-----------------------
<< undefined >>
parseInt():  NaN
Number():  NaN
-----------------------
<< 0 >>
parseInt():  0
Number():  0
-----------------------
<< function isNaN() { [native code] } >>
parseInt():  NaN
Number():  NaN
-----------------------
<< {} >>
parseInt():  NaN
Number():  NaN
-----------------------
<< [] >>
parseInt():  NaN
Number():  0
-----------------------
<< "" >>
parseInt():  NaN
Number():  0
-----------------------
<< 123.56 >>
parseInt():  123
Number():  123.56
-----------------------
<< "123.56#" >>
parseInt():  123
Number():  NaN
-----------------------
<< function () {
} >>
parseInt():  NaN
Number():  NaN
-----------------------

(js)series(鍊結方法版)

// 註冊錯誤處理函式
            $Series_.reject('b', error_fun);

            $Series_('b', b_1);
            $Series_('b', b_2); // 會拋出(reject)
            $Series_('b', b_3);



///////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *
 */
function $Series_(jobName, fn) {
    return $Series_._addSeries(jobName, fn);
};
/* ========================================================================== */
/**
 * ($Series_)的參數
 */
(function(self) {
    self.jobList = {};

    // 若沒有指定任務名,就用此預設的
    self.defaultJobName = 'fx';

    // 每個(job)本身要帶的資料
    self.defaultJobData = {
        'last': undefined, // 每個任務列最後一個工作節點
        'carryValue': undefined, // 紀錄每個工作節點的返回值
        'active': false, // 任務列是否在執行中
        'count': 0, // 等待中的數量
        'reject': undefined // 有(reject)過會放這
    };
})($Series_);
/* ========================================================================== */
/**
 * ($Series_)方法集
 */
(function(self) {
    /**
     * 把任務加入隊列
     *
     * 若隊列閒置,就執行
     */
    self._addSeries = function(jobName, fn) {
        debugger;

        if (typeof jobName == 'function') {
            jobName = self.defaultJobName;
            fn = jobName;
        }

        jobName = jobName || self.defaultJobData;
        /* ---------------------------------- */
        /**
         * 調出(job)
         */
        var job;

        if (typeof self.jobList[jobName] == 'undefined') {
            self.jobList[jobName] = Object.create(self.defaultJobData);
        }
        job = self.jobList[jobName];
        /* -------------------------------------------- */
        var Series = self.prototype.series;
        var now = new Series(jobName);
        /* -------------------------------------------- */
        /**
         * 處理節點間的關係
         */

        // 掛勾
        (job.last) && (job.last.next = now)

        job.last = now;
        ++job.count; // 通知(job)多加一個項目
        /* -------------------------------------------- */
        // 設定隊列要執行的事項
        now.setCallBack(fn);
        /* -------------------------------------------- */
        /**
         * 若沒在執行中
         *
         * 強制啟動
         */
        (!job.active) && (now.action());
        /* -------------------------------------------- */
        return now;

    };
    /* ====================================================================== */
    /**
     * 註冊錯誤事件(API)
     */
    self.reject = function(jobName, fn) {
        debugger;

        // 處理進來的參數
        if (arguments.length == 1) {

            if (typeof jobName == 'function') {
                fn = jobName;
                jobName = self.defaultJobName;
            } else if (jobName == null) {
                jobName = self.defaultJobName;
                fn = undefined;
            }
        }

        jobName = jobName || self.defaultJobName;
        /* ---------------------------------- */
        var jobData;

        if (typeof self.jobList[jobName] == 'undefined') {
            self.jobList[jobName] = Object.create(self.defaultJobData);
        }
        jobData = self.jobList[jobName];
        /* ---------------------------------- */
        jobData.reject = (typeof fn == 'function') ? fn : undefined;

    };
})($Series_);


/* ========================================================================== */
(function(_self) {
    // debugger;
    /**
     * 核心(序列)
     */
    function Series(jobName) {
        var self = this;

        // 下一個要執行的(series)
        this.next;
        this.fn = Series;
        /* ---------------------------------- */
        // 要執行的任務
        this.callBack;
        /* ---------------------------------- */
        /**
         * 參考所屬的工作隊列($Async_.jobList)
         *
         * 主要在設定(job.carryValue, active, last)
         */
        this.job;
        this.jobName = jobName || '';

        /* ================================================================== */
        this.__construct = function() {
            // debugger;

            // 取得所屬(job)
            this.job = _self.jobList[this.jobName];
        };
        /* ================================================================== */
        /**
         * call by window
         *
         * 要丟給(this.callBack)的參數
         * 任務結束時,要執行此,通知任務結束,開始下一步
         *
         */
        this._resolve = function(value) {
            // debugger;

            --self.job.count;

            if (arguments.length) {
                self.job.carryValue = value;
            }

            if (self.next) {
                // 若有下一步,執行下一步的(callBack)
                self.next.action();
            } else {
                // 沒有下一步,通知隊列結束

                self.job.last = undefined;
                self.job.active = false;
            }
        };
        /* ================================================================== */
        /**
         * call by window
         *
         * 隊列出錯,呼叫此
         * reset隊列,方便以後呼叫
         *
         */
        this._reject = function(data) {
            // debugger;

            /* ---------------------------------- */
            // 要傳送的資訊
            var carryValue = undefined;

            if (typeof self.job.carryValue == 'object') {
                carryValue = Object.create(self.job.carryValue);
            } else if (typeof self.job.carryValue != 'undefined') {
                carryValue = self.job.carryValue;
            }

            var _data = {
                'count': self.job.count,
                'data': carryValue,
                'error': data
            };
            /* ---------------------------------- */
            self.job.active = false;
            self.job.carryValue = undefined;
            self.job.last = undefined;
            self.job.count = 0;

            var reject_fun = self.job.reject;
            self.job.reject = undefined;
            /* ---------------------------------- */

            (typeof reject_fun == 'function') && reject_fun(_data);
        };
        /* ================================================================== */
        this.__construct();
    };
    ////////////////////////////////////////////////////////////////////////////
    (function() {
        /**
         * 主要任務(callBack)
         *
         * 執行(this.callBack)
         */
        this.action = function() {
            // debugger;
            var self = this;

            // 通知隊列在執行中
            this.job.active = true;

            /* -------------------------------------------- */
            if (typeof this.callBack != 'function') {
                return;
            }

            var info = {
                'active': this.job.active,
                'count': this.job.count,
                'data': this.job.carryValue,
                'reject': this.job.reject
            };

            // 執行任務(resolve, reject, carryValue, otherInfo)
            setTimeout(function() {
                self.callBack(self._resolve, self._reject, self.job.carryValue, info);
            }, 0);

        };
        /* ================================================================== */
    }).call(Series.prototype);
    /* ====================================================================== */
    (function() {
        this.__setGet = function() {};
        /* ================================================================== */
        /**
         * 設定要執行的(this.callBack)
         */
        this.setCallBack = function(fn) {
            if (typeof fn == 'function') {
                this.callBack = fn;
            }
        };
    }).call(Series.prototype);


    /* ====================================================================== */
    _self.prototype.series = Series;
})($Series_);

(js)dispatchEvent()


EventTarget.dispatchEvent()
於此 EventTarget 物件上觸發特定的 Event 物件實體,相當於依照註冊的順序呼叫它的 EventListener。一般事件處理規則(包含 capturing 和可選的 bubbling 階段)適用於用 dispatchEvent() 手動觸發事件。

語法

cancelled = !target.dispatchEvent(event)

參數

  • event 是要被觸發的事件( Event object )。
  • target is used to initialize the Event.target and determine which event listeners to invoke.

回傳值

  • 會在事件完成傳遞(捕捉、命中、冒泡三階段)之後才回傳其值。
  • 若事件在傳遞過程當中,曾於一個或一個以上的事件監聽器裡被執行了該事件的 Event.preventDefault() 方法(且事件須確實已被取消了預設行為),即回傳 false。否則回傳 true 值。
若遇到以下 3 種情況,dispatchEvent 會給錯誤資訊--  UNSPECIFIED_EVENT_TYPE_ERR :
  1. 執行 dispatchEvent 前並未藉由初始化事件指定事件類型
  2. 事件類型為 null 。
  3. 事件類型是個空白字串。
這些異常,處理器會報告「異常未捕獲(uncaught exceptions)」;
事件處理器(event handlers)會在一群呼叫堆(nested callstack)上執行:事件的呼叫方(caller)會先由處理器會阻擋暫停執行,直到事件完成才繼續執行,但是要注意的是,事件若發生異常並不會傳回給呼叫方。

注意

dispatchEvent 是「建立→初始化→觸發」的最後一步驟。這些步驟是用來觸發事件,讓事件完成。事件有多種建立方式,例如用 ​document.createEvent 並用 initEvent 或其他特殊 methods ,像是 initMouseEvent 或 initUIEvent 來初始化。
詳請可參考《Event》。

範例

請參閱《建立或觸發事件》。

(js)自定義事件,並trigger

window.addEventListener("MyEventType", function(evt) {

alert(evt.detail);

}, false);

--------------------------------------------------

var evt = document.createEvent("CustomEvent");

evt.initCustomEvent("MyEventType", true, true, "Any Object Here");

window.dispatchEvent(evt);


////////////////////////////////////////////////////////////////////////////////

var a = document.createElement('a');
--------------------------------------------------
var evt = document.createEvent('MouseEvents');

// 亦可
var evt = document.createEvent('Event');
--------------------------------------------------
evt.initEvent("click", true, true);

a.dispatchEvent(evt);

2016年12月13日 星期二

(js)各種行別的特色

null '=>'
constructor.toString()=
Object.getPrototypeOf()= undefined
type= object
toString.call()= [object Null]
----------------------------------
undefined '=>'
constructor.toString()=
Object.getPrototypeOf()= undefined
type= undefined
toString.call()= [object Undefined]
----------------------------------
5 =>
constructor.toString()=
function String() { [native code] }
Object.getPrototypeOf()= [String: '']
type= string
toString.call()= [object String]
toString()= 5
----------------------------------
5 '=>'
constructor.toString()=
function Number() { [native code] }
Object.getPrototypeOf()= [Number: 0]
type= number
toString.call()= [object Number]
toString()= 5
----------------------------------
{ age: 15 } '=>'
constructor.toString()=
function Object() { [native code] }
Object.getPrototypeOf()= {}
type= object
toString.call()= [object Object]
toString()= [object Object]
----------------------------------
[ 2, 3 ] '=>'
constructor.toString()=
function Array() { [native code] }
Object.getPrototypeOf()= []
type= object
toString.call()= [object Array]
toString()= 2,3
----------------------------------
SelfDefineObj {} '=>'
constructor.toString()=
function SelfDefineObj() {}
Object.getPrototypeOf()= SelfDefineObj {}
type= object
toString.call()= [object Object]
toString()= [object Object]
----------------------------------
true '=>'
constructor.toString()=
function Boolean() { [native code] }
Object.getPrototypeOf()= [Boolean: false]
type= boolean
toString.call()= [object Boolean]
toString()= true
----------------------------------
[Function] '=>'
constructor.toString()=
function Function() { [native code] }
Object.getPrototypeOf()= function () {}
type= function
toString.call()= [object Function]
toString()= function () {

    }
----------------------------------
Map {} '=>'
constructor.toString()=
function Map() { [native code] }
Object.getPrototypeOf()= Map {}
type= object
toString.call()= [object Map]
toString()= [object Map]
----------------------------------
Tue Dec 20 2016 17:15:57 GMT+0800 (????????) '=>'
constructor.toString()=
function Date() { [native code] }
Object.getPrototypeOf()= Invalid Date
type= object
toString.call()= [object Date]
toString()= Tue Dec 20 2016 17:15:57 GMT+0800 (????????)
----------------------------------
/\d/ '=>'
constructor.toString()=
function RegExp() { [native code] }
Object.getPrototypeOf()= /(?:)/
type= object
toString.call()= [object RegExp]
toString()= /\d/
----------------------------------

(js)jQuery基本架構

(function(winsow) {
    // (Array)方法
    var deletedIds = [];

    var document = window.document;

    // Array.prototype.slice
    var slice = deletedIds.slice;

    // Array.prototype.concat
    var concat = deletedIds.concat;

    // Array.prototype.push
    var push = deletedIds.push;

    // Array.prototype.indexOf
    var indexOf = deletedIds.indexOf;

    var class2type = {};

    var toString = class2type.toString;

    var hasOwn = class2type.hasOwnProperty;

    var support = {};

    var version = "1";

    /* ========================================================================== */
    function xQuery(domList) {
        debugger;

        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new xQuery.fn.init(domList);
    };

    // 核心工具,對外API
    xQuery.fn = xQuery.prototype = {
        each: function(callback) {
            return xQuery.each(this, callback);
        }
    };

    xQuery.fn.init = init;

    /**
     * 核心包裹
     *
     * @param {any} domList
     * @returns
     */
    function init(domList) {

        if (typeof domList.length === 'number') {
            for (var i = 0; i < domList.length; i++) {
                this[i] = domList[i];
            }
            this.length = domList.length;
        } else {
            this[0] = domList;
            this.length = 1;
        }
        return this;
    };


    init.prototype = xQuery.fn;
    /* ========================================================================== */
    // (jquery)擴充的方法
    xQuery.extend = xQuery.fn.extend = function() {
        var src, copyIsArray, copy, name, options, clone,
            target = arguments[0] || {},
            i = 1,
            length = arguments.length,
            deep = false;

        // Handle a deep copy situation
        if (typeof target === "boolean") {
            deep = target;

            // skip the boolean and the target
            target = arguments[i] || {};
            i++;
        }

        // Handle case when target is a string or something (possible in deep copy)
        if (typeof target !== "object" && typeof target !== 'function') {
            target = {};
        }

        // extend jQuery itself if only one argument is passed
        if (i === length) {
            target = this;
            i--;
        }

        for (; i < length; i++) {
            // Only deal with non-null/undefined values
            if ((options = arguments[i]) != null) {

                // Extend the base object
                for (name in options) {
                    src = target[name];
                    copy = options[name];

                    // Prevent never-ending loop
                    if (target === copy) {
                        continue;
                    }

                    // Recurse if we're merging plain objects or arrays
                    if (deep && copy && (xQuery.isPlainObject(copy) ||
                            (copyIsArray = Array.isArray(copy)))) {

                        if (copyIsArray) {
                            copyIsArray = false;
                            clone = src && Array.isArray(src) ? src : [];

                        } else {
                            clone = src && xQuery.isPlainObject(src) ? src : {};
                        }

                        // Never move original objects, clone them
                        target[name] = xQuery.extend(deep, clone, copy);

                        // Don't bring in undefined values
                    } else if (copy !== undefined) {
                        target[name] = copy;
                    }
                }
            }
        }

        // Return the modified object
        return target;
    };
    /* ========================================================================== */
    /**
     * 核心方法
     */
    /**
     * 核心方法
     */
    xQuery.extend({

        // Unique for each copy of jQuery on the page
        expando: "xQuery" + (version + Math.random()).replace(/\D/g, ""),

        // Assume jQuery is ready without the ready module
        isReady: true,

        error: function(msg) {
            throw new Error(msg);
        },

        noop: function() {},

        // See test/unit/core.js for details concerning isFunction.
        // Since version 1.3, DOM methods and functions like alert
        // aren't supported. They return false on IE (#2968).
        isFunction: function(obj) {
            return xQuery.type(obj) === "function";
        },

        isArray: Array.isArray || function(obj) {
            return xQuery.type(obj) === "array";
        },

        isArrayLike: isArrayLike,

        isWindow: function(obj) {
            /* jshint eqeqeq: false */
            return obj != null && obj == obj.window;
        },

        isNumeric: function(obj) {

            // parseFloat NaNs numeric-cast false positives (null|true|false|"")
            // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
            // subtraction forces infinities to NaN
            // adding 1 corrects loss of precision from parseFloat (#15100)
            var realStringObj = obj && obj.toString();
            return !Array.isArray(obj) && (realStringObj - parseFloat(realStringObj) + 1) >= 0;
        },

        isEmptyObject: function(obj) {
            var name;
            for (name in obj) {
                return false;
            }
            return true;
        },

        isPlainObject: function(obj) {
            var key;

            // Must be an Object.
            // Because of IE, we also have to check the presence of the constructor property.
            // Make sure that DOM nodes and window objects don't pass through, as well
            if (!obj || xQuery.type(obj) !== "object" || obj.nodeType || xQuery.isWindow(obj)) {
                return false;
            }

            try {

                // Not own constructor property must be Object
                if (obj.constructor &&
                    !hasOwn.call(obj, "constructor") &&
                    !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
                    return false;
                }
            } catch (e) {

                // IE8,9 Will throw exceptions on certain host objects #9897
                return false;
            }

            // Support: IE<9
            // Handle iteration over inherited properties before own properties.
            if (!support.ownFirst) {
                for (key in obj) {
                    return hasOwn.call(obj, key);
                }
            }

            // Own properties are enumerated firstly, so to speed up,
            // if last one is own, then all properties are own.
            for (key in obj) {}

            return key === undefined || hasOwn.call(obj, key);
        },

        type: function(obj) {
            if (obj == null) {
                return obj + "";
            }
            return typeof obj === "object" || typeof obj === "function" ?
                class2type[toString.call(obj)] || "object" :
                typeof obj;
        },

        // Workarounds based on findings by Jim Driscoll
        globalEval: function(data) {
            if (data && xQuery.trim(data)) {

                // We use execScript on Internet Explorer
                // We use an anonymous function so that context is window
                // rather than jQuery in Firefox
                (window.execScript || function(data) {
                    window["eval"].call(window, data); // jscs:ignore requireDotNotation
                })(data);
            }
        },

        // Convert dashed to camelCase; used by the css and data modules
        // Microsoft forgot to hump their vendor prefix (#9572)
        camelCase: function(string) {
            return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
        },

        nodeName: function(elem, name) {
            return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
        },
        // important
        each: function(obj, callback) {
            var length, i = 0;

            if (isArrayLike(obj)) {
                length = obj.length;
                for (; i < length; i++) {
                    if (callback.call(obj[i], i, obj[i]) === false) {
                        break;
                    }
                }
            } else {
                for (i in obj) {
                    if (callback.call(obj[i], i, obj[i]) === false) {
                        break;
                    }
                }
            }

            return obj;
        },

        // Support: Android<4.1, IE<9
        trim: function(text) {
            return text == null ?
                "" :
                (text + "").replace(rtrim, "");
        },

        // results is for internal usage only
        makeArray: function(arr, results) {
            var ret = results || [];

            if (arr != null) {
                if (isArrayLike(Object(arr))) {
                    xQuery.merge(ret,
                        typeof arr === "string" ? [arr] : arr
                    );
                } else {
                    push.call(ret, arr);
                }
            }

            return ret;
        },

        inArray: function(elem, arr, i) {

            var len;

            if (arr) {
                if (indexOf) {
                    return indexOf.call(arr, elem, i);
                }

                len = arr.length;
                i = i ? i < 0 ? Math.max(0, len + i) : i : 0;

                for (; i < len; i++) {

                    // Skip accessing in sparse arrays
                    if (i in arr && arr[i] === elem) {
                        return i;
                    }
                }
            }

            return -1;
        },

        merge: function(first, second) {
            debugger;

            var len = +second.length,
                j = 0,
                i = first.length;

            while (j < len) {
                first[i++] = second[j++];
            }

            // Support: IE<9
            // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
            if (len !== len) {
                while (second[j] !== undefined) {
                    first[i++] = second[j++];
                }
            }

            first.length = i;

            return first;
        },

        grep: function(elems, callback, invert) {
            var callbackInverse,
                matches = [],
                i = 0,
                length = elems.length,
                callbackExpect = !invert;

            // Go through the array, only saving the items
            // that pass the validator function
            for (; i < length; i++) {
                callbackInverse = !callback(elems[i], i);
                if (callbackInverse !== callbackExpect) {
                    matches.push(elems[i]);
                }
            }

            return matches;
        },

        // arg is for internal usage only
        map: function(elems, callback, arg) {
            debugger;

            var length, value,
                i = 0,
                ret = [];

            // Go through the array, translating each of the items to their new values
            if (isArrayLike(elems)) {
                length = elems.length;
                for (; i < length; i++) {
                    value = callback(elems[i], i, arg);

                    if (value != null) {
                        ret.push(value);
                    }
                }

                // Go through every key on the object,
            } else {
                for (i in elems) {
                    value = callback(elems[i], i, arg);

                    if (value != null) {
                        ret.push(value);
                    }
                }
            }

            // Flatten any nested arrays
            return concat.apply([], ret);
        },

        // A global GUID counter for objects
        guid: 1,

        // Bind a function to a context, optionally partially applying any
        // arguments.
        proxy: function(fn, context) {
            var args, proxy, tmp;

            if (typeof context === "string") {
                tmp = fn[context];
                context = fn;
                fn = tmp;
            }

            // Quick check to determine if target is callable, in the spec
            // this throws a TypeError, but we will just return undefined.
            if (typeof fn !== 'function') {
                return undefined;
            }

            // Simulated bind
            args = slice.call(arguments, 2);
            proxy = function() {
                return fn.apply(context || this, args.concat(slice.call(arguments)));
            };

            // Set the guid of unique handler to the same of original handler, so it can be removed
            proxy.guid = fn.guid = fn.guid || xQuery.guid++;

            return proxy;
        },

        now: function() {
            return +(new Date());
        },

        // jQuery.support is not used in Core but other projects attach their
        // properties to it so it needs to exist.
        support: support
    });
    /* ========================================================================== */
    // Populate the class2type map
    xQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),
        function(i, name) {
            class2type["[object " + name + "]"] = name.toLowerCase();
        });

    function isArrayLike(obj) {
        debugger;
        // Support: iOS 8.2 (not reproducible in simulator)
        // `in` check used to prevent JIT error (gh-2145)
        // hasOwn isn't used here due to false negatives
        // regarding Nodelist length in IE
        var length = !!obj && "length" in obj && obj.length,
            type = xQuery.type(obj);

        if (type === "function" || xQuery.isWindow(obj)) {
            return false;
        }

        return type === "array" || length === 0 ||
            typeof length === "number" && length > 0 && (length - 1) in obj;
    }


    window.xQuery = xQuery;
})(window)