成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript進(jìn)階學(xué)習(xí)(二)—— 基于原型鏈繼承的js工具庫的實(shí)現(xiàn)方法

陳偉 / 876人閱讀

摘要:一些額外的全局函數(shù)命名空間對象接口和構(gòu)造函數(shù)與沒有典型的關(guān)聯(lián),但卻是有效的。最后有幾點(diǎn)需要說明的是每個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個指向原型對象的內(nèi)部指針。

文章來源:小青年原創(chuàng)
發(fā)布時間:2016-07-03
關(guān)鍵詞:JavaScript,原型鏈,jQuery類庫
轉(zhuǎn)載需標(biāo)注本文原始地址: http://zhaomenghuan.github.io...

前言

寫這篇文章的目的很簡單,就是想把之前一些不太清晰的概念梳理一下,網(wǎng)上這類教程很多,但是本文盡可能還原問題本質(zhì),注意知識點(diǎn)之間的聯(lián)系。相信看過我前面的博客的朋友一定知道我寫文章的風(fēng)格了,盡可能詳盡,而且不是只是為了解決某一個小問題而寫,方便大家知識點(diǎn)更體系,一篇內(nèi)容其實(shí)相當(dāng)于一章節(jié)的內(nèi)容,容量有點(diǎn)大,我也不是一天完成的,一般是一周時間左右,所以大家閱讀的話可能也需要一些時間才能有所收獲。作為進(jìn)階教程,本文將簡要講述JavaScript面向?qū)ο缶幊痰膬?nèi)容,但是不會介紹什么是接口,什么是對象,什么是對象屬性,什么是對象方法,但是相信你看完了后自然理所當(dāng)然的理解了這些基本概念。

重新認(rèn)識window對象 Window與window的區(qū)別

在開始學(xué)習(xí)之前我們首先用一個工具,就是瀏覽器自帶的開發(fā)者工具控制臺。我這里用hbuider直接打開這個工具,在【web瀏覽器】預(yù)覽工具欄右鍵單擊會彈出一個框框,在這個框框中選擇【Console】,然后在命令行輸入js代碼我們就可以看到執(zhí)行結(jié)果,這里我們先輸入一個window,然后會發(fā)現(xiàn)有json結(jié)構(gòu)的內(nèi)容。

我們?nèi)绻挥每刂婆_,直接用document.write(window);,頁面上寫出:[object Window],很顯然內(nèi)容不及這里直觀,所以我們后面的很多內(nèi)容會在控制臺演示。熟練使用這個工具會給我們的開發(fā)帶來很多好處,我想很多新手吐槽JavaScript不易調(diào)試,其實(shí)很多時候是他們不會調(diào)試。

很多博客在文章一開始講一大堆理論,為了避免落入俗套,我們這里先做幾個有趣的實(shí)驗(yàn),我們在控制臺繼續(xù)輸入window.top,window.window甚至window.window.window,...,我們會發(fā)現(xiàn)得到的結(jié)果居然一模一樣。

> window === window.window               // true
> window === window.top                  // true
> window.top === window.window           // true
> window.window === window.window.window // true

是不是有點(diǎn)暈了,這是什么鬼。。。不要急,我們接著看,我們來個更暈的,哈哈!

> window        
// Window {top: Window, window: Window, location: Location, chrome: Object, document: document…}
> Window        
// function Window() { [native code] }
> window.Window 
// function Window() { [native code] }
> Window.window
// undefined

這到底是什么鬼?windowWindow到底是什么關(guān)系?

我們下面來接著看看他們各自的類型:

> typeof Window            // "function"
> typeof window            // "object"
> window instanceof Window // true

查閱資料發(fā)現(xiàn):

window 對象表示一個包含DOM文檔的窗口,其 document 屬性指向窗口中載入的 DOM文檔 。window 對象實(shí)現(xiàn)了 Window 接口,此接口繼承自 AbstractView 接口。一些額外的全局函數(shù)、命名空間、對象、接口和構(gòu)造函數(shù)與 window 沒有典型的關(guān)聯(lián),但卻是有效的。這個接口從 EventTarget 接口繼承屬性,通過 WindowTimers 、WindowBase64 和 WindowEventHandlers 實(shí)現(xiàn)屬性。

這么說相信新手應(yīng)該沒啥感覺,最好還是舉個例子說說,比如我們?nèi)コ燥堃c(diǎn)菜,Window說白了一個菜單,window是端上桌子的那道菜,至于這道菜色香味以及制作方法和Window無關(guān),只和window有關(guān)。

Window規(guī)定了對象的類型,所以我們不難理解window instanceof Window的值為啥是trueWindowfunction。那么這里我們就清楚了windowWindow的具體方法實(shí)現(xiàn),而Window對象沒有Window屬性,所以Window.windowundefined,所以我們需要關(guān)注的是Window的屬性方法。

我們在前面可以看出來window對象自身有topwindow屬性,類型為 Window,并且值是window本身;另外有個Window屬性,值是Window對象,自然至此前面的內(nèi)容也解釋清楚了。

window 對象document屬性( 指向當(dāng)前窗口內(nèi)的文檔節(jié)點(diǎn))

window.document指向document對象的引用,document對象是Document 接口接口的具體實(shí)現(xiàn)。Document 接口代表在瀏覽器及服務(wù)器中加載任意 web 頁面,也作為 web 頁面內(nèi)容(DOM tree, 包含如 和

雖然這段話看起來,但是實(shí)際上意思很簡單:
如果我們要想獲取一個document的內(nèi)容,我們可以使用document對象下的方法屬性和方法去獲取,比如獲取標(biāo)題:



    
        
        hello world
    
    
        
    

我們這里的document為啥不加window也可以彈出結(jié)果呢,因?yàn)閣indow為頂層對象,這里可以忽略不寫,比如alert()方法其實(shí)是window.alert()下的方法,我們這里不寫window,一樣可以得到結(jié)果。另外,我們這里只是獲取了title,至于其他的內(nèi)容,那就要學(xué)習(xí)document的屬性和方法。

__proto__屬性(原型指針) 和 prototype屬性(原型對象)

說到這兩個屬性,我們真的很糾結(jié),這兩者到底有什么聯(lián)系和區(qū)別呢?我們先看下面的例子:

> window.prototype === window.__proto__     // false
> Window.prototype === window.__proto__     // true
> window.constructor === Window             // true
> Window.__proto__.__proto__.__proto__.__proto__ // null

臥槽,這是什么鬼?prototype__proto__到底分別各自指什么,Window鏈?zhǔn)秸{(diào)用__proto__怎么最后會變成null? 似乎說到這里謎團(tuán)越來越多了,我們這里就要跳出window對象舉個簡單例子說說,不然大家真的是暈的。

function person(name) {
    this.name = name;
    this.getName = function() {
        alert(this.name)
    }
}

var zhangsan = new person("zhangsan");
var lisi = new person("lisi");

console.log(zhangsan.name)
console.log(lisi.name)
zhangsan.getName();
lisi.getName();
結(jié)果:
"zhangsan"
"lisi"

注:可以使用關(guān)鍵字 this調(diào)用類中的屬性, this是對當(dāng)前對象的引用。

這樣一個例子我們似乎看到了面向?qū)ο笾欣^承的特性,在其他面向?qū)ο笳Z言中,這里的person函數(shù)被設(shè)計(jì)為“類”,但是在JavaScript中這里設(shè)計(jì)得有點(diǎn)畸形的感覺,為啥這么說呢,因?yàn)檫@里的person是一個構(gòu)造函數(shù)(constructor),用new實(shí)例化的也不是其他面向?qū)ο笳Z言中的類,而是構(gòu)造函數(shù),這種設(shè)計(jì)導(dǎo)致一個問題是啥呢?無法共享屬性和方法,每一個實(shí)例對象,都有自己的屬性和方法的副本!?。?/strong>

比如:每一個實(shí)例對象都有g(shù)etName(),都是從父親構(gòu)造器中繼承得到,這樣就產(chǎn)生多個副本,但是我們希望這個方法是公用的,避免多個副本的資源浪費(fèi),我們希望能夠把公用的屬性方法提取出來,然后實(shí)例化的對象也可以引用,但是不會直接拷貝一份作為副本。這個時候構(gòu)造函數(shù)(constructor)顯得有點(diǎn)力不從心了,JavaScript的設(shè)計(jì)者引入了一個重要的屬性prototype,這個屬性包含一個對象(通常稱為“prototype對象")。我們把這個例子改成用prototype寫試試:

function person(name) {
    this.name = name;
}
person.prototype.getName = function() {
    alert(this.name)
}

var zhangsan = new person("zhangsan");
var lisi = new person("lisi");

這樣我們多個實(shí)例化對象可以公用同一個方法,換句話說所有的實(shí)例對象共享同一個prototype對象,通常稱為原型。一層層的繼承實(shí)現(xiàn)了鏈條式的"原型鏈"(prototype chain),JavaScript因此通過這個原型鏈實(shí)現(xiàn)繼承。至于為啥最開始怎么設(shè)計(jì),都是為了開發(fā)者簡單,但是也因此給大家的感覺是特別,而且特別難理解,但是事實(shí)上其實(shí)并沒有那么神奇?。?!

prototype屬性很特殊,它還有一個隱式的constructor,指向了構(gòu)造函數(shù)本身。

> person.prototype.constructor === person // true
> zhangsan.constructor === person         // true
> zhangsan.constructor === person.prototype.constructor // true

說了這個多,我們一直沒有解釋__proto__屬性,我們上面講了可以通過構(gòu)造函數(shù)的prototype屬性實(shí)現(xiàn)繼承共用公用的屬性方法,但是我們沒有說明實(shí)例化對象如何訪問到它所繼承的對象的原型對象,這里的__proto__屬性就是這個作用。我們再回過頭去看之前的問題:
因?yàn)?b>window是通過實(shí)例化Window得到,自然我們訪問Window原型對象有兩種方法:1.直接通過Window的prototype屬性;2.通過實(shí)例化子對象的__proto__訪問父對象的原型對象。這兩種方法實(shí)現(xiàn)的結(jié)果一模一樣。

Window.prototype === window.__proto__ // true

另外在JavaScript中有一個很特別的地方:萬物皆對象,萬物皆為空。
怎么理解呢,在JavaScript中的一切都源于對象,而且最頂層的對象是null對象,這會讓人很費(fèi)解的。所以當(dāng)我們通過__proto__不斷的尋找最頂層的原型對象時會發(fā)現(xiàn)為null。

基于原型的編程不是面向?qū)ο缶幊讨畜w現(xiàn)的風(fēng)格,且行為重用(在基于類的語言中也稱為繼承)是通過裝飾它作為原型的現(xiàn)有對象的過程實(shí)現(xiàn)的。這種模式也被稱為弱類化,原型化,或基于實(shí)例的編程。

最后有幾點(diǎn)需要說明的是:

每個構(gòu)造函數(shù)都有一個原型對象(prototype),原型對象都包含一個指向構(gòu)造函數(shù)的指針(constructor),而實(shí)例都包含一個指向原型對象的內(nèi)部指針(__proto__)。

除了使用__proto__方式訪問對象的原型,還可以通過Object.getPrototypeOf方法來獲取對象的原型,以及通過Object.setPrototypeOf方法來重寫對象的原型。__proto__屬性只有瀏覽器才需要部署,其他環(huán)境可以沒有這個屬性,而且前后的兩根下劃線,表示它本質(zhì)是一個內(nèi)部屬性,不應(yīng)該對使用者暴露。

instanceof和Object.isPrototypeOf()可以判斷兩個對象是否是繼承關(guān)系。如上面那個例子:

// instanceof 運(yùn)算符返回一個布爾值,表示一個對象是否由某個構(gòu)造函數(shù)創(chuàng)建。
> zhangsan instanceof person
=> true
// Object.isPrototypeOf()只要某個對象處在原型鏈上,都返回true。
> person.prototype.isPrototypeOf(zhangsan)
=> true

這里推薦大家看看下面幾篇文章:

JavaScript面向?qū)ο蠛喗?/p>

JavaScript 原型中的哲學(xué)思想

Javascript繼承機(jī)制的設(shè)計(jì)思想

如何打造一個自己的類jQuery的js工具庫?

文章寫到本來是準(zhǔn)備重新開篇的,剛剛上面在window下將原型鏈繼承不知道會不會有點(diǎn)誤導(dǎo)一些朋友,因?yàn)樽铋_始是準(zhǔn)備以window對象入手將面向?qū)ο蟮膬?nèi)容整理一下,發(fā)現(xiàn)寫著寫著有點(diǎn)零散了,因?yàn)閣indow對象有很多其他內(nèi)容值得將,但是篇幅和本文主題影響,只能先停下后面再開篇補(bǔ)充,講了原型鏈繼承的理論知識,我們自然要實(shí)際動手做點(diǎn)項(xiàng)目才能說明問題。

基本概念講解

如果我們?nèi)ゲ榭匆恍﹋s庫的寫法,我們會發(fā)現(xiàn)經(jīng)常有這樣一種結(jié)構(gòu):

(function(w,undefined) {
    //...
})(window);

在理解為什么要這樣寫之前我們首先要明白什么JavaScript的作用域,什么是匿名函數(shù),什么是閉包?

作用域

在es6之前,JavaScript是遵循函數(shù)作用域,不支持塊級作用域。

var i=0;
if(i<2){
    var i = 2;
}
alert(i); // 2

在es6中支持使用let聲明了一個塊級域的本地變量,并且可以同時初始化該變量。

var i=0;
if(i<2){
    let i = 2;
}
alert(i); // 0

函數(shù)內(nèi)部可以直接讀取函數(shù)全局變量。函數(shù)內(nèi)的變量如果是使用var 申明,則是局部變量,作用域范圍為函數(shù)體內(nèi)部,不可讀??;但是需要注意的是未經(jīng)過var申明,就變成了全局變量,在函數(shù)外部也可以調(diào)用。

// 局部變量類型:
var i=0;
var fn = function () {
    if(i<2){
        var i = 2;
    }
}
fn();
alert(i); // 0

// 全局變量類型
var i=0;
var fn = function () {
    if(i<2){
        i = 2;
    }
}
fn();
alert(i); // 2

變量提升:一個變量或函數(shù)可以在它被引用之后聲明。

【變量】
foo = 2
var foo;
// 被隱式地解釋為:
var foo;
foo = 2;

【函數(shù)】
hoisted(); // logs "foo"
function hoisted() {
  console.log("foo");
}
匿名函數(shù):沒有函數(shù)名稱的函數(shù)

匿名函數(shù)是這樣的:

function(arg1,arg2){
    // code
}

但是通常我們會把匿名函數(shù)寫成自執(zhí)行的匿名函數(shù):

(function(arg1,arg2){
    // code
})(a1,a2);

等價于:
var fn = function(arg1,arg2){
    // code
}
fn(a1,a2);

其實(shí)這里就是實(shí)參與形參的關(guān)系,arg1,arg2在函數(shù)體內(nèi)作為形參被引用,a1,a2作為實(shí)參在調(diào)用的時候傳入到函數(shù)體中被調(diào)用,至于變量內(nèi)部存儲原理這里不做深入探究,畢竟學(xué)過編程的人應(yīng)該都清楚。

我們現(xiàn)在回過頭來看看本小節(jié)開頭說的那個例子,為啥要那樣寫呢?

(function(w,undefined) {
    //...
})(window);

為什么要傳入 window?
通過傳入 window變量,使得 window由全局變量變?yōu)榫植孔兞浚?dāng)在我們封裝的代碼塊中訪問 window時,不需要將作用域鏈回退到頂層作用域,這樣可以更快的訪問 window;同時將 window作為參數(shù)傳入,可以在壓縮代碼時進(jìn)行優(yōu)化。

為什么要傳入 undefined?
在只執(zhí)行匿名函數(shù)的作用域內(nèi),確保 undefined 是真的未定義。因?yàn)?undefined 能夠被重寫,賦予新的值。

閉包

我們前面說了在函數(shù)外可以調(diào)用函數(shù)內(nèi)未經(jīng)過var聲明的全局變量,但是如何從外部讀取函數(shù)局部變量呢?我們可以在函數(shù)內(nèi)部再定義一個函數(shù)。

var fn = function(){
    var name = "local";
    var f = function(){
        alert(name); 
    }
    return f
}

// 調(diào)用
var resurlt = fn();
resurlt();
// or
fn()();

閉包主要有兩個作用:
一是可以讀取函數(shù)內(nèi)部的變量,另一個就是讓這些變量的值始終保持在內(nèi)存中。

讀取函數(shù)內(nèi)部變量我們很好理解,但是至于內(nèi)部變量的值保存在存儲中這個就有點(diǎn)難理解,我們看個例子:

var fn = function(){
    var i = 0;
    add = function(){
        i++;
    }
    var f = function(){
        alert(i); 
    }
    return f
}

var result = fn();
result(); // 0
add();
result(); // 1

add未加var 聲明是全局變量,如果變量i不在內(nèi)存中存儲,那么我們第一次和第二次調(diào)用result()值都應(yīng)該為0。原因在于我們將fn()的返回值f()數(shù)賦值給一個全局變量,由于這個全局變量一直處于內(nèi)存中,f函數(shù)同樣也在內(nèi)存中,f()函數(shù)依賴于fn()函數(shù),因此fn()中的局部變量i一直處于內(nèi)存之中。
如果上面的例子在調(diào)用的時候使用fn()()則不會出現(xiàn)這種情況。

1)由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。

2)閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值?!?學(xué)習(xí)Javascript閉包(Closure)

這里簡要講解了一下閉包的一些作用,主要是為了幫助我們理解為啥一些js庫采用閉包。

jQuery中鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn)原理

首先我們怎么實(shí)現(xiàn)私有命名空間?
通過定義一個匿名函數(shù),創(chuàng)建了一個"私有"的命名空間,該命名空間的變量和方法,不會破壞全局的命名空間,我們只暴漏出一個頂層的對象供外部調(diào)用即可。

前面我們講到window對象的時候有個知識點(diǎn)沒有說的是,我們在頁面定義一個全局變量的時候,這個全局變量最終是會在window對象下,對于調(diào)用window對象下的屬性和方法我們一般無需通過window.的形式就可以調(diào)用。同理當(dāng)我們引用jQuery這種庫的時候,jQuery對象會在引用頁面的window對象下,這是因?yàn)閖Query庫最后會將jQuery或者$對象掛在window對象下,這樣就實(shí)現(xiàn)了頂層對象的暴漏。

下面我們實(shí)現(xiàn)一個適用于現(xiàn)代瀏覽器的極小DOM操作庫,主要解決移動端,所以我們這里取名為mjs。

(function(w,undefined) {
    // 構(gòu)造函數(shù)
    var mjs = function(selector, context) {
        return new mjs.fn.init(selector, context);
    }        
    // 構(gòu)造函數(shù)mjs的原型對象
    mjs.fn = mjs.prototype = {
        constructor: mjs,
        init: function (selector, context) {
            //...
        }
    }
    
    mjs.fn.init.prototype = mjs.fn;
    // 為window全局變量添加mjs對象
    w.mjs = w.m = mjs;
})(window);

這樣我們就可以無需new mjs(),直接使用 mjs.* 或者 m.* 鏈?zhǔn)秸{(diào)用相關(guān)方法。

selector(選擇器)

下面我們實(shí)現(xiàn)一個最簡的選擇器,這里我不考慮兼容低級版本瀏覽器,使用querySelectorAll實(shí)現(xiàn)。我們接著上面的完善mjs.prototype.init方法。我們?nèi)绻豢紤]鏈?zhǔn)秸{(diào)用,我們最簡單的選擇器甚至可以長這樣:

var $ = function (selector) {
   return document.querySelector(selector);
}

調(diào)用:
$(".content")

如果想給選擇器加一個上下文,我們進(jìn)一步可以這樣:

/**
 * 選擇器
 * @param {Object} selector
 * @param {Object} context
 */
var $ = function (selector, context) {
    var context = context || document;
    var el = context.querySelectorAll(selector);
    return Array.prototype.slice.call(el);
};

// 調(diào)用       
var divObj = $(".div",$(".content")[0]);
console.log(divObj[0].innerHTML)

當(dāng)然我們這里補(bǔ)充完整就是這樣了:

// 構(gòu)造函數(shù)mjs的原型對象
mjs.prototype = {
    constructor: mjs,
    init: function (selector, context) {    
        if(!selector) { 
            return mjs; 
        }else if(typeof selector === "object"){
            var selector = [selector];
            for (var i = 0; i < selector.length; i++) {
               this[i] = selector[i];
            }
            this.length = selector.length;
            return mjs;
        }else if(typeof selector === "string"){    
            var selector = selector.trim();
            var context = context || document;
            var el = context.querySelectorAll(selector);
            var dom = Array.prototype.slice.call(el);
            var length = dom.length;
            for (var i = 0; i < length; i++) {
                this[i] = dom[i];
            }
            this.context = context;
            this.selector = selector;
            this.length = length;
            return this;
        }
    }
}

這里我們先只完成最簡單的選擇器功能,還有當(dāng)selector是function類型的我們沒有進(jìn)行判斷,這里不貼出來,大家具體可以看看源代碼。我們可以驗(yàn)證一下我們封裝的這個選擇器:

div1 span1
console.log(mjs(".divBox")[0].innerHTML) // "div1span1" console.log(mjs(".divBox span")[0].innerHTML) // "span1" var divBox = mjs(".divBox")[0]; console.log(mjs("span",divBox)[0].innerHTML) // "span1"

因?yàn)閕nnerHTML是原生DOM操作的方法,我們mjs對象沒有這個方法,所以我們這里是將mjs對象轉(zhuǎn)成了原生DOM對象,轉(zhuǎn)換方法:mjs(selector)[0]。

html()、text()、attr()

為了簡單起見我們繼續(xù)封裝,先完成一個html()方法。

...
html: function (content) {
    if (content === undefined && this[0].nodeType === 1) {
              return this[0].innerHTML.trim();
          }else{
              var len = this.length;
        for (var i = 0; i < len; i++) {
            this[i].innerHTML = content;
        }
        return this;
          }
},
text: function (val) {
    if (!arguments.length) {
        return this[0].textContent.trim();
    } else {
        for (var i = 0; i < this.length; i++) {
            this[i].innerText = val;
        }
        return this;
    }
}
...

上面的例子我們可以這樣調(diào)用:

// 直接獲取內(nèi)容,默認(rèn)獲取第一個匹配項(xiàng)
console.log(mjs(".divBox").html())
console.log(mjs(".divBox span").html())
console.log(mjs(".divBox span").text())
// 更新內(nèi)容,默認(rèn)更新所有匹配項(xiàng)
mjs(".divBox span").html("我是新的內(nèi)容")
mjs(".divBox span").text("我是新的內(nèi)容")
// 支持上下文查找方法
console.log(mjs("span",mjs(".divBox")[0]).html())
// 設(shè)置屬性
mjs(".divBox").attr("name","divBox");
// 獲取屬性
console.log(mjs(".divBox").attr("name")) 
prepend()、append()、before()、after()、remove()
prepend: function(str) {
    var len = this.length;
          for (var i = 0; i < len; i++) {
        this[i].insertAdjacentHTML("afterbegin", str);
    }
    return this;
},
append: function (str) {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        this[i].insertAdjacentHTML("beforeend", str);
    }
    return this;
},
before: function (str) {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        this[i].insertAdjacentHTML("beforebegin", str);
    }
    return this;
},
after: function (str) {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        this[i].insertAdjacentHTML("afterend", str);
    }
    return this;
},
remove: function () {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        this[i].parentNode.removeChild(this[i]);
    }
      return this;
}

調(diào)用:

// 添加元素
mjs(".divBox").prepend("
  • prepend
") mjs(".divBox").append("
  • append
") mjs(".divBox").before("
  • before
") mjs(".divBox").after("
  • after
") // 刪除元素 mjs(".divBox").remove();

insertAdjacentHTML() 將指定的文本解析為 HTML 或 XML,然后將結(jié)果節(jié)點(diǎn)插入到 DOM 樹中的指定位置處。該方法不會重新解析調(diào)用該方法的元素,因此不會影響到元素內(nèi)已存在的元素節(jié)點(diǎn)。從而可以避免額外的解析操作,比直接使用 innerHTML 方法要快?!狹DN insertAdjacentHTML

語法:
element.insertAdjacentHTML(position, text);
position 是相對于 element 元素的位置,并且只能是以下的字符串之一:

beforebegin: 在 element 元素的前面。

afterbegin:在 element 元素的第一個子節(jié)點(diǎn)前面。

beforeend:在 element 元素的最后一個子節(jié)點(diǎn)后面。

afterend:在 element 元素的后面。

hasClass()、addClass()、removeClass()、toggleClass()
...
hasClass: function (cls) {
    return this[0].classList.contains(cls);
},
addClass: function (cls) {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        if(!this[i].classList.contains(cls)){
            this[i].classList.add(cls);
        }
    }
    return this;
},
removeClass: function (cls) {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        if(this[i].classList.contains(cls)){
            this[i].classList.remove(cls);
        }
    }
    return this;
},
toggleClass: function (cls) {
    return this[0].classList.toggle(cls);
}
...

調(diào)用方法:

// hasClass(返回值為布爾值)
console.log(mjs(".divBox").hasClass("divBox"))
// addClass
mjs(".divBox").addClass("red")
// removeClass
mjs(".divBox").removeClass("red")
// toggleClass
mjs(".divBox").toggleClass("red")
css()
css: function (attr,val) {
    var len = this.length;
    for(var i = 0;i < len; i++) {
        if(arguments.length === 1){
            var obj = arguments[0];
            if(typeof obj === "string"){
                return getComputedStyle(this[i],null)[attr];
            }else if(typeof obj === "object"){
                for(var attr in obj){
                    this[i].style[attr] = obj[attr];
                }      
            }
        } else {    
            if(typeof val === "function"){
                this[i].style[attr] = val();
            }else{
                this[i].style[attr] = val;
            }   
        } 
    }
    return this;
}

調(diào)用方法:

// 獲取樣式屬性值
console.log(mjs(".divBox").css("color"));
// 設(shè)置樣式屬性值
// 方法1
mjs(".divBox").css("color","red");
// 方法2
mjs(".divBox").css({
    "width":"100px",
    "color":"white",
    "background-color":"#98bf21",
    "font-family":"Arial",
    "font-size":"20px",
    "padding":"5px"
});
// 方法3
mjs(".divBox").css(
    "background-color",function(){
        return "#F00"
    }
)    
find()、first()、last()、eq(index)、parent()
find: function(selector){
    return this.init(selector,this[0])
},
first: function(){
    return this.init(this[0])
},
last: function(){
    return this.init(this[this.length-1])
},
eq: function(index){
    return this.init(this[index])
},
parent: function(){
    return this.init(this[0].parentNode);
}

我們前面想通過上下文查找內(nèi)容:

console.log(mjs("span",mjs(".divBox")[0]).html())

我們可以通過find方法這樣寫:

console.log(mjs(".divBox").find("span").html())            console.log(mjs(".divBox span").first().html())
console.log(mjs(".divBox span").last().html())
console.log(mjs(".divBox span").eq(1).html())
console.log(mjs(".divBox span").eq(1).parent().html())

關(guān)鍵在于mjs對象和原生dom的區(qū)別和相互轉(zhuǎn)換。

至此我們封裝了一個簡單的類jQuery的工具庫,當(dāng)然對于一個完整的工具庫,比如jQuery、zepto等,它們功能肯定是更為完善,封裝了更多的方法,在異常處理及性能、可拓展性方法做得更好,由于本文的重點(diǎn)不是為了完成一個完整的庫,在此只是拋磚引玉,只是學(xué)習(xí)一下常用的思想,有興趣的朋友可以繼續(xù)完善這個庫。

mjs github地址:https://github.com/zhaomenghu...

參考文章

MDN javascript
可想造一個屬于你自己的jQuery庫?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79868.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你“對象”還好嗎?

    摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    李昌杰 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你“對象”還好嗎?

    摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    Lyux 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你“對象”還好嗎?

    摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    AaronYuan 評論0 收藏0
  • 小技巧 - 收藏集 - 掘金

    摘要:然而學(xué)習(xí)布局,你只要學(xué)習(xí)幾個手機(jī)端頁面自適應(yīng)解決方案布局進(jìn)階版附源碼示例前端掘金一年前筆者寫了一篇手機(jī)端頁面自適應(yīng)解決方案布局,意外受到很多朋友的關(guān)注和喜歡。 十分鐘學(xué)會 Fiddler - 后端 - 掘金一.Fiddler介紹 Fiddler是一個http抓包改包工具,fiddle英文中有欺騙、偽造之意,與wireshark相比它更輕量級,上手簡單,因?yàn)橹荒茏ttp和https數(shù)據(jù)...

    A Loity 評論0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<