學(xué)習(xí) jQuery 源碼整體架構(gòu)熟空,打造屬于自己的 js 類庫

雖然現(xiàn)在基本不怎么使用jQuery了,但jQuery流行10多年JS庫搞莺,還是有必要學(xué)習(xí)它的源碼的息罗。也可以學(xué)著打造屬于自己的js類庫,求職面試時(shí)可以增色不少才沧。

本文章學(xué)習(xí)的是v3.4.1版本阱当。
unpkg.com源碼地址:https://unpkg.com/jquery@3.4.1/dist/jquery.js

jQuery github倉庫

自執(zhí)行匿名函數(shù)

(function(global, factory){

})(typeof window !== "underfined" ? window: this, function(window, noGlobal){

});

外界訪問不到里面的變量和函數(shù),里面可以訪問到外界的變量糜工,但里面定義了自己的變量弊添,則不會(huì)訪問外界的變量。
匿名函數(shù)將代碼包裹在里面捌木,防止與其他代碼沖突和污染全局環(huán)境油坝。
關(guān)于自執(zhí)行函數(shù)不是很了解的讀者可以參看這篇文章。
[譯] JavaScript:立即執(zhí)行函數(shù)表達(dá)式(IIFE)

瀏覽器環(huán)境下刨裆,最后把$jQuery函數(shù)掛載到window上澈圈,所以在外界就可以訪問到$jQuery了。

if ( !noGlobal ) {
    window.jQuery = window.$ = jQuery;
}
// 其中`noGlobal`參數(shù)只有在這里用到帆啃。

支持多種環(huán)境下使用 比如 commonjs瞬女、amd規(guī)范

commonjs 規(guī)范支持

commonjs實(shí)現(xiàn) 主要代表 nodejs

// global是全局變量,factory 是函數(shù)
( function( global, factory ) {

    //  使用嚴(yán)格模式
    "use strict";
    // Commonjs 或者 CommonJS-like  環(huán)境
    if ( typeof module === "object" && typeof module.exports === "object" ) {
        // 如果存在global.document 則返回factory(global, true);
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

// Pass this if window is not defined yet
// 第一個(gè)參數(shù)判斷window努潘,存在返回window诽偷,不存在返回this
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {});

amd 規(guī)范 主要代表 requirejs

if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    } );
}

cmd 規(guī)范 主要代表 seajs

很遺憾,jQuery源碼里沒有暴露對(duì)seajs的支持疯坤。但網(wǎng)上也有一些方案报慕。這里就不具體提了。畢竟現(xiàn)在基本不用seajs了压怠。

無 new 構(gòu)造

實(shí)際上也是可以 new的眠冈,因?yàn)?code>jQuery是函數(shù)。而且和不用new效果是一樣的菌瘫。
new顯示返回對(duì)象蜗顽,所以和直接調(diào)用jQuery函數(shù)作用效果是一樣的。
如果對(duì)new操作符具體做了什么不明白雨让」透牵可以參看我之前寫的文章。

面試官問:能否模擬實(shí)現(xiàn)JS的new操作符

源碼:

 var
    version = "3.4.1",

    // Define a local copy of jQuery
    jQuery = function( selector, context ) {
        // 返回new之后的對(duì)象
        return new jQuery.fn.init( selector, context );
    };
jQuery.fn = jQuery.prototype = {
    // jQuery當(dāng)前版本
    jquery: version,
    // 修正構(gòu)造器為jQuery
    constructor: jQuery,
    length: 0,
};
init = jQuery.fn.init = function( selector, context, root ) {
    // ...
    if ( !selector ) {
        return this;
    }
    // ...
};
init.prototype = jQuery.fn;
jQuery.fn === jQuery.prototype;     // true
init = jQuery.fn.init;
init.prototype = jQuery.fn;
// 也就是
jQuery.fn.init.prototype === jQuery.fn;  // true
jQuery.fn.init.prototype === jQuery.prototype;  // true

關(guān)于這個(gè)筆者畫了一張jQuery原型關(guān)系圖宫患,所謂一圖勝千言刊懈。

jQuery-v3.4.1原型關(guān)系圖.png

<sciprt src="https://unpkg.com/jquery@3.4.1/dist/jquery.js">
</script>
console.log({jQuery});
// 在谷歌瀏覽器控制臺(tái),可以看到j(luò)Query函數(shù)下掛載了很多靜態(tài)屬性和方法娃闲,在jQuery.fn 上也掛著很多屬性和方法虚汛。

Vue源碼中,也跟jQuery類似皇帮,執(zhí)行的是Vue.prototype._init方法卷哩。

function Vue (options) {
    if (!(this instanceof Vue)
    ) {
        warn('Vue is a constructor and should be called with the `new` keyword');
    }
    this._init(options);
}
initMixin(Vue);
function initMixin (Vue) {
    Vue.prototype._init = function (options) {};
};

核心函數(shù)之一 extend

用法:

jQuery.extend( target [, object1 ] [, objectN ] )        Returns: Object

jQuery.extend( [deep ], target, object1 [, objectN ] )

jQuery.extend API
jQuery.fn.extend API

看幾個(gè)例子:
(例子可以我放到在線編輯代碼的jQuery.extend例子codepen了,可以直接運(yùn)行)属拾。

// 1. jQuery.extend( target)
var result1 = $.extend({
    job: '前端開發(fā)工程師',
});

console.log(result1, 'result1', result1.job); // $函數(shù) 加了一個(gè)屬性 job  // 前端開發(fā)工程師

// 2. jQuery.extend( target, object1)
var result2 = $.extend({
    name: '若川',
},
{
    job: '前端開發(fā)工程師',
});

console.log(result2, 'result2'); // { name: '若川', job: '前端開發(fā)工程師' }

// deep 深拷貝
// 3. jQuery.extend( [deep ], target, object1 [, objectN ] )
var result3 = $.extend(true,  {
    name: '若川',
    other: {
        mac: 0,
        ubuntu: 1,
        windows: 1,
    },
}, {
    job: '前端開發(fā)工程師',
    other: {
        mac: 1,
        linux: 1,
        windows: 0,
    }
});
console.log(result3, 'result3');
// deep true
// {
//     "name": "若川",
//     "other": {
//         "mac": 1,
//         "ubuntu": 1,
//         "windows": 0,
//         "linux": 1
//     },
//     "job": "前端開發(fā)工程師"
// }
// deep false
// {
//     "name": "若川",
//     "other": {
//         "mac": 1,
//         "linux": 1,
//         "windows": 0
//     },
//     "job": "前端開發(fā)工程師"
// }

結(jié)論:extend函數(shù)既可以實(shí)現(xiàn)給jQuery函數(shù)可以實(shí)現(xiàn)淺拷貝将谊、也可以實(shí)現(xiàn)深拷貝〗グ祝可以給jQuery上添加靜態(tài)方法和屬性尊浓,也可以像jQuery.fn(也就是jQuery.prototype)上添加屬性和方法,這個(gè)功能歸功于this纯衍,jQuery.extend調(diào)用時(shí)this指向是jQuery栋齿,jQuery.fn.extend調(diào)用時(shí)this指向則是jQuery.fn

淺拷貝實(shí)現(xiàn)

知道這些襟诸,其實(shí)實(shí)現(xiàn)淺拷貝還是比較容易的:

// 淺拷貝實(shí)現(xiàn)
jQuery.extend = function(){
    // options 是擴(kuò)展的對(duì)象object1瓦堵,object2...
    var options,
    // object對(duì)象上的鍵
    name,
    // copy object對(duì)象上的值,也就是是需要拷貝的值
    copy,
    // 擴(kuò)展目標(biāo)對(duì)象歌亲,可能不是對(duì)象菇用,所以或空對(duì)象
    target = arguments[0] || {},
    // 定義i為1
    i = 1,
    // 定義實(shí)參個(gè)數(shù)length
    length = arguments.length;
    // 只有一個(gè)參數(shù)時(shí)
    if(i === length){
        target = this;
        i--;
    }
    for(; i < length; i++){
        // 不是underfined 也不是null
        if((options = arguments[i]) !=  null){
            for(name in options){
                copy = options[name];
                // 防止死循環(huán),continue 跳出當(dāng)前此次循環(huán)
                if ( name === "__proto__" || target === copy ) {
                    continue;
                }
                if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }

    }
    // 最后返回目標(biāo)對(duì)象
    return target;
}

深拷貝則主要是在以下這段代碼做判斷陷揪⊥锱福可能是數(shù)組和對(duì)象引用類型的值悍缠,做判斷扮休。

if ( copy !== undefined ) {
    target[ name ] = copy;
}

為了方便讀者調(diào)試迎卤,代碼同樣放在jQuery.extend淺拷貝代碼實(shí)現(xiàn)codepen,可在線運(yùn)行蜗搔。

深拷貝實(shí)現(xiàn)

$.extend = function(){
    // options 是擴(kuò)展的對(duì)象object1,object2...
    var options,
    // object對(duì)象上的鍵
    name,
    // copy object對(duì)象上的值樟凄,也就是是需要拷貝的值
    copy,
    // 深拷貝新增的四個(gè)變量 deep缝龄、src、copyIsArray、clone
    deep = false,
    // 源目標(biāo)叔壤,需要往上面賦值的
    src,
    // 需要拷貝的值的類型是函數(shù)
    copyIsArray,
    //
    clone,
    // 擴(kuò)展目標(biāo)對(duì)象瞎饲,可能不是對(duì)象,所以或空對(duì)象
    target = arguments[0] || {},
    // 定義i為1
    i = 1,
    // 定義實(shí)參個(gè)數(shù)length
    length = arguments.length;

    // 處理深拷貝情況
    if ( typeof target === "boolean" ) {
        deep = target;

        // Skip the boolean and the target
        // target目標(biāo)對(duì)象開始后移
        target = arguments[ i ] || {};
        i++;
    }

    // Handle case when target is a string or something (possible in deep copy)
    // target不等于對(duì)象炼绘,且target不是函數(shù)的情況下嗅战,強(qiáng)制將其賦值為空對(duì)象。
    if ( typeof target !== "object" && !isFunction( target ) ) {
        target = {};
    }

    // 只有一個(gè)參數(shù)時(shí)
    if(i === length){
        target = this;
        i--;
    }
    for(; i < length; i++){
        // 不是underfined 也不是null
        if((options = arguments[i]) !=  null){
            for(name in options){
                copy = options[name];
                // 防止死循環(huán)俺亮,continue 跳出當(dāng)前此次循環(huán)
                if ( name === "__proto__" || target === copy ) {
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 這里deep為true驮捍,并且需要拷貝的值有值,并且是純粹的對(duì)象
                // 或者需拷貝的值是數(shù)組
                if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
                    ( copyIsArray = Array.isArray( copy ) ) ) ) {

                    // 源目標(biāo)脚曾,需要往上面賦值的
                    src = target[ name ];

                    // Ensure proper type for the source value
                    // 拷貝的值东且,并且src不是數(shù)組,clone對(duì)象改為空數(shù)組本讥。
                    if ( copyIsArray && !Array.isArray( src ) ) {
                        clone = [];
                        // 拷貝的值不是數(shù)組相速,對(duì)象不是純粹的對(duì)象菩貌。
                    } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
                        // clone 賦值為空對(duì)象
                        clone = {};
                    } else {
                        // 否則 clone = src
                        clone = src;
                    }
                    // 把下一次循環(huán)時(shí),copyIsArray 需要重新賦值為false
                    copyIsArray = false;

                    // Never move original objects, clone them
                    // 遞歸調(diào)用自己
                    target[ name ] = jQuery.extend( deep, clone, copy );

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

    }
    // 最后返回目標(biāo)對(duì)象
    return target;
};

為了方便讀者調(diào)試,這段代碼同樣放在jQuery.extend深拷貝代碼實(shí)現(xiàn)codepen邦危,可在線運(yùn)行盟劫。

深拷貝衍生的函數(shù) isFunction

判斷參數(shù)是否是函數(shù)祷愉。

var isFunction = function isFunction( obj ) {

    // Support: Chrome <=57, Firefox <=52
    // In some browsers, typeof returns "function" for HTML <object> elements
    // (i.e., `typeof document.createElement( "object" ) === "function"`).
    // We don't want to classify *any* DOM node as a function.
    return typeof obj === "function" && typeof obj.nodeType !== "number";
};

深拷貝衍生的函數(shù) jQuery.isPlainObject

jQuery.isPlainObject(obj)
測(cè)試對(duì)象是否是純粹的對(duì)象(通過 "{}" 或者 "new Object" 創(chuàng)建的)莱找。

jQuery.isPlainObject({}) // true
jQuery.isPlainObject("test") // false
var getProto = Object.getPrototypeOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call( Object );

jQuery.extend( {
    isPlainObject: function( obj ) {
        var proto, Ctor;

        // Detect obvious negatives
        // Use toString instead of jQuery.type to catch host objects
        // !obj 為true或者 不為[object Object]
        // 直接返回false
        if ( !obj || toString.call( obj ) !== "[object Object]" ) {
            return false;
        }

        proto = getProto( obj );

        // Objects with no prototype (e.g., `Object.create( null )`) are plain
        // 原型不存在 比如 Object.create(null) 直接返回 true;
        if ( !proto ) {
            return true;
        }

        // Objects with prototype are plain iff they were constructed by a global Object function
        Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
        // 構(gòu)造器是函數(shù),并且 fnToString.call( Ctor )  === fnToString.call( Object );
        return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
    },
});

extend函數(shù)勤庐,也可以自己刪掉寫一寫示惊,算是jQuery中一個(gè)比較核心的函數(shù)了。而且用途廣泛愉镰,可以內(nèi)部使用也可以米罚,外部使用擴(kuò)展 插件等。

鏈?zhǔn)秸{(diào)用

jQuery能夠鏈?zhǔn)秸{(diào)用是因?yàn)橐恍┖瘮?shù)執(zhí)行結(jié)束后 return this丈探。
比如
jQuery 源碼中的addClass录择、removeClasstoggleClass碗降。

jQuery.fn.extend({
    addClass: function(){
        // ...
        return this;
    },
    removeClass: function(){
        // ...
        return this;
    },
    toggleClass: function(){
        // ...
        return this;
    },
});

jQuery.noConflict 很多js庫都會(huì)有的防沖突函數(shù)

jQuery.noConflict API

用法:

 <script>
    var $ = '我是其他的$隘竭,jQuery不要覆蓋我';
</script>
<script src="./jquery-3.4.1.js">
</script>
<script>
    $.noConflict();
    console.log($); // 我是其他的$,jQuery不要覆蓋我
</script>

jQuery.noConflict 源碼

var

    // Map over jQuery in case of overwrite
    _jQuery = window.jQuery,

    // Map over the $ in case of overwrite
    _$ = window.$;

jQuery.noConflict = function( deep ) {
    // 如果已經(jīng)存在$ === jQuery;
    // 把已存在的_$賦值給window.$;
    if ( window.$ === jQuery ) {
        window.$ = _$;
    }

    // 如果deep為 true, 并且已經(jīng)存在jQuery === jQuery;
    // 把已存在的_jQuery賦值給window.jQuery;
    if ( deep && window.jQuery === jQuery ) {
        window.jQuery = _jQuery;
    }

    // 最后返回jQuery
    return jQuery;
};

總結(jié)

全文主要通過淺析了jQuery整體結(jié)構(gòu)讼渊,自執(zhí)行匿名函數(shù)动看、無new構(gòu)造、支持多種規(guī)范(如commonjs爪幻、amd規(guī)范)菱皆、核心函數(shù)之extend须误、鏈?zhǔn)秸{(diào)用、jQuery.noConflict等方面仇轻。

重新梳理下文中學(xué)習(xí)的源碼結(jié)構(gòu)京痢。

// 源碼結(jié)構(gòu)
( function( global, factory )
    "use strict";
    if ( typeof module === "object" && typeof module.exports === "object" ) {
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
    var version = "3.4.1",

        // Define a local copy of jQuery
        jQuery = function( selector, context ) {
            return new jQuery.fn.init( selector, context );
        };

    jQuery.fn = jQuery.prototype = {
        jquery: version,
        constructor: jQuery,
        length: 0,
        // ...
    };

    jQuery.extend = jQuery.fn.extend = function() {};

    jQuery.extend( {
        // ...
        isPlainObject: function( obj ) {},
        // ...
    });

    init = jQuery.fn.init = function( selector, context, root ) {};

    init.prototype = jQuery.fn;

    if ( typeof define === "function" && define.amd ) {
        define( "jquery", [], function() {
            return jQuery;
        } );
    }
    jQuery.noConflict = function( deep ) {};

    if ( !noGlobal ) {
        window.jQuery = window.$ = jQuery;
    }

    return jQuery;
});

可以學(xué)習(xí)到jQuery巧妙的設(shè)計(jì)和架構(gòu),為自己所用拯田,打造屬于自己的js類庫历造。
相關(guān)代碼和資源放置在github blog中甩十,需要的讀者可以自取船庇。

下一篇文章可能是學(xué)習(xí)underscorejs的源碼整體架構(gòu)。

讀者發(fā)現(xiàn)有不妥或可改善之處侣监,歡迎評(píng)論指出鸭轮。另外覺得寫得不錯(cuò),可以點(diǎn)贊橄霉、評(píng)論窃爷、轉(zhuǎn)發(fā),也是對(duì)筆者的一種支持姓蜂。

筆者往期文章

面試官問:JS的繼承

面試官問:JS的this指向

面試官問:能否模擬實(shí)現(xiàn)JS的call和apply方法

面試官問:能否模擬實(shí)現(xiàn)JS的bind方法

面試官問:能否模擬實(shí)現(xiàn)JS的new操作符

前端使用puppeteer 爬蟲生成《React.js 小書》PDF并合并

擴(kuò)展閱讀

chokcoco: jQuery- v1.10.2 源碼解讀

chokcoco:【深入淺出jQuery】源碼淺析--整體架構(gòu)

songjz :jQuery 源碼系列(一)總體架構(gòu)

關(guān)于

作者:常以若川為名混跡于江湖按厘。前端路上 | PPT愛好者 | 所知甚少,唯善學(xué)钱慢。

個(gè)人博客 https://lxchuan12.github.io

github blog逮京,相關(guān)源碼和資源都放在這里,求個(gè)star_~

微信交流群

加微信 lxchuan12束莫,備注寫明來源懒棉。拉您進(jìn)微信群【前端視野交流群】。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末览绿,一起剝皮案震驚了整個(gè)濱河市策严,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饿敲,老刑警劉巖妻导,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異怀各,居然都是意外死亡栗竖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門渠啤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狐肢,“玉大人,你說我怎么就攤上這事沥曹》菝” “怎么了碟联?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)僵腺。 經(jīng)常有香客問我鲤孵,道長(zhǎng),這世上最難降的妖魔是什么辰如? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任普监,我火速辦了婚禮,結(jié)果婚禮上琉兜,老公的妹妹穿的比我還像新娘凯正。我一直安慰自己,他們只是感情好豌蟋,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布廊散。 她就那樣靜靜地躺著,像睡著了一般梧疲。 火紅的嫁衣襯著肌膚如雪允睹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天幌氮,我揣著相機(jī)與錄音缭受,去河邊找鬼。 笑死该互,一個(gè)胖子當(dāng)著我的面吹牛米者,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慢洋,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼塘雳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了普筹?” 一聲冷哼從身側(cè)響起败明,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎太防,沒想到半個(gè)月后妻顶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜒车,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年讳嘱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酿愧。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沥潭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嬉挡,到底是詐尸還是另有隱情钝鸽,我是刑警寧澤汇恤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站拔恰,受9級(jí)特大地震影響因谎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颜懊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一财岔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧河爹,春花似錦匠璧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲁僚。三九已至炊苫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冰沙,已是汗流浹背侨艾。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拓挥,地道東北人唠梨。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像侥啤,于是被迫代替她去往敵國(guó)和親当叭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 請(qǐng)參看我github中的wiki盖灸,不定期更新蚁鳖。https://github.com/ivonzhang/Front...
    zhangivon閱讀 7,105評(píng)論 2 19
  • PNG 有PNG8和truecolor PNG PNG8類似GIF顏色上限為256,文件小赁炎,支持alpha透明度醉箕,...
    hudaren閱讀 1,502評(píng)論 0 0
  • 1.幾種基本數(shù)據(jù)類型?復(fù)雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結(jié)構(gòu)? 基本數(shù)據(jù)類型:Undefined、Nul...
    極樂君閱讀 5,498評(píng)論 0 106
  • 時(shí)光如流水般悄悄逝去徙垫,卻不曾發(fā)出潺潺的聲響讥裤。 如今的我已然站在了2017年的尾巴上,不敢回憶姻报,因?yàn)闀r(shí)光太快...
    凱00凱閱讀 96評(píng)論 0 0
  • 如果知道逃避和拖延的心態(tài)的成因或許你會(huì)豁然開朗吴旋。 你開始的時(shí)候一定有著焦慮的情緒在损肛,焦慮是沒有目標(biāo)的恐慌不安的狀態(tài)...
    望舒Lucky閱讀 355評(píng)論 0 2