成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JavaScript_框架

Jeffrrey / 1536人閱讀

摘要:框架與庫(kù)庫(kù)解決某個(gè)問(wèn)題而拼湊出來(lái)的一大堆函數(shù)與類的集合。框架一個(gè)半成品的應(yīng)用,直接給出一個(gè)骨架。鎖定,意味著無(wú)法擴(kuò)展。雙鏈?zhǔn)侵杆鼉?nèi)部把回調(diào)分成兩種,一種叫成功回調(diào),用于正常的執(zhí)行,一種叫錯(cuò)誤回調(diào),用于出錯(cuò)時(shí)執(zhí)行。

框架與庫(kù):

庫(kù):解決某個(gè)問(wèn)題而拼湊出來(lái)的一大堆函數(shù)與類的集合。每個(gè)函數(shù)(方法)之間都沒(méi)什么關(guān)聯(lián)。
框架:一個(gè)半成品的應(yīng)用,直接給出一個(gè)骨架。

種子模塊

對(duì)象擴(kuò)展,數(shù)組化,類型判定,簡(jiǎn)單的事件綁定與卸載,無(wú)沖突處理模塊加載domReady

命名空間

jQuery對(duì)命名空間的控制:
把命名空間保存到一個(gè)臨時(shí)變量中,后面通過(guò)noConflict放回去.

var _jQuery = window.jQuery, _$ = window.$ // 先把可能存在的同名變量保存起來(lái)

jQuery.extend({
    noConflict (deep) {
        window.$ = _$ // 這時(shí)再放回去
        if (deep) {
            window.jQuery = _jQuery
            return jQuery
        }
    }
})

對(duì)象擴(kuò)展

淺拷貝和深拷貝

在JavaScript中一般約定俗成為:extendmixin

// mass Framework的mix方法
function mix(target, source) {
    var args = [].slice.call(arguments), i = 1, key, ride = typeof args[args.length - 1] === "boolean" ? args.pop() : true
    if (args.length === 1) { // 處理$.mix(hash)的情形
        target = !this.window ? this : {}
        i = 0
    }

    while ((srouce = args[i++])) {
        for (key in source) { // 允許對(duì)象糅雜,用戶保證都是對(duì)象
            if (ride || !(key in target)) {
                target[key] = srouce[key]
            }
        }
    }
    return target
}

數(shù)組化

瀏覽器下存在許多類數(shù)組對(duì)象:

function內(nèi)的arguments

document.forms

form.elements

document.links

select.options

document.getElementsByName

document.getElementsByTagName

childNodes

children (獲取節(jié)點(diǎn)集合HTMLCollection, NodeList)

轉(zhuǎn)換方法:

Array.form()

[].slice.call()
Array.prototype.slice.call()
// jQuery的makeArray
var makeArray = function makeArray(array) {
    var ret = []
    if (array !== null) {
        var i = array.length
        if (i === null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval) {
            ret[0] = array
        } else {
            while (i) {
                ret[--i] = array[i]
            }
        }
        return ret
    }
}

類型判定

JavaScript存在兩套類型系統(tǒng)

基本類型

對(duì)象類型系統(tǒng)

基本類型:undefined,null,string,boolean,number,Set,Map
對(duì)象類型:function,object

基本數(shù)據(jù)類型通過(guò)typeof來(lái)檢測(cè)
對(duì)象類型通過(guò)instanceof來(lái)檢測(cè)

一般通用的檢測(cè)方法:

Object.prototpe.toString.call(arg)

isPlainObject判斷是否為純凈的JavaScript對(duì)象

function isPlainObject (obj) {
    return obj && typeof obj === "object" && Object.getProtypeOf(obj) === Object.prootype
}

domReady

作用:滿足用戶提前綁定事件

方法:

window.onload

mass的DomReady處理方式:

var readyList = []
mass.ready = function (fn) {
    if (readyList) {
        readyList.push(fn)
    } else {
        fn()
    }
}
var readyFn, ready = W3C ? "DOMContentLoaded" : "readystatechange"
function fireReady () {
    for (var i = 0, fn; fn = readyList[i++]; ) {
        fn()
    }
    readyList = null
    fireReady = $.noop // 惰性函數(shù),防止IE9二次調(diào)用 _changeDeps
}

function deScrollCheck () {
    try { // IE下通過(guò)doScollCheck檢測(cè)DOM樹(shù)是否建完
        html.doScroll("left")
        fireReady()
    } catch (e) {
        setTimeout(doScrollCheck)
    }
}

// 在FF3.6之前,不存在readyState屬性
if (!DOC.readyState) {
    var readyState = DOC.readyState = DOC.boyd ? "complete" : "loading"
}
if (DOC.readyState === "complete") {
    fireReady() // 如果在domReady之外加載
} else {
    $.bind(DOC, ready, readyFn = function () {
        if (W3C || DOC.readyState === "complete") {
            fireReady()
            if (readyState) { // IE下不能改寫(xiě)DOC.readyState
                DOC.readyState = "complete"
            }
        }
    })
    if (html.doScroll) {
        try {
            if (self.eval ===parent.eval) {
                deScrollCheck()
            }
        } catch (e) {
            deScrollCheck()
        }
    }
}

無(wú)沖突處理

jQuery的無(wú)沖突處理:

var 
window = this, 
undefined, 
_jQuery = window.jQuery, 
_$ = window.$,
// 把window存入閉包中的同名變量,方便內(nèi)部函數(shù)在調(diào)用window時(shí)不要難過(guò)費(fèi)大力氣查找它
// _jQuery 與 _$用于以后重寫(xiě)
jQuery = window.jQuery = window.$ = function (selector, context) {
    // 用于返回一個(gè)jQuery對(duì)象
    return new jQuery.fn.init(selector, context)
}

jQuery.exnted({
    noConflict (deep) {
        // 引入jQuery類庫(kù)后,閉包外面的window.$與window.jQuery都存儲(chǔ)著一個(gè)函數(shù),它是用來(lái)生成jQuery對(duì)象或domReady后執(zhí)行里面的函數(shù)的
        // 在還沒(méi)有把function賦給它們時(shí),_jQuery與_$已經(jīng)被賦值了,因此它們倆的值必然是undefined,因此放棄控制權(quán),就是用undefined把window.$里面的jQuery系的函數(shù)清除掉。
        window.$ = _$ // 相當(dāng)于window.$ = undefined
        // 需要為noConflict添加一個(gè)布爾值,為true
        if (deep) {
            // 必須用一個(gè)東西接納jQuery對(duì)象與jQuery的入口函數(shù),閉包里面的東西除非被window等宿主對(duì)象引用,否則就是不可見(jiàn)的,因此把比較里面的jQuery return出去,外面用一個(gè)變量接納就可以
            window.jQuery = _jQuery // 相當(dāng)于window.jQuery = undefined
        }
        return jQuery
    }
})
模塊加載系統(tǒng)

AMD規(guī)范

AMD是Asynchronous Module Definition異步模塊定義

異步:有效避免了采用同步加載方式中,導(dǎo)致的頁(yè)面假死現(xiàn)象

模塊定義:每個(gè)模塊必須按照一定的個(gè)是編寫(xiě)

加載器所在路徑

要加載一個(gè)模塊,需要一個(gè)URL作為加載地址,一個(gè)script作為加載媒介。但用戶在require時(shí)都用ID,需要一個(gè)將ID轉(zhuǎn)換為URL的方法。約定URL的合成規(guī)則:

basePath + 模塊ID  + ".js"

在DOM樹(shù)中最后加入script

function getBasePath () {
    var nodes = document.getElementsByTagName("script")
    var node = nodes[nodes.length - 1]
    var src = document.querySelector ? node.src : node.getAttribute("src", 4)
    return src
}

獲取當(dāng)前Script標(biāo)簽

function getCurrentScript (base) { // 為true時(shí)相當(dāng)于getBasePath
    var stack
    try { // FF 可以直接 var e = new Error("test"),但其它瀏覽器只會(huì)生成一個(gè)空Error
        a.b.c() // 強(qiáng)制報(bào)錯(cuò),以便獲取e.stack
    } catch (e) { // Safari的錯(cuò)誤對(duì)象只有l(wèi)ine,sourceId,sourceURL
        stack = e.stack
        if (!stack && window.opera) {
            // opera 9 沒(méi)有e.stack,但有e.Backtrace,不能直接獲取,需要對(duì)e對(duì)象轉(zhuǎn)字符串進(jìn)行抽取
            stack = (`${e}`.match(/of inlked script S+/g) || []).join(" ")
        }
    }
    if (stack) {
        stack = stack.split(/[@]/g).pop() // 取得最后一行,最后一個(gè)空間或@之后的部分
        stack = stack[0] === "(" ? stck.slice(1, -1) : stack.replace(/s/, "") // 去掉換行符
        return stack.replace(/(:d+)?:d+$/i, "") // 去掉行號(hào)與或許存在的出錯(cuò)字符串起始位置
        // 在動(dòng)態(tài)加載模塊時(shí),節(jié)點(diǎn)偶插入head中,因此只在head標(biāo)簽中尋找
        var nodes = (base ? document : head).getElementByTagName("scirpt")
        for (var i = nodes.length, node; node = nodes[--i]) {
            if ((base || node.className) && node.readyState === "interactive") { // 如果此模塊
                return node.className = node.src
            } 
        }
    }
}

require 方法

作用:當(dāng)依賴列表都加載王弼執(zhí)行用戶回調(diào)。

取得依賴列表的第一個(gè)ID,轉(zhuǎn)換為URL。無(wú)論是通過(guò)basePath + ID +".js",還是以映射的方式直接得到。

檢測(cè)此模塊有沒(méi)有加載過(guò),或正在被加載。因此,需要一個(gè)對(duì)象來(lái)保持所有模塊的加載情況。當(dāng)用戶從來(lái)沒(méi)有加載過(guò)此節(jié)點(diǎn),就進(jìn)入加載流程。

創(chuàng)建script節(jié)點(diǎn),綁定onerror,onload,onreadychange等事件判定加載成功與否,然后添加href并插入DOM樹(shù),開(kāi)始加載。

將模塊的URL,依賴列表等構(gòu)建成一個(gè)對(duì)象,放到檢測(cè)隊(duì)列中,在onerror,onload,onreadychange等事件觸發(fā)時(shí)進(jìn)行檢測(cè)。

require的實(shí)現(xiàn):

window.require = $.require = function require(list, factory, parent) {
    var deps = {} // 檢測(cè)它的依賴是否都未2
    var args = [] // 保存依賴模塊的返回值
    var dn = 0 // 需要安裝的模塊數(shù)
    var cn = 0 // 已安裝的模塊數(shù)
    var id = parent || `callback${setTimeout("1")}`
    var parent = parent || basepath // basepath為加載器的路徑
    `${list}`.replace($.rowd, (el) => {
        var url = loadJSCSS(el, parent)
        if (url) {
            dn++
            if (module[url] && module[url].state === 2) {
                cn++
            }
            if (!deps[url]) {
                args.push(url)
                deps[url] = "alogy" // 去重
            }
        }
    })
    modules[id] = { // 創(chuàng)建一個(gè)對(duì)象,記錄模塊的加載情況與其他信息
        id: id,
        factory: factory,
        deps, deps,
        args: args,
        state: 1
    }
    if (dn === cn) { // 如果需要安裝的等于已安裝好的
        fireFactory(id, args, factory) // 安裝到框架中
    } else {
        // 放入到檢測(cè)對(duì)象中,等待 checkDeps處理
        loadings.unshift(id)
    }
    checkDeps()
}

大多數(shù)情況下喜歡使用Dep來(lái)表示消息訂閱器,Depdependence的縮寫(xiě),中文是依賴.

require一次,相當(dāng)于把當(dāng)前的用戶回調(diào)當(dāng)成一個(gè)不用加載的匿名模塊,ID是隨機(jī)生成,回調(diào)是否執(zhí)行,要待deps對(duì)象里面所有值都為2

require方法中重要方法:

loadJSCSS,作用:用于轉(zhuǎn)換ID為URL

fireFactory,執(zhí)行用戶回調(diào)

checkDeps,檢測(cè)依賴是否都安裝好,安裝好就執(zhí)行fireFactory

function loadJSCSS(url, parent, ret, shim) {
    // 1. 特別處理mass | ready標(biāo)識(shí)符
    if (/^(mass|ready)$/.test(url)) {
        return url
    }
    // 2. 轉(zhuǎn)換為完成路勁
    if ($.config.alias[url]) { // 別名
        ret = $.config.alias[url]
        if (typeof ret === "object") {
            shim = ret
            ret = ret.src
        }
    } else {

        if (/^(w+)(d)?:.*/.test(url)) { // 如果本來(lái)就是完整路徑
            ret = url
        } else {
            parent = parent.substr(0, parent.lastIndexOf("/"))
            var tmp = url.charAt(0)
            if (tmp !== "." && tmp !== "/") { // 相對(duì)于更路徑
                ret = basepath + url
            } else if (url.slice(0, 2) === "./") { // 相對(duì)于兄弟路徑
                ret = parent + url.slice(1)
            } lse if (url.slice(0, 2) === "..") { // 相對(duì)于父路徑
                var arr = parent.replace(//$/, "").split("/")
                tmp = url.replace(/..//g, () => {
                    arr.pop()
                    return ""
                })
                ret = `${arr.join("/")}/${tmp}`
            } else if (tmp === "/") {
                ret = `${parent}${url}`  // 相對(duì)于兄弟路徑
            } else {
                $.error(`不符合模塊標(biāo)識(shí)符規(guī)則:${url}`)
            }
        }
    }

    var src = ret.replace(/[?#].*/, "")
    var ext
    if (/.(css|js)$/.test(src)) {
        ext = RegExp.$1
    }
    if (!ext) { // 如果沒(méi)有后綴名,加上后綴名
        src += ".js"
        ext = "js"
    }
    //  開(kāi)始加載JS 或 CSS
    if (ext === "js") {
        if (!modules[src]) { // 如果之前沒(méi)有加載過(guò)
            modules[src] = {
                id: src,
                parent: parent,
                exports: {}
            }
            if (shim) { // shim機(jī)制
                require(shim.deps || "", () => {
                    loadJS(src, () => {
                        modules[src].state = 2
                        modules[src].exports = type shim.exports === "function" ? shim.exports() : window[shim.exports]
                        checkDeps()
                    })
                })
            } else {
                loadJS(src)
            }
        }
        return src
    } else {
        loadCSS(src)
    }
}

function loadJS(url, callback) {
    // 通過(guò)script節(jié)點(diǎn)加載目標(biāo)文件
    var node = DOC.createElement("script")
    node.className = moduleClass // 讓getCurrentScript只處理類名為moduleClass的script節(jié)點(diǎn)
    node[W3C ? "onload" : "onreadystatechange"] = function () {
        if (W3C || /loaded|complete/i.test(node.readyState)) {
            // facotrys里面裝著define方法的工廠函數(shù)(define(id?, deps?, factory))
            var factory = factorys.pop()
            factory && factory.delay(node.src)
            if (callback) {
                callback()
            }
            if (checkFail(node, false, !W3C)) {
                $.log(`已成功加載${node.src}`, 7)
            }
        }
    }
    node.onerror = function () {
        checkFail(node, true)
    }
    // 插入到head的第一個(gè)節(jié)點(diǎn)前,防止IE6下標(biāo)簽沒(méi)閉合前使用appendChild拋錯(cuò)
    node.src = url
    head.insertBefore(node, head.firstChild)
}

function checkDeps () {
    loop: for (var i = loadings.length, id; id = loadings[--i];) {
        for (var key in deps) {
            if (hasOwn.call(deps, key) && modules[key].state !== 2) {
                continue loop
            }
        }
        //  如果deps是空對(duì)象或者其依賴的模塊的狀態(tài)都是2
        if (obj.state !== 2) {
            loading.splice(i, 1) //  必須先移除再安裝,防止在IE下DOM樹(shù)建完成后手動(dòng)刷新頁(yè)面,會(huì)多次執(zhí)行它
            fireFactory(obj.id, obj.args, obj.factory)
            checkDeps() // 如果成功,則再執(zhí)行一次,以防止有些模塊就差本模塊沒(méi)有安裝好
        }
    }
}

function fireFactory (id, deps, factory) { // 從 modules中手機(jī)各模塊的返回值執(zhí)行factory
    for (var i = 0, array = [], d; d = deps[i++];) {
        array.push(modules[d].exports)
    }
    var module = Object(modules[id])
    var ret = factory.apply(global, array)
    modules.state = 2
    if (ret !== void 0) {
        modules[id].exports = ret
    }
    return ret
}

define方法

define需要考慮循環(huán)依賴的問(wèn)題。比如:加載A,要依賴B與C,加載B,要依賴A與C。這時(shí)A與B就循環(huán)依賴了。A與B在判定各自的deps中的鍵值都是2時(shí)才執(zhí)行,結(jié)果都無(wú)法執(zhí)行了。

window.define = $.define = function define (id, deps, factory) {
    var args = $.slice(arguments)
    if (typeof id === "string") {
        var _id = args.shift()
    }
    if (typeof args[0] === "boolean") { // 用于文件合并,在標(biāo)準(zhǔn)瀏覽器中跳過(guò)不定模塊
        if (args[0]) {
            return
        }
        args.shift()
    }
    if (typeof args[0] === "function") { // 上線合并后能直接的到模塊ID,否則尋找當(dāng)前正在解析中的script節(jié)點(diǎn)的src作為模塊ID
        args.unshift([])
    }
    // 除了Safari外,都能直接通過(guò)getCurrentScript一步到位得到當(dāng)前執(zhí)行的script節(jié)點(diǎn),Safari可通過(guò)onload+delay閉包組合解決
    id = modules[id] && modules[id].state >= 1 ? _id : getCurrentScript()
    factory = args[1]
    factory.id = _id // 用于調(diào)試
    factory.delay = function (id) {
        args.push(id)
        var isCycle = true
        try {
            isCycle = checkCycle(modules[id].deps, id)
        } catch (e) {}
        if (isCycle) {
            $.error(`${id}模塊與之前的某些模塊存在循環(huán)依賴`)
        }
        delete factory.delay // 釋放內(nèi)存
        require.apply(null, args)
    }
    if (id) {
        factory.delay(id, args)
    } else {
        factorys.push(factory)
    }
}

checkCycle方法:

function checkCycle (deps, nick) {
    // 檢測(cè)是否存在循環(huán)依賴
    for (var id in deps) {
        if (deps[id] === "alogy" && modules[id].state !== 2 && (id === nick || checkCycle(modules[id].deps, nick))) {
            return true
        }
    }
}
語(yǔ)言模塊

字符串

類型:

與標(biāo)簽無(wú)關(guān)的實(shí)現(xiàn):carAt.charCodeAt,concat,indexOf,lastIndexof,localCompare,match,replace,serach,slice,split,substring,toLocaleLowerCase,toLocaleUpperCase,toLowerCase,toUpperCase以及從Object繼承回來(lái)的方法,如toString,valueOf。

與標(biāo)簽有關(guān)的實(shí)現(xiàn),都是對(duì)原字符串添加一對(duì)標(biāo)簽:anchor,big,blink,bold,fixedfontcolor,italics,small,strike,sub,sup

后來(lái)添加或?yàn)闃?biāo)準(zhǔn)化的瀏覽器方法: trim,quote,toSource,trimLeft,trimRight

truncate
用于對(duì)字符進(jìn)行階段處理,當(dāng)超過(guò)限定長(zhǎng)度,默認(rèn)添加三個(gè)點(diǎn)號(hào)或其它。

function truncate (target, length = 30, truncation) {
    truncation = truncation === void(0) ? "..." : truncation
    return traget.length > length ? `${target.slice(0, length - target.length)}${truncation}` : `${target}`
}

cameliae
轉(zhuǎn)換為駝峰分格

function camelize (target) {
    if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
        return target
    }
    return target.replace(/[-_][^-_]/g, (match) => {
        return match.charAt(1).toUpperCase()
    })
}

dasherize
轉(zhuǎn)為連字符風(fēng)格,亦即CSS變量的風(fēng)格

function underscored (target) {
    return target.replace(/([a-zd]([A-Z]))/g, "$1_$2").replace(/-/g, "_").toLowerCase()
}
function dasherize (target) {
    return underscored(target).replace(/_/g, "-")
}

capitalize
首字母大寫(xiě)

function capitalize (target) {
    return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase()
}

stripTags
移除字符串中 html標(biāo)簽

function stripTags (target) {
    return String(target || "").replace(/<[^>]+>/g, "")
}

stripScripts
移除字符串中所有的script標(biāo)簽

function stripScripts (target) {
    return Sting(target || "").replace(/                
閱讀需要支付1元查看
<