第一部分-基礎知識(2)-this迷雪、call限书、apply

在JavaScript編程中,this關鍵字總是讓初學者感到迷惑章咧,Function.prototype.callFunction.prototype.apply這兩個方法也有著廣泛的運用倦西。我們有必要在學習設計模式之前先理解這幾個概念。

  • <a href="#no1">2.1 this</a>
  • <a href="#no2">2.2 call 和 apply</a>

<a name="no1">2.1 this</a>

跟別的語言大相徑庭的是赁严,JavaScriptthis總是指向一個對象扰柠,而具體指向哪個對象是在運行時基于函數(shù)的執(zhí)行環(huán)境動態(tài)綁定的,而非函數(shù)被聲明時的環(huán)境疼约。

2.1.1 this的指向

除去不常用的witheval的情況耻矮,具體到實際應用中,this的指向大致可以分為以下4種忆谓。

  • 作為對象的方法調用裆装。
  • 作為普通函數(shù)調用。
  • 構造器調用倡缠。
  • Function.prototype.callFunction.prototype.apply調用哨免。

1. 作為對象的方法調用

當函數(shù)作為對象的方法被調用時,this指向該對象:

var obj = {
    a: 1,
    getA: function(){
        alert ( this === obj );    // 輸出:true
        alert ( this.a );    // 輸出: 1
    }
};

obj.getA();

2. 作為普通函數(shù)調用

當函數(shù)不作為對象的屬性被調用時昙沦,也就是我們常說的普通函數(shù)方式琢唾,此時的this總是指向全局對象。在瀏覽器的JavaScript里盾饮,這個全局對象是window對象采桃。

window.name = 'globalName';

var getName = function(){
    return this.name;
};

console.log( getName() );    // 輸出:globalName

或者:

window.name = 'globalName';

var myObject = {
    name: 'sven',
    getName: function(){
        return this.name;
    }
};

var getName = myObject.getName;
console.log( getName() );    // globalName

有時候我們會遇到一些困擾,比如在div節(jié)點的事件函數(shù)內部丘损,有一個局部的callback方法普办,callback被作為普通函數(shù)調用時,callback內部的this指向了window徘钥,但我們往往是想讓它指向該div節(jié)點衔蹲,見如下代碼:

<html>
    <body>
        <div id="div1">我是一個div</div>
    </body>
    <script>

    window.id = 'window';

    document.getElementById( 'div1' ).onclick = function(){
        alert ( this.id );        // 輸出:'div1'
        var callback = function(){
            alert ( this.id );        // 輸出:'window'
        }
        callback();
    };

    </script>
</html>

此時有一種簡單的解決方案,可以用一個變量保存div節(jié)點的引用:

document.getElementById( 'div1' ).onclick = function(){
    var that = this;    // 保存div的引用
    var callback = function(){
        alert ( that.id );    // 輸出:'div1'
    }
    callback();
};

在ECMAScript 5的strict模式下呈础,這種情況下的this已經(jīng)被規(guī)定為不會指向全局對象舆驶,而是undefined

function func(){
    "use strict"
    alert ( this );    // 輸出:undefined
}

func();

3. 構造器調用

JavaScript中沒有類橱健,但是可以從構造器中創(chuàng)建對象,同時也提供了new運算符沙廉,使得構造器看起來更像一個類拘荡。

除了宿主提供的一些內置函數(shù),大部分JavaScript函數(shù)都可以當作構造器使用撬陵。構造器的外表跟普通函數(shù)一模一樣珊皿,它們的區(qū)別在于被調用的方式。當用new運算符調用函數(shù)時袱结,該函數(shù)總會返回一個對象亮隙,通常情況下途凫,構造器里的this就指向返回的這個對象垢夹,見如下代碼:

var MyClass = function(){
    this.name = 'sven';
};

var obj = new MyClass();
alert ( obj.name );     // 輸出:sven

但用new調用構造器時,還要注意一個問題维费,如果構造器顯式地返回了一個object類型的對象果元,那么此次運算結果最終會返回這個對象,而不是我們之前期待的this

var MyClass = function(){
    this.name = 'sven';
    return {    // 顯式地返回一個對象
        name: 'anne'
    }
};

var obj = new MyClass();
alert ( obj.name );     // 輸出:anne

如果構造器不顯式地返回任何數(shù)據(jù)犀盟,或者是返回一個非對象類型的數(shù)據(jù)而晒,就不會造成上述問題:

var MyClass = function(){
    this.name = 'sven'
    return 'anne';    // 返回string類型
};

var obj = new MyClass();
alert ( obj.name );     // 輸出:sven

4. Function.prototype.call或Function.prototype.apply調用

跟普通的函數(shù)調用相比,用Function.prototype.callFunction.prototype.apply可以動態(tài)地改變傳入函數(shù)的this

var obj1 = {
    name: 'sven',
    getName: function() {
        return this.name;
    }
};

var obj2 = {
    name: 'anne'
};

console.log(obj1.getName()); // 輸出: sven
console.log(obj1.getName.call(obj2)); // 輸出:anne

callapply方法能很好地體現(xiàn)JavaScript的函數(shù)式語言特性阅畴,在JavaScript中倡怎,幾乎每一次編寫函數(shù)式語言風格的代碼,都離不開callapply贱枣。在JavaScript諸多版本的設計模式中监署,也用到了callapply

2.1.2 丟失的this

這是一個經(jīng)常遇到的問題纽哥,我們先看下面的代碼:

var obj = {
    myName: 'sven',
    getName: function() {
        return this.myName;
    }
};

console.log(obj.getName()); // 輸出:'sven'

var getName2 = obj.getName;
console.log(getName2()); // 輸出:undefined

當調用obj.getName時钠乏,getName方法是作為obj對象的屬性被調用的,根據(jù)2.1.1節(jié)提到的規(guī)律春塌,此時的this指向obj對象晓避,所以obj.getName()輸出'sven'

當用另外一個變量getName2來引用obj.getName只壳,并且調用getName2時俏拱,根據(jù)2.1.2節(jié)提到的規(guī)律,此時是普通函數(shù)調用方式吼句,this是指向全局window的彰触,所以程序的執(zhí)行結果是undefined

再看另一個例子命辖,document.getElementById這個方法名實在有點過長况毅,我們大概嘗試過用一個短的函數(shù)來代替它分蓖,如同prototype.js等一些框架所做過的事情:

var getId = function( id ){
    return document.getElementById( id );
};

getId( 'div1' );

我們也許思考過為什么不能用下面這種更簡單的方式:

var getId = document.getElementById;
getId( 'div1' );

現(xiàn)在不妨花1分鐘時間,讓這段代碼在瀏覽器中運行一次:

<html>
    <body>
        <div id="div1">我是一個div</div>
    </body>
    <script>

    var getId = document.getElementById;
    getId( 'div1' );

    </script>
</html>

在Chrome尔许、Firefox么鹤、IE10中執(zhí)行過后就會發(fā)現(xiàn),這段代碼拋出了一個異常味廊。這是因為許多引擎的document.getElementById方法的內部實現(xiàn)中需要用到this蒸甜。這個this本來被期望指向document,當getElementById方法作為document對象的屬性被調用時余佛,方法內部的this確實是指向document的柠新。

但當用getId來引用document.getElementById之后,再調用getId辉巡,此時就成了普通函數(shù)調用恨憎,函數(shù)內部的this指向了window,而不是原來的document郊楣。

我們可以嘗試利用applydocument當作this傳入getId函數(shù)憔恳,幫助“修正”this

document.getElementById = (function( func ){
    return function(){
        return func.apply( document, arguments );
    }
})( document.getElementById );

var getId = document.getElementById;
var div = getId( 'div1' );

alert (div.id);    // 輸出: div1

<a name="no2">2.2 call和apply</a>

Function.prototype.callFunction.prototype.apply都是非常常用的方法。它們的作用一模一樣净蚤,區(qū)別僅在于傳入?yún)?shù)形式的不同钥组。

2.2.1 call和apply的區(qū)別

apply接受兩個參數(shù),第一個參數(shù)指定了函數(shù)體內this對象的指向今瀑,第二個參數(shù)為一個帶下標的集合程梦,這個集合可以為數(shù)組,也可以為類數(shù)組橘荠,apply方法把這個集合中的元素作為參數(shù)傳遞給被調用的函數(shù):

var func = function( a, b, c ){
    console.log( [ a, b, c ] );    // 輸出 [ 1, 2, 3 ]
};

func.apply( null, [ 1, 2, 3 ] );

在這段代碼中屿附,參數(shù) 1、2砾医、3 被放在數(shù)組中一起傳入func函數(shù)拿撩,它們分別對應func參數(shù)列表中的a、b如蚜、c压恒。

call傳入的參數(shù)數(shù)量不固定,跟apply相同的是错邦,第一個參數(shù)也是代表函數(shù)體內的this指向探赫,從第二個參數(shù)開始往后,每個參數(shù)被依次傳入函數(shù):

var func = function( a, b, c ){
    console.log ( [ a, b, c ] );    // 輸出 [ 1, 2, 3 ]
};

func.call( null, 1, 2, 3 );

當調用一個函數(shù)時撬呢,JavaScript的解釋器并不會計較形參和實參在數(shù)量伦吠、類型以及順序上的區(qū)別,JavaScript的參數(shù)在內部就是用一個數(shù)組來表示的。從這個意義上說毛仪,applycall的使用率更高搁嗓,我們不必關心具體有多少參數(shù)被傳入函數(shù),只要用apply一股腦地推過去就可以了箱靴。

call是包裝在apply上面的一顆語法糖腺逛,如果我們明確地知道函數(shù)接受多少個參數(shù),而且想一目了然地表達形參和實參的對應關系衡怀,那么也可以用call來傳送參數(shù)棍矛。

當使用call或者apply的時候,如果我們傳入的第一個參數(shù)為null抛杨,函數(shù)體內的this會指向默認的宿主對象够委,在瀏覽器中則是window

var func = function( a, b, c ){
    alert ( this === window );    // 輸出true
};

func.apply( null, [ 1, 2, 3 ] );

但如果是在嚴格模式下,函數(shù)體內的this還是為null

var func = function( a, b, c ){
    "use strict";
    alert ( this === null );     // 輸出true
}

func.apply( null, [ 1, 2, 3 ] );

有時候我們使用call或者apply的目的不在于指定this指向怖现,而是另有用途茁帽,比如借用其他對象的方法。那么我們可以傳入null來代替某個具體的對象:

Math.max.apply( null, [ 1, 2, 5, 3, 4 ] )    // 輸出:5

2.2.2 call和apply的用途

前面說過真竖,能夠熟練使用callapply脐雪,是我們真正成為一名JavaScript程序員的重要一步厌小,本節(jié)我們將詳細介紹callapply在實際開發(fā)中的用途恢共。

1. 改變this指向

callapply最常見的用途是改變函數(shù)內部的this指向,我們來看個例子:

var obj1 = {
    name: 'sven'
};

var obj2 = {
    name: 'anne'
};

window.name = 'window';

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

getName();    // 輸出: window
getName.call( obj1 );    // 輸出: sven
getName.call( obj2 );    // 輸出: anne

當執(zhí)行getName.call( obj1 )這句代碼時璧亚,getName函數(shù)體內的this就指向obj1對象讨韭,所以此處的

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

實際上相當于:

var getName = function(){
    alert ( obj1.name );        // 輸出: sven
};

在實際開發(fā)中,經(jīng)常會遇到this指向被不經(jīng)意改變的場景癣蟋,比如有一個div節(jié)點透硝,div節(jié)點的onclick事件中的this本來是指向這個div的:

document.getElementById( 'div1' ).onclick = function(){
    alert( this.id );        // 輸出:div1
};

假如該事件函數(shù)中有一個內部函數(shù)func,在事件內部調用func函數(shù)時疯搅,func函數(shù)體內的this就指向了window濒生,而不是我們預期的div,見如下代碼:

document.getElementById( 'div1' ).onclick = function(){
    alert( this.id );            // 輸出:div1
    var func = function(){
        alert ( this.id );        // 輸出:undefined
    }
     func();
};

這時候我們用call來修正func函數(shù)內的this幔欧,使其依然指向div

document.getElementById( 'div1' ).onclick = function(){
    var func = function(){
        alert ( this.id );        // 輸出:div1
    }
    func.call( this );
};

使用call來修正this的場景罪治,我們并非第一次遇到,在上一小節(jié)關于this的學習中礁蔗,我們就曾經(jīng)修正過document.getElementById函數(shù)內部“丟失”的this觉义,代碼如下:

document.getElementById = (function( func ){
    return function(){
        return func.apply( document, arguments );
    }
})( document.getElementById );

var getId = document.getElementById;
var div = getId( 'div1' );
alert ( div.id );    // 輸出: div1

2. Function.prototype.bind

大部分高級瀏覽器都實現(xiàn)了內置的Function.prototype.bind,用來指定函數(shù)內部的this指向浴井,即使沒有原生的Function.prototype.bind實現(xiàn)晒骇,我們來模擬一個也不是難事,代碼如下:

Function.prototype.bind = function(context) {
    var self = this; // 保存原函數(shù)
    return function() { // 返回一個新的函數(shù)
        return self.apply(context, arguments); // 執(zhí)行新的函數(shù)的時候,會把之前傳入的context
        // 當作新函數(shù)體內的this
    }
};

var obj = {
    name: 'sven'
};

var func = function() {
    alert(this.name); // 輸出:sven
}.bind(obj);

func();`

我們通過Function.prototype.bind來“包裝”func函數(shù)洪囤,并且傳入一個對象context當作參數(shù)徒坡,這個context對象就是我們想修正的this對象。

Function.prototype.bind的內部實現(xiàn)中瘤缩,我們先把func函數(shù)的引用保存起來崭参,然后返回一個新的函數(shù)。當我們在將來執(zhí)行func函數(shù)時款咖,實際上先執(zhí)行的是這個剛剛返回的新函數(shù)何暮。在新函數(shù)內部,self.apply( context, arguments )這句代碼才是執(zhí)行原來的func函數(shù)铐殃,并且指定context對象為func函數(shù)體內的this海洼。

這是一個簡化版的Function.prototype.bind實現(xiàn),通常我們還會把它實現(xiàn)得稍微復雜一點富腊,使得可以往func函數(shù)中預先填入一些參數(shù):

Function.prototype.bind = function() {
    var self = this, // 保存原函數(shù)
        context = [].shift.call(arguments), // 需要綁定的this上下文
        args = [].slice.call(arguments); // 剩余的參數(shù)轉成數(shù)組
    return function() { // 返回一個新的函數(shù)
        return self.apply(context, [].concat.call(args, [].slice.call(arguments)));
        // 執(zhí)行新的函數(shù)的時候坏逢,會把之前傳入的context當作新函數(shù)體內的this
        // 并且組合兩次分別傳入的參數(shù),作為新函數(shù)的參數(shù)
    }
};

var obj = {
    name: 'sven'
};

var func = function(a, b, c, d) {
    alert(this.name); // 輸出:sven
    alert([a, b, c, d]) // 輸出:[ 1, 2, 3, 4 ]
}.bind(obj, 1, 2);

func(3, 4);`

3. 借用其他對象的方法

我們知道赘被,杜鵑既不會筑巢是整,也不會孵雛,而是把自己的蛋寄托給云雀等其他鳥類民假,讓它們代為孵化和養(yǎng)育浮入。同樣,在JavaScript中也存在類似的借用現(xiàn)象羊异。

借用方法的第一種場景是“借用構造函數(shù)”事秀,通過這種技術,可以實現(xiàn)一些類似繼承的效果:

var A = function(name) {
    this.name = name;
};

var B = function() {
    A.apply(this, arguments);
};

B.prototype.getName = function() {
    return this.name;
};

var b = new B('sven');
console.log(b.getName()); // 輸出: 'sven'

借用方法的第二種運用場景跟我們的關系更加密切野舶。

函數(shù)的參數(shù)列表arguments是一個類數(shù)組對象易迹,雖然它也有“下標”,但它并非真正的數(shù)組平道,所以也不能像數(shù)組一樣睹欲,進行排序操作或者往集合里添加一個新的元素。這種情況下一屋,我們常常會借用Array.prototype對象上的方法窘疮。比如想往arguments中添加一個新的元素,通常會借用Array.prototype.push

(function(){
    Array.prototype.push.call( arguments, 3 );
    console.log ( arguments );    // 輸出[1,2,3]
})( 1, 2 );

在操作arguments的時候陆淀,我們經(jīng)常非常頻繁地找Array.prototype對象借用方法考余。

想把arguments轉成真正的數(shù)組的時候,可以借用Array.prototype.slice方法轧苫;想截去arguments列表中的頭一個元素時尖坤,又可以借用Array.prototype.shift方法。那么這種機制的內部實現(xiàn)原理是什么呢摩瞎?我們不妨翻開V8的引擎源碼威沫,以Array.prototype.push為例,看看V8引擎中的具體實現(xiàn):

function ArrayPush() {
    var n = TO_UINT32( this.length );    // 被push的對象的length
    var m = %_ArgumentsLength();     // push的參數(shù)個數(shù)
    for (var i = 0; i < m; i++) {
        this[ i + n ] = %_Arguments( i );   // 復制元素     (1)
    }
    this.length = n + m;      // 修正length屬性的值    (2)
    return this.length;
};

通過這段代碼可以看到,Array.prototype.push實際上是一個屬性復制的過程,把參數(shù)按照下標依次添加到被push的對象上面,順便修改了這個對象的length屬性滚躯。至于被修改的對象是誰,到底是數(shù)組還是類數(shù)組對象嘿歌,這一點并不重要掸掏。

由此可以推斷,我們可以把“任意”對象傳入Array.prototype.push

var a = {};
Array.prototype.push.call( a, 'first' );
    
alert ( a.length );    // 輸出:1
alert ( a[ 0 ] );    // first

這段代碼在絕大部分瀏覽器里都能順利執(zhí)行宙帝,但由于引擎的內部實現(xiàn)存在差異丧凤,如果在低版本的IE瀏覽器中執(zhí)行,必須顯式地給對象a設置length屬性:

var a = {
    length: 0
};

前面我們之所以把“任意”兩字加了雙引號步脓,是因為可以借用Array.prototype.push方法的對象還要滿足以下兩個條件愿待,從ArrayPush函數(shù)的(1)處和(2)處也可以猜到,這個對象至少還要滿足:

  • 對象本身要可以存取屬性靴患;
  • 對象的length屬性可讀寫仍侥。

對于第一個條件,對象本身存取屬性并沒有問題鸳君,但如果借用Array.prototype.push方法的不是一個object類型的數(shù)據(jù)农渊,而是一個number類型的數(shù)據(jù)呢? 我們無法在number身上存取其他數(shù)據(jù),那么從下面的測試代碼可以發(fā)現(xiàn)相嵌,一個number類型的數(shù)據(jù)不可能借用到Array.prototype.push方法:

var a = 1;
Array.prototype.push.call( a, 'first' );
alert ( a.length );      // 輸出:undefined
alert ( a[ 0 ] );    // 輸出:undefined

對于第二個條件腿时,函數(shù)的length屬性就是一個只讀的屬性况脆,表示形參的個數(shù)饭宾,我們嘗試把一個函數(shù)當作this傳入Array.prototype.push

var func = function(){};
Array.prototype.push.call( func, 'first' );
    
alert ( func.length );
// 報錯:cannot assign to read only property ‘length’ of function(){}

資料來源

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市格了,隨后出現(xiàn)的幾起案子看铆,更是在濱河造成了極大的恐慌,老刑警劉巖盛末,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弹惦,死亡現(xiàn)場離奇詭異,居然都是意外死亡悄但,警方通過查閱死者的電腦和手機棠隐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檐嚣,“玉大人助泽,你說我怎么就攤上這事。” “怎么了嗡贺?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵隐解,是天一觀的道長。 經(jīng)常有香客問我诫睬,道長煞茫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任摄凡,我火速辦了婚禮续徽,結果婚禮上,老公的妹妹穿的比我還像新娘亲澡。我一直安慰自己炸宵,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布谷扣。 她就那樣靜靜地躺著土全,像睡著了一般。 火紅的嫁衣襯著肌膚如雪会涎。 梳的紋絲不亂的頭發(fā)上裹匙,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音末秃,去河邊找鬼概页。 笑死,一個胖子當著我的面吹牛练慕,可吹牛的內容都是我干的惰匙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼铃将,長吁一口氣:“原來是場噩夢啊……” “哼项鬼!你這毒婦竟也來了?” 一聲冷哼從身側響起劲阎,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤绘盟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后悯仙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龄毡,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年锡垄,在試婚紗的時候發(fā)現(xiàn)自己被綠了沦零。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡货岭,死狀恐怖路操,靈堂內的尸體忽然破棺而出序攘,到底是詐尸還是另有隱情,我是刑警寧澤寻拂,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布程奠,位于F島的核電站,受9級特大地震影響祭钉,放射性物質發(fā)生泄漏瞄沙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一慌核、第九天 我趴在偏房一處隱蔽的房頂上張望距境。 院中可真熱鬧,春花似錦垮卓、人聲如沸垫桂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诬滩。三九已至,卻和暖如春灭将,著一層夾襖步出監(jiān)牢的瞬間疼鸟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工庙曙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留空镜,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓捌朴,卻偏偏與公主長得像吴攒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子砂蔽,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容

  • 工廠模式類似于現(xiàn)實生活中的工廠可以產生大量相似的商品洼怔,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式察皇。簡單...
    舟漁行舟閱讀 7,718評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象茴厉,但只有一個實例,加載時并不主動創(chuàng)建什荣,需要時才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,056評論 1 10
  • 本文源于本人關于《JavaScript設計模式與開發(fā)實踐》(曾探著)的閱讀總結。想詳細了解具體內容建議閱讀該書蜕依。 ...
    yozosann閱讀 259評論 0 1
  • 女人的幸福感是來自內心的,不是依靠外表光鮮亮麗友瘤,不是嫁給一個疼愛自己高富帥翠肘,不是把自己捧到高高在上位置,高貴地昂著...
    P尐c閱讀 2,252評論 0 0
  • 今天辫秧,iphone x發(fā)布束倍,這個吸引了無數(shù)人眼球的發(fā)布會,被網(wǎng)友評論最多的就是人臉識別解鎖功能盟戏,男人們說不敢睡覺了...
    星光下的咖啡館閱讀 189評論 3 1