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

資訊專欄INFORMATION COLUMN

JavaScript基礎(chǔ)系列--打敗this

BoYang / 957人閱讀

摘要:然后繼續(xù)往后看,后面你會(huì)得到答案的想馬上驗(yàn)證可以拖到最后到底是什么的確定是在的創(chuàng)建階段,而的創(chuàng)建發(fā)生在瀏覽器第一次加載的時(shí)候或者調(diào)用函數(shù)的時(shí)候具體可參見(jiàn)之前寫(xiě)過(guò)的一篇文章基礎(chǔ)系列執(zhí)行環(huán)境與作用域鏈。

最近重溫了一遍《你不知道的JavaScript--上卷》,其中第二部分關(guān)于this的講解讓我收獲頗多,所以寫(xiě)一篇讀書(shū)筆記記錄總結(jié)一番。

消除誤解--this指向自身

由于this的英文釋義,許多人都會(huì)將其理解成指向函數(shù)自身(JavaScript 中的所有函數(shù)都
是對(duì)象),但是實(shí)際上this并不像我們所想的那樣指向函數(shù)自身,我們可以通過(guò)下面的栗子驗(yàn)證一下~

function foo(num) {
    console.log( "foo: " + num );
    // 記錄foo 被調(diào)用的次數(shù)
    this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
    if (i > 5) {
        foo( i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被調(diào)用了多少次?
console.log( foo.count ); // 0 -- WTF?

上述栗子的本意是想記錄foo被調(diào)用的次數(shù)

假設(shè)this指向函數(shù)本身,那么this.countfoo.count應(yīng)該是foo函數(shù)對(duì)象的同一個(gè)屬性,那么最終得到的foo.count應(yīng)該是4;

然而實(shí)際上,最終得到的foo.count0,也就是說(shuō)foo.count初始化之后就沒(méi)有再改變過(guò)了,所以this.countfoo.count是相互獨(dú)立的,互不影響;所以結(jié)論是:this并不是指向函數(shù)本身

那么這個(gè)里面的this到底是指向什么呢?你可以思考一下,寫(xiě)下你的答案。然后繼續(xù)往后看,后面你會(huì)得到答案的~~想馬上驗(yàn)證可以拖到最后...

this到底是什么

this的確定是在Execution Context的創(chuàng)建階段,而Execution Context的創(chuàng)建發(fā)生在瀏覽器第一次加載script的時(shí)候或者調(diào)用函數(shù)的時(shí)候----具體可參見(jiàn)之前寫(xiě)過(guò)的一篇文章JavaScript基礎(chǔ)系列---執(zhí)行環(huán)境與作用域鏈。

所以this 是在運(yùn)行時(shí)進(jìn)行綁定的,并不是在編寫(xiě)時(shí)綁定,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件,this的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式;this的指向并沒(méi)有一個(gè)固定的說(shuō)法,需要分情況而論。

要想明確this指向什么,需要通過(guò)尋找函數(shù)的調(diào)用位置來(lái)判斷函數(shù)在執(zhí)行過(guò)程中會(huì)如何綁定this,從而確定this的指向。

尋找調(diào)用位置

尋找調(diào)用位置就是尋找“函數(shù)被調(diào)用的位置”,但是做起來(lái)并沒(méi)有這么簡(jiǎn)單,因?yàn)槟承┚幊棠J娇赡軙?huì)隱藏真正的調(diào)用位置,這種時(shí)候很容易出錯(cuò)。

最重要的是要分析調(diào)用棧(就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)),我們關(guān)心的調(diào)用位置就在當(dāng)前正在執(zhí)行的函數(shù)的前一個(gè)調(diào)用中,下面用栗子來(lái)幫助理解:

function baz() {
    debugger
    // 當(dāng)前調(diào)用棧是:baz
    // 因此,當(dāng)前調(diào)用位置是全局作用域
    console.log( "baz" );
    bar(); // <-- bar 的調(diào)用位置
}
function bar() {
    debugger
    // 當(dāng)前調(diào)用棧是baz -> bar
    // 因此,當(dāng)前調(diào)用位置在baz 中
    console.log( "bar" );
    foo(); // <-- foo 的調(diào)用位置
}
function foo() {
    debugger
    // 當(dāng)前調(diào)用棧是baz -> bar -> foo
    // 因此,當(dāng)前調(diào)用位置在bar 中
    console.log( "foo" );
}
baz(); // <-- baz 的調(diào)用位置

如果條件允許,可以使用開(kāi)發(fā)者工具進(jìn)行觀察,將會(huì)更加直觀。

baz函數(shù)是在全局作用域中調(diào)用的,baz函數(shù)的調(diào)用棧為baz,所以baz函數(shù)的調(diào)用位置是全局作用域

bar函數(shù)是在baz函數(shù)中調(diào)用的,bar函數(shù)的調(diào)用棧為baz -> bar,當(dāng)正在執(zhí)行的是bar函數(shù)時(shí),其前一個(gè)調(diào)用是baz,所以bar函數(shù)的調(diào)用位置是baz函數(shù)中的bar();位置

foo函數(shù)是在bar函數(shù)中調(diào)用的,foo函數(shù)的調(diào)用棧為baz -> bar -> foo,當(dāng)正在執(zhí)行的是foo函數(shù)時(shí),其前一個(gè)調(diào)用是bar,所以foo函數(shù)的調(diào)用位置是bar函數(shù)中的foo();位置

this的綁定規(guī)則

找到調(diào)用位置后該如何確定this的指向呢?這是有規(guī)則可循的,下面我們就來(lái)看看這四條規(guī)則,了解了規(guī)則后,確定this的步驟就變成:找到調(diào)用位置,然后判斷需要應(yīng)用四條規(guī)則中的哪一條,根據(jù)規(guī)則得出this的指向。

默認(rèn)綁定

首先要介紹的是最常用的函數(shù)調(diào)用類型:獨(dú)立函數(shù)調(diào)用。這種調(diào)用是直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,它的調(diào)用位置是全局作用域,于是this指向全局對(duì)象??梢园堰@條規(guī)則看作是無(wú)法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則。

我們看下面的代碼:

function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2

首先我們要知道一件事,聲明在全局作用域中的變量(比如上述代碼中的var a = 2)就是全局對(duì)象的一個(gè)同名屬性。它們本質(zhì)上就是同一個(gè)東西,并不是通過(guò)復(fù)制得到的,就像一個(gè)硬幣的兩面一樣。

在代碼中,foo()是在全局作用域中直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,所以foo函數(shù)調(diào)用時(shí)應(yīng)用this的默認(rèn)綁定,因此this指向全局對(duì)象;既然this指向全局對(duì)象,那么this.a便是全局變量a,所以打印的結(jié)果為2。

注意:嚴(yán)格模式下,禁止this關(guān)鍵字指向全局對(duì)象,此時(shí)this會(huì)綁定到undefined;所以當(dāng)函數(shù)定義在嚴(yán)格模式下或函數(shù)內(nèi)的代碼運(yùn)行在嚴(yán)格模式下時(shí),其中的this綁定的是undefined;特別注意如果僅僅是函數(shù)的調(diào)用語(yǔ)句運(yùn)行在嚴(yán)格模式下,那么不受影響,該函數(shù)內(nèi)的this仍然綁定到全局對(duì)象

"use strict";
function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // TypeError: Cannot read property "a" of undefined

foo函數(shù)定義在嚴(yán)格模式下,所以this綁定到了`undefined

function foo() {
    "use strict";
    console.log( this.a );
}
var a = 2;
foo(); // TypeError: Cannot read property "a" of undefined

foo函數(shù)內(nèi)部為嚴(yán)格模式,所以this綁定到了undefined

function foo() {
    console.log( this.a );
}
"use strict";
var a = 2;
foo(); // 2

嚴(yán)格模式的標(biāo)識(shí)在foo函數(shù)的定義之后,foo函數(shù)未定義在嚴(yán)格模式下,僅僅是foo函數(shù)的調(diào)用語(yǔ)句foo()運(yùn)行在嚴(yán)格模式下,所以this仍然可以綁定到全局對(duì)象

function foo() {
    console.log( this.a );
}
var a = 2;
(function(){
   "use strict";
   foo(); // 2
})()

僅僅是foo函數(shù)的調(diào)用語(yǔ)句foo()運(yùn)行在嚴(yán)格模式下,所以this仍然可以綁定到全局對(duì)象

溫馨提示:通常來(lái)說(shuō)你不應(yīng)該在代碼中混合使用嚴(yán)格模式和n非嚴(yán)格模式。整個(gè)程序要么嚴(yán)格要么非嚴(yán)格。然而,有時(shí)候你可能會(huì)用到第三方庫(kù),其嚴(yán)格程度和你的代碼有所不同,因此一定要注意這類兼容性細(xì)節(jié)。

隱式綁定

第二條規(guī)則是考慮函數(shù)調(diào)用位置是否有上下文對(duì)象,或者說(shuō)該函數(shù)是否被某個(gè)對(duì)象“擁有”或者“包含”(僅僅是這么理解一下),如果函數(shù)調(diào)用位置有上下文對(duì)象,那么隱式綁定規(guī)則會(huì)把該函數(shù)中的this綁定到這個(gè)上下文對(duì)象

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 2

首先需要注意的是foo函數(shù)的聲明方式,及其之后是如何被當(dāng)作引用屬性添加到obj中的。但是無(wú)論是直接在obj中定義還是先定義再添加為引用屬性,這個(gè)函數(shù)嚴(yán)格來(lái)說(shuō)都不屬于obj對(duì)象;然而,調(diào)用位置會(huì)使用obj上下文來(lái)引用函數(shù),因此你可以說(shuō)函數(shù)被調(diào)用時(shí)obj 對(duì)象“擁有”或者“包含”它。

當(dāng)函數(shù)調(diào)用位置有上下文對(duì)象時(shí),隱式綁定規(guī)則會(huì)把該函數(shù)中的this綁定到這個(gè)上下文對(duì)象。所以上面的例子中,調(diào)用foo()時(shí)this被綁定到obj,那么this.aobj.a 是一樣的,打印的結(jié)果便是2。

對(duì)象屬性引用鏈中只有最頂層或者說(shuō)最后一層會(huì)影響調(diào)用位置,看個(gè)例子就很容易理解了:

function foo() {
    console.log( this.a );
}
var obj2 = {
    a: 42,
    foo: foo
};
var obj1 = {
    a: 2,
    obj2: obj2
};
obj1.obj2.foo(); // 42

上述對(duì)象引用鏈為 :obj1->obj2,只有最后一層會(huì)影響調(diào)用位置,也就是只有obj2會(huì)影響調(diào)用位置,所以foo函數(shù)的調(diào)用位置的上下文對(duì)象為obj2,this綁定到obj2

注意:有些情況下會(huì)出現(xiàn)隱式丟失,意思就是被隱式綁定的函數(shù)丟失綁定對(duì)象,也就是說(shuō)它會(huì)應(yīng)用默認(rèn)綁定,從而把this綁定到全局對(duì)象或者undefined上(取決于是否是嚴(yán)格模式)

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var bar = obj.foo; // 函數(shù)別名!
var a = "oops, global"; // a 是全局對(duì)象的屬性
bar(); // "oops, global"

上面例子中,雖然barobj.foo的一個(gè)引用,但是實(shí)際上,它引用的是foo 函數(shù)本身,相當(dāng)于var bar = foo;。因此此時(shí)的bar()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,所以會(huì)應(yīng)用了默認(rèn)綁定,綁定到全局對(duì)象

function foo() {
    console.log( this.a );
}
function doFoo(fn) {
    // fn 其實(shí)引用的是foo
    fn(); // <-- 調(diào)用位置!
}
var obj = {
    a: 2,
    foo: foo
};
var a = "oops, global"; // a 是全局對(duì)象的屬性
doFoo( obj.foo ); // "oops, global"
setTimeout( obj.foo, 100 ); // "oops, global"

參數(shù)傳遞其實(shí)就是一種隱式賦值,因此我們傳入函數(shù)時(shí)也會(huì)被隱式賦值,所以將obj.foo傳遞給doFoo函數(shù)的參數(shù)fn,相當(dāng)于fn = foo,所以doFoo函數(shù)內(nèi)部的fn()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,所以會(huì)應(yīng)用了默認(rèn)綁定,綁定到全局對(duì)象

內(nèi)置函數(shù)setTimeout的結(jié)果也是一樣的?;卣{(diào)函數(shù)丟失this綁定是非常常見(jiàn)的,之后我們會(huì)介紹如何通過(guò)固定this來(lái)修復(fù)這個(gè)問(wèn)題。

顯式綁定

就像我們剛才看到的那樣,在分析隱式綁定時(shí),我們必須在一個(gè)對(duì)象內(nèi)部包含一個(gè)指向函數(shù)的屬性,并通過(guò)這個(gè)屬性間接引用函數(shù),從而把this 間接(隱式)綁定到這個(gè)對(duì)象上。那么如果我們不想在對(duì)象內(nèi)部包含函數(shù)引用,而想在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù),該怎么做呢?

可以使用函數(shù)的call(..)apply(..) 方法。嚴(yán)格來(lái)說(shuō),JavaScript 的宿主環(huán)境有時(shí)會(huì)提供一些非常特殊的函數(shù),它們并沒(méi)有這兩個(gè)方法。但是這樣的函數(shù)非常罕見(jiàn),JavaScript 提供的絕大多數(shù)函數(shù)以及你自己創(chuàng)建的所有函數(shù)都可以使用call(..)apply(..) 方法。

這兩個(gè)方法是如何工作的呢?它們的第一個(gè)參數(shù)是一個(gè)對(duì)象,它們會(huì)把這個(gè)對(duì)象綁定到this,接著在調(diào)用函數(shù)時(shí)指定這個(gè)this;因?yàn)槟憧梢灾苯又付?b>this的綁定對(duì)象,因此我們稱之為顯式綁定。(如果沒(méi)有傳遞第一個(gè)參數(shù),也就是沒(méi)有直接指定this,那么this將綁定到全局對(duì)象或者undefined上)

function foo() {
    console.log( this.a );
}
var obj = {
    a:2
};
foo.call( obj ); // 2

通過(guò)foo.call(..),我們可以在調(diào)用foo時(shí)強(qiáng)制把它的this綁定到obj上。

如果你傳入了一個(gè)原始值(字符串類型、布爾類型或者數(shù)字類型)來(lái)當(dāng)作this的綁定對(duì)象,這個(gè)原始值會(huì)被轉(zhuǎn)換成它的對(duì)象形式(也就是new String(..)、new Boolean(..) 或者new Number(..))。這通常被稱為“裝箱”。但是在嚴(yán)格模式下this不會(huì)被強(qiáng)制轉(zhuǎn)換為一個(gè)對(duì)象,也就是說(shuō)傳入原始值來(lái)當(dāng)做this的綁定對(duì)象,那么它不會(huì)轉(zhuǎn)換為對(duì)象形式

function foo() {
    console.log( this );
}
foo.call( "cc" ); // String?{"cc"}
foo.call( 6 ); // Number?{6}
foo.call( true ); // Boolean?{true}

"use strict"
function foo() {
    console.log( this );
}
foo.call( "cc" ); // cc
foo.call( 6 ); // 6
foo.call( true ); // true

可惜,顯式綁定仍然無(wú)法解決我們之前提出的丟失綁定問(wèn)題

function foo() {
    console.log( this.a );
}
var obj = {
    a:6
};
var bar = function() {
    foo();
};
bar.call(obj); // undefined

可以看出,雖然bar通過(guò)call(..)方法顯示綁定到了obj,但是其內(nèi)部的foo()仍然是一個(gè)不帶任何修飾的函數(shù)調(diào)用,this綁定到全局對(duì)象

硬綁定

顯式綁定的一個(gè)變種可以解決這個(gè)丟失綁定問(wèn)題,我們稱這個(gè)變種為硬綁定,下面來(lái)看看它是如何解決的:

function foo() {
    console.log( this.a );
}
var obj = {
    a:6
};
var bar = function() {
    foo.call( obj );
};
bar(); // 6
setTimeout( bar, 100 ); // 6
// 硬綁定的bar 不可能再修改它的this
bar.call( window ); // 6

我們創(chuàng)建了函數(shù)bar,并在它的內(nèi)部手動(dòng)調(diào)用了foo.call(obj),因此強(qiáng)制把foothis 綁定到了obj,無(wú)論之后如何調(diào)用函數(shù)barthis始終綁定到obj。

一般來(lái)說(shuō),可以創(chuàng)建一個(gè)可重復(fù)使用的硬綁定輔助函數(shù):

function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}
// 簡(jiǎn)單的輔助綁定函數(shù)
function bind(fn, obj) {
    return function() {
        return fn.apply( obj, arguments );
    };
}
var obj = {
    a:2
};
var bar = bind( foo, obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5

通過(guò)bind函數(shù)就可以將foo函數(shù)的this始終綁定為obj,由于硬綁定是一種非常常用的模式,所以在ES5中提供了內(nèi)置的方法Function.prototype.bind,將上面的例子改成該方法的形式,代碼如下:

function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}
var obj = {
    a:2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5

bind(..)會(huì)返回一個(gè)硬編碼的新函數(shù),調(diào)用這個(gè)新函數(shù)時(shí)會(huì)把原始函數(shù)的this綁定到傳入bind(..)的參數(shù)上并調(diào)用原始函數(shù),所以foo.bind( obj )會(huì)返回一個(gè)新函數(shù),然后被賦值給bar,調(diào)用bar時(shí)會(huì)把foo中的this綁定到obj,并且調(diào)用foo函數(shù)。

API調(diào)用的“上下文”

除了上面說(shuō)的硬綁定可以強(qiáng)制給this一個(gè)綁定,第三方庫(kù)的許多函數(shù),以及JavaScript語(yǔ)言和宿主環(huán)境中許多新的內(nèi)置函數(shù),都提供了一個(gè)可選的參數(shù),通常被稱為“上下文”(context),其作用和bind(..) 一樣,確保你的回調(diào)函數(shù)使用指定的this。

比如說(shuō):

function foo(el) {
    console.log( el, this.id );
}
var obj = {
    id: "awesome"
};
// 調(diào)用foo(..) 時(shí)把this綁定到obj
[1, 2, 3].forEach( foo, obj );
// 1 "awesome"
// 2 "awesome"
// 3 "awesome"

array.forEach(function(currentValue, index, arr), thisValue)方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù),它的第二個(gè)參數(shù)thisValue就可以指定回調(diào)函數(shù)中的this(如果這個(gè)參數(shù)為空,那么this將綁定到全局對(duì)象或者undefined上);forEach內(nèi)部實(shí)際上就是通過(guò)call(..) 或者apply(..) 實(shí)現(xiàn)了顯式綁定

其他函數(shù)還有array.map,array.filterarray.every,array.some

new綁定

最后一條this的綁定規(guī)則,在講解它之前我們首先需要澄清一個(gè)非常常見(jiàn)的關(guān)于JavaScript 中函數(shù)和對(duì)象的誤解。

在傳統(tǒng)的面向類的語(yǔ)言中,“構(gòu)造函數(shù)”是類中的一些特殊方法,使用new初始化類時(shí)會(huì)調(diào)用類中的構(gòu)造函數(shù)。通常的形式是這樣的:

    something = new MyClass(..);

JavaScript也有一個(gè)new操作符,使用方法看起來(lái)也和那些面向類的語(yǔ)言一樣,但是,JavaScriptnew的機(jī)制實(shí)際上和面向類的語(yǔ)言完全不同。

首先我們重新定義一下JavaScript中的“構(gòu)造函數(shù)”:在JavaScript中,構(gòu)造函數(shù)只是一些使用new操作符時(shí)被調(diào)用的函數(shù),它們并不會(huì)屬于某個(gè)類,也不會(huì)實(shí)例化一個(gè)類。實(shí)際上,它們甚至都不能說(shuō)是一種特殊的函數(shù)類型,它們只是被new操作符調(diào)用的普通函數(shù)而已。(ES6中的Class只是語(yǔ)法糖而已)

自定義函數(shù)和內(nèi)置對(duì)象函數(shù)(比如Number(..))都可以用new來(lái)調(diào)用,這種函數(shù)調(diào)用被稱為構(gòu)造函數(shù)調(diào)用。這里有一個(gè)重要但是非常細(xì)微的區(qū)別:實(shí)際上并不存在所謂的“構(gòu)造函數(shù)”,只有對(duì)于函數(shù)的“構(gòu)造調(diào)用”。

使用new來(lái)調(diào)用函數(shù),或者說(shuō)發(fā)生構(gòu)造函數(shù)調(diào)用時(shí),會(huì)自動(dòng)執(zhí)行下面的操作:

創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)全新的對(duì)象

這個(gè)新對(duì)象會(huì)被執(zhí)行[[Prototype]]鏈接([[Prototype]]指向構(gòu)造函數(shù)的原型對(duì)象

這個(gè)新對(duì)象會(huì)綁定到該構(gòu)造函數(shù)中的this

執(zhí)行構(gòu)造函數(shù)中的代碼

如果該構(gòu)造函數(shù)沒(méi)有返回其他對(duì)象,那么會(huì)自動(dòng)返回這個(gè)新對(duì)象

上述過(guò)程中的this綁定就被稱為new綁定,下面看個(gè)簡(jiǎn)單的例子:

function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2

使用new來(lái)調(diào)用foo(..)時(shí),我們會(huì)構(gòu)造一個(gè)新對(duì)象(賦值給了變量bar)并把它綁定到foo函數(shù)中的this上,foo函數(shù)中的this綁定的就是對(duì)象bar

綁定規(guī)則的優(yōu)先級(jí)

在了解了四種綁定規(guī)則后,我們需要了解一下他們之間的優(yōu)先級(jí),因?yàn)橛袝r(shí)候會(huì)出現(xiàn)符合多種規(guī)則的情況。

毫無(wú)疑問(wèn),默認(rèn)綁定的優(yōu)先級(jí)是四條規(guī)則中最低的,所以我們可以先不考慮它。

隱式綁定和顯式綁定哪個(gè)優(yōu)先級(jí)更高?我們來(lái)測(cè)試一下:

function foo() {
    console.log( this.a );
}
var obj1 = {
    a: 2,
    foo: foo
};
var obj2 = {
    a: 3,
    foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2

可以明顯看出,顯示綁定優(yōu)先于隱式綁定,也就是說(shuō)在判斷時(shí)應(yīng)當(dāng)先考慮是否可以應(yīng)用顯式綁定

那么隱式綁定和new綁定哪個(gè)優(yōu)先級(jí)更高?我們也來(lái)測(cè)試一下:

function foo(something) {
    this.a = something;
}
var obj1 = {
    foo: foo
};
var obj2 = {};

obj1.foo( 2 );//隱式綁定
console.log( obj1.a ); // 2

var bar = new obj1.foo( 4 );//new綁定,相當(dāng)于vra bar = new foo(4);
console.log( obj1.a ); // 2
console.log( bar.a ); // 4

可以看到new綁定比隱式綁定優(yōu)先級(jí)高,那么現(xiàn)在還需要知道new綁定和顯式綁定誰(shuí)的優(yōu)先級(jí)更高,由于newcall/apply 無(wú)法一起使用,因此無(wú)法通過(guò)new foo.call(obj1) 來(lái)直接進(jìn)行測(cè)試,而硬綁定是顯示綁定的一種,所以我們使用硬綁定來(lái)測(cè)試它倆的優(yōu)先級(jí):

在看代碼之前先回憶一下硬綁定是如何工作的。Function.prototype.bind(..) 會(huì)創(chuàng)建一個(gè)新的包裝函數(shù),這個(gè)函數(shù)會(huì)忽略它當(dāng)前的this綁定(無(wú)論綁定的對(duì)象是什么),并把我們提供的對(duì)象綁定到this上。

這樣看起來(lái)硬綁定(也是顯式綁定的一種)似乎比new 綁定的優(yōu)先級(jí)更高,應(yīng)該無(wú)法使用new來(lái)控制this綁定,那實(shí)際上是如何的呢?來(lái)讓代碼揭曉答案:

function foo(something) {
    this.a = something;
}
var obj1 = {};

var bar = foo.bind( obj1 );
bar(2);
console.log( obj1.a ); // 2

var baz = new bar(3);
console.log( obj1.a ); // 2
console.log( baz.a ); // 3

bar函數(shù)中的的this被硬綁定到obj1上,但是new bar(3)并沒(méi)有像我們前面預(yù)計(jì)的那樣把obj1.a修改為3,這說(shuō)明使用new來(lái)調(diào)用bar()的時(shí)候,bar函數(shù)中的this綁定的不是obj1(否則obj1.a應(yīng)該被修改為3),所以使用new仍然可以控制this綁定,實(shí)際上此時(shí)bar函數(shù)中的this綁定的是一個(gè)新對(duì)象,這個(gè)新對(duì)象最后賦值給了baz,所以baz.a的值為3。

為什么與預(yù)想的不同?因?yàn)?b>ES5 中內(nèi)置的Function.prototype.bind(..)方法的內(nèi)部會(huì)進(jìn)行判斷,會(huì)判斷硬綁定函數(shù)是否是被new調(diào)用,如果是的話就會(huì)使用新創(chuàng)建的this替換硬綁定的this。

所以new綁定的優(yōu)先級(jí)高于顯示綁定。

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])方法,可以傳入?yún)?shù)序列,當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的函數(shù),所以bind(..)的功能之一就是可以把除了第一個(gè)參數(shù)(第一個(gè)參數(shù)用于綁定this)之外的其他參數(shù)都傳給下層的函數(shù)(這種技術(shù)稱為“部分應(yīng)用”,是“柯里化”的一種)。

正是由于bind(...)的這一功能,如果我們?cè)?b>new中使用硬綁定函數(shù),那么就可以預(yù)先設(shè)置函數(shù)的一些參數(shù),這樣在使用new進(jìn)行初始化時(shí)就可以只傳入其余的參數(shù),這也就是為什么有些時(shí)候會(huì)在new中使用硬綁定函數(shù)的原因,看個(gè)例子:

function foo(p1,p2) {
    this.val = p1 + p2;
}
// 之所以使用null 是因?yàn)樵诒纠形覀儾⒉魂P(guān)心硬綁定的this是什么
// 反正使用new的時(shí)候this會(huì)被修改
var bar = foo.bind( null, "p1" );//傳入預(yù)先設(shè)置的參數(shù)p1
var baz = new bar( "p2" );//只需傳入剩余的參數(shù)p2
baz.val; // p1p2
優(yōu)先級(jí)總結(jié)

綜上所述,優(yōu)先級(jí)如下:
new綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定

那么我們?cè)诖_定this的時(shí)候就可以根據(jù)下面的步驟來(lái):

函數(shù)是否使用new調(diào)用(new綁定)?如果是的話this綁定的是新創(chuàng)建的對(duì)象。

var bar = new foo()

函數(shù)是否通過(guò)call、apply(顯式綁定)或者硬綁定bind調(diào)用?如果是的話,this綁定的是指定的對(duì)象。

var bar = foo.call(obj2)

函數(shù)是否在某個(gè)上下文對(duì)象中調(diào)用(隱式綁定)?如果是的話,this綁定的是那個(gè)上下文對(duì)象。

var bar = obj1.foo()

如果都不是的話,使用默認(rèn)綁定。如果在嚴(yán)格模式下,就綁定到undefined,否則綁定到全局對(duì)象。

var bar = foo()

對(duì)于正常的函數(shù)調(diào)用來(lái)說(shuō),理解了這些知識(shí)就可以明白this的綁定原理了,不過(guò)……凡事總有例外?。?!

綁定的特殊情況

在某些場(chǎng)景下this的綁定行為會(huì)出乎意料,你認(rèn)為應(yīng)當(dāng)應(yīng)用其他綁定規(guī)則時(shí),實(shí)際上應(yīng)用的可能是默認(rèn)綁定規(guī)則。

被忽略的this

如果你把null或者undefined作為this的綁定對(duì)象傳入callapply 或者bind,這些值在調(diào)用時(shí)會(huì)被忽略,實(shí)際應(yīng)用的是默認(rèn)綁定規(guī)則:

function foo() {
    console.log( this.a );
}
var a = 2;
foo.call( null ); // 2

那么什么情況下你會(huì)傳入null呢?一種非常常見(jiàn)的做法是使用apply(..)來(lái)“展開(kāi)”一個(gè)數(shù)組,并當(dāng)作參數(shù)傳入一個(gè)函數(shù)(ES6中可以直接使用...操作符)。類似地,bind(..)可以對(duì)參數(shù)進(jìn)行柯里化(預(yù)先設(shè)置一些參數(shù)),這種方法有時(shí)非常有用:

function foo(a,b) {
    console.log( "a:" + a + ", b:" + b );
}
// 把數(shù)組“展開(kāi)”成參數(shù)
foo.apply( null, [2, 3] ); // a:2, b:3

// 使用 bind(..) 進(jìn)行柯里化
var bar = foo.bind( null, 2 );
bar( 3 ); // a:2, b:3

這兩種方法都需要傳入一個(gè)參數(shù)當(dāng)作this的綁定對(duì)象。如果函數(shù)并不關(guān)心this的話,你仍然需要傳入一個(gè)占位值,這時(shí)null可能是一個(gè)不錯(cuò)的選擇,就像代碼所示的那樣。

然而,總是使用null來(lái)忽略this綁定可能產(chǎn)生一些副作用。如果某個(gè)函數(shù)確實(shí)使用了this(比如第三方庫(kù)中的一個(gè)函數(shù)),那默認(rèn)綁定規(guī)則會(huì)把this綁定到全局對(duì)象(在瀏覽器中這個(gè)對(duì)象是window),這將導(dǎo)致不可預(yù)計(jì)的后果(比如修改全局對(duì)象。顯而易見(jiàn),這種方式可能會(huì)導(dǎo)致許多難以分析和追蹤的bug。

一種“更安全”的做法是傳入一個(gè)特殊的對(duì)象,把this綁定到這個(gè)對(duì)象不會(huì)對(duì)你的程序產(chǎn)生任何副作用。就像網(wǎng)絡(luò)(以及軍隊(duì))一樣,我們可以創(chuàng)建一個(gè)DMZdemilitarized zone,非軍事區(qū))對(duì)象,如果我們?cè)诤雎?b>this綁定時(shí)總是傳入一個(gè)DMZ對(duì)象,那就什么都不用擔(dān)心了,因?yàn)槿魏螌?duì)于this的使用都會(huì)被限制在這個(gè)空對(duì)象中,不會(huì)對(duì)全局對(duì)象產(chǎn)生任何影響。

由于這個(gè)DMZ對(duì)象完全是一個(gè)空對(duì)象,可以使用一個(gè)特殊的變量名來(lái)表示它,比如?(這是數(shù)學(xué)中表示空集合符號(hào)的小寫(xiě)形式)。在JavaScript中創(chuàng)建一個(gè)空對(duì)象最簡(jiǎn)單的方法都是Object.create(null),Object.create(null){}很像,但是并不會(huì)創(chuàng)建Object.prototype這個(gè)委托,所以它比{}“更空”,所以之前的例子可以改為:

function foo(a,b) {
    console.log( "a:" + a + ", b:" + b );
}
// 我們的DMZ 空對(duì)象
var ? = Object.create( null );
// 把數(shù)組展開(kāi)成參數(shù)
foo.apply( ?, [2, 3] ); // a:2, b:3
// 使用bind(..) 進(jìn)行柯里化
var bar = foo.bind( ?, 2 );
bar( 3 ); // a:2, b:3
間接引用

另一個(gè)需要注意的是,你有可能(有意或者無(wú)意地)創(chuàng)建一個(gè)函數(shù)的“間接引用”,在這種情況下,調(diào)用這個(gè)函數(shù)會(huì)應(yīng)用默認(rèn)綁定規(guī)則。

間接引用最容易在賦值時(shí)發(fā)生:

function foo() {
    console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2

賦值表達(dá)式的返回值是要賦的值,所以p.foo = o.foo的返回值是目標(biāo)函數(shù)的引用,即foo函數(shù)的引用,因此調(diào)用位置是foo()而不是p.foo()或者o.foo()。根據(jù)我們之前說(shuō)過(guò)的,這里會(huì)應(yīng)用默認(rèn)綁定。

軟綁定

之前我們已經(jīng)看到過(guò),硬綁定這種方式可以把this強(qiáng)制綁定到指定的對(duì)象(除了使用new時(shí)),防止函數(shù)調(diào)用應(yīng)用默認(rèn)綁定規(guī)則。問(wèn)題在于,硬綁定會(huì)大大降低函數(shù)的靈活性,使用硬綁定之后就無(wú)法使用隱式綁定或者顯式綁定來(lái)修改this。

如果可以給默認(rèn)綁定指定一個(gè)全局對(duì)象和undefined以外的值,那就可以實(shí)現(xiàn)和硬綁定相同的效果,同時(shí)保留隱式綁定或者顯式綁定修改this的能力。

可以通過(guò)一種被稱為軟綁定的方法來(lái)實(shí)現(xiàn)我們想要的效果:

if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
        var fn = this;//這個(gè)this是指調(diào)用softBind的函數(shù)
        // 捕獲所有 curried 參數(shù)(柯里化參數(shù))
        var curried = [].slice.call( arguments, 1 );//arguments指?jìng)魅雜oftBind的參數(shù)列表
        var bound = function() {
            return fn.apply(
                (!this || this === (window || global)) ? obj : this,
                curried.concat.apply( curried, arguments)
            );//這里的this是指調(diào)用bound時(shí)的this,arguments指?jìng)魅隻ound的參數(shù)列表
        };
        bound.prototype = Object.create( fn.prototype );
        return bound;
    };
}

除了軟綁定之外,softBind(..) 的其他原理和ES5內(nèi)置的bind(..) 類似。它會(huì)對(duì)指定的函數(shù)進(jìn)行封裝,首先檢查調(diào)用時(shí)的this,如果this綁定到全局對(duì)象或者undefined,那就把指定的默認(rèn)對(duì)象obj綁定到this,否則不會(huì)修改this。此外,這段代碼還支持可選的柯里化(詳情請(qǐng)查看之前和bind(..)相關(guān)的介紹),看看軟綁定的實(shí)例:

function foo() {
    console.log("name: " + this.name);
}
var obj = { name: "obj" },
obj2 = { name: "obj2" },
obj3 = { name: "obj3" };

var fooOBJ = foo.softBind( obj );
fooOBJ(); // name: obj

obj2.foo = foo.softBind(obj);
obj2.foo(); // name: obj2 <---- 看!??!通過(guò)上下文對(duì)象(隱式綁定)綁定到obj2

fooOBJ.call( obj3 ); // name: obj3 <---- 看!通過(guò)顯示綁定綁定到obj3

setTimeout( obj2.foo, 10 );// name: obj <---- 應(yīng)用了軟綁定,this本來(lái)綁定到全局對(duì)象,通過(guò)軟綁定綁定到了obj

可以看到,軟綁定版本的foo()可以手動(dòng)將this綁定到obj2或者obj3上,但如果應(yīng)用默
認(rèn)綁定,則會(huì)將this綁定到obj。

特殊的箭頭函數(shù)

我們之前介紹的四條規(guī)則已經(jīng)可以包含所有正常的函數(shù)。但是ES6中介紹了一種無(wú)法使用這些規(guī)則的特殊函數(shù)類型:箭頭函數(shù)。

箭頭函數(shù)并不是使用function關(guān)鍵字定義的,而是使用被稱為“胖箭頭”的操作符=>定義的。箭頭函數(shù)不使用this的四種標(biāo)準(zhǔn)規(guī)則,而是根據(jù)外層(函數(shù)或者全局)作用域來(lái)決定this。

我們來(lái)看看箭頭函數(shù)的詞法作用域:

function foo() {
    // 返回一個(gè)箭頭函數(shù)
    return (a) => {
        //this 繼承自foo()
        console.log( this.a );
    };
}
var obj1 = {
    a:2
};
var obj2 = {
    a:3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, 不是3 !

foo()內(nèi)部創(chuàng)建的箭頭函數(shù)會(huì)捕獲調(diào)用foo()時(shí)的this。由于foo()this綁定到obj1,bar(引用箭頭函數(shù))的this也會(huì)綁定到obj1箭頭函數(shù)的綁定無(wú)法被修改。(new也不行?。?/p>

箭頭函數(shù)最常用于回調(diào)函數(shù)中,例如事件處理器或者定時(shí)器:

function foo() {
    setTimeout(() => {
        // 這里的this 在詞法上繼承自foo()
        console.log( this.a );
    },100);
}
var obj = {
    a:2
};
foo.call( obj ); // 2

箭頭函數(shù)可以像bind(..)一樣確保函數(shù)的this被綁定到指定對(duì)象,此外,其重要性還體現(xiàn)在它用更常見(jiàn)的詞法作用域取代了傳統(tǒng)的this機(jī)制。實(shí)際上,在ES6之前我們就已經(jīng)在使用一種幾乎和箭頭函數(shù)完全一樣的模式:

function foo() {
    var self = this; // lexical capture of this
    setTimeout( function(){
        console.log( self.a );
    }, 100 );
}
var obj = {
    a: 2
};
foo.call( obj ); // 2

是不是非常熟悉?

雖然self = this和箭頭函數(shù)看起來(lái)都可以取代bind(..),但是從本質(zhì)上來(lái)說(shuō),它們想替代的是this機(jī)制,如果你經(jīng)常編寫(xiě)this風(fēng)格的代碼,但是絕大部分時(shí)候都會(huì)使用self = this或者箭頭函數(shù)來(lái)否定this機(jī)制,那你或許應(yīng)當(dāng):

只使用詞法作用域并完全拋棄錯(cuò)誤this風(fēng)格的代碼;

完全采用this風(fēng)格,在必要時(shí)使用bind(..),盡量避免使用self = this和箭頭函數(shù)。

當(dāng)然,包含這兩種代碼風(fēng)格的程序可以正常運(yùn)行,但是在同一個(gè)函數(shù)或者同一個(gè)程序中混合使用這兩種風(fēng)格通常會(huì)使代碼更難維護(hù),并且可能也會(huì)更難編寫(xiě)。

疑問(wèn)解答

先來(lái)說(shuō)一下最前面的一個(gè)例子的真實(shí)情況:

function foo(num) {
    console.log( "foo: " + num );
    // 記錄foo 被調(diào)用的次數(shù)
    this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
    if (i > 5) {
        foo( i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被調(diào)用了多少次?
console.log( foo.count ); // 0 -- WTF?

先說(shuō)結(jié)論,this指向全局對(duì)象,而this.countNaN。
通過(guò)分析我們可以知道foo的調(diào)用位置是全局作用域,然后foo處于非嚴(yán)格模式,所以this指向全局對(duì)象,由于this.count的值一開(kāi)始為undefined,然后進(jìn)行this.count++;的操作,所以變成NaN

記得前面提到過(guò)下面這段話:

嚴(yán)格模式下,禁止this關(guān)鍵字指向全局對(duì)象,此時(shí)this會(huì)綁定到undefined;所以當(dāng)函數(shù)定義在嚴(yán)格模式下或函數(shù)內(nèi)的代碼運(yùn)行在嚴(yán)格模式下時(shí),其中的this綁定的是undefined;特別注意如果僅僅是函數(shù)的調(diào)用語(yǔ)句運(yùn)行在嚴(yán)格模式下,那么不受影響,該函數(shù)內(nèi)的this仍然綁定到全局對(duì)象

但是測(cè)試的時(shí)候遇到一種情況一開(kāi)始讓我匪夷所思:

function foo(){
    "use strict";
    console.log(this);
}

setTimeout(foo,100);//Window

foo的函數(shù)體處于嚴(yán)格模式下,為什么this還是綁定到全局對(duì)象Window?于是我又測(cè)試了幾種情況:

"use strict";
function foo(){
    console.log(this);
}
setTimeout(foo,100);//Window

//---------分割線-----------

function foo(){
    console.log(this);
}
setTimeout(function(){
    "use strict";
    foo();
},100);//Window

//---------分割線-----------

function foo(){
    "use strict";
    console.log(this);
}
setTimeout(function(){
    foo();
},100);//undefined

只有最后一種情況this綁定到undefined,其他情況仍然綁定到Window
在MDN-Window.setTimeout-關(guān)于this的問(wèn)題中,找到一段備注:

備注:在嚴(yán)格模式下,setTimeout( )的回調(diào)函數(shù)里面的this仍然默認(rèn)指向window對(duì)象, 并不是undefined

但是這個(gè)僅僅是告訴了我們結(jié)論,并沒(méi)有給出為什么。經(jīng)過(guò)思考,我給出我自己的猜想,也不知道對(duì)不對(duì):

我們知道setTimout是掛在Window下的方法,所以調(diào)用時(shí)實(shí)際上是Window.setTimout,是通過(guò)Window對(duì)象調(diào)用的,一般認(rèn)為setTimout的偽代碼是下面這樣:

function setTimeout(fn,delay) {
    // 等待delay 毫秒
    fn(); 
}

但是通過(guò)前文的介紹,我們知道

直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,它的調(diào)用位置是全局作用域,非嚴(yán)格模式下綁定到全局對(duì)象,嚴(yán)格模式下綁定到undefined

根據(jù)setTimeout這種偽代碼,等待delay毫秒后,fn()就是一個(gè)不帶任何修飾的函數(shù)調(diào)用,而下面的測(cè)試確仍然指向全局對(duì)象Window

function foo(){
    "use strict";
    console.log(this);
}

Window.setTimeout(foo,100);//Window

所以我猜想,setTimout的偽代碼是下面這樣:

function setTimeout(fn,delay) {
    // 等待delay 毫秒
    //直接執(zhí)行fn內(nèi)的代碼,而不是調(diào)用fn(相當(dāng)于把fn中的代碼粘貼到此處) 
}

基于這種猜想,我們來(lái)看前面的測(cè)試代碼:

function foo(){
    "use strict";
    console.log(this);
}

Window.setTimeout(foo,100);//Window

相當(dāng)于下面這樣:

Window = {
    setTimeout: function(){
        // 等待100毫秒
        "use strict";
        console.log(this);
    }
}

這樣一看,this自然就是指向Window;再看其他三個(gè)測(cè)試代碼:

"use strict";
function foo(){
    console.log(this);
}
setTimeout(foo,100);//Window

//相當(dāng)于
"use strict";
Window = {
    setTimeout: function(){
        // 等待100毫秒
        console.log(this);
    }
}//通過(guò)Window調(diào)用setTimeout,this指向Window


//---------分割線-----------

function foo(){
    console.log(this);
}
setTimeout(function(){
    "use strict";
    foo();
},100);//Window

//相當(dāng)于
Window = {
    setTimeout: function(){
        // 等待100毫秒
        "use strict";
        foo();
    }//通過(guò)Window調(diào)用setTimeout,其內(nèi)部調(diào)用了foo,而且僅僅是foo的調(diào)用處于嚴(yán)格模式,所以foo中的this指向Window
}

//---------分割線-----------

function foo(){
    "use strict";
    console.log(this);
}
setTimeout(function(){
    foo();
},100);//undefined

//相當(dāng)于
Window = {
    setTimeout: function(){
        // 等待100毫秒
        foo();
    }//通過(guò)Window調(diào)用setTimeout,其內(nèi)部調(diào)用了foo,但是foo的函數(shù)體處于嚴(yán)格模式,所以foo中的this指向undefined
}

似乎一切也說(shuō)的過(guò)去,不過(guò)我暫時(shí)沒(méi)有找到權(quán)威性的資料來(lái)證實(shí),自己先這樣理解一下,如果不對(duì),還請(qǐng)大家指正!

尾聲

以前對(duì)this真是不清不楚,這次徹底的順了一遍之后清晰多了,每天進(jìn)步一點(diǎn)點(diǎn),加油~

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/95579.html

相關(guān)文章

  • ES2015入門(mén)系列10-類 classes

    摘要:我們繼續(xù),這次來(lái)聊聊類。,編寫(xiě)代碼角色基類判斷角色是否死亡升級(jí)受到傷害攻擊普通攻擊攻擊了造成了點(diǎn)傷害攻擊,有概率是用必殺攻擊必殺攻擊使用必殺攻擊了造成了點(diǎn)傷害游戲世界權(quán)利的游戲初始化英雄怪物集合,模擬簡(jiǎn)單的游戲關(guān)卡。 OK, 我們繼續(xù),這次來(lái)聊聊類。 內(nèi)有 Jon Snow大戰(zhàn)異鬼, ? 熟悉后端的朋友們對(duì)類肯定都不陌生,如下面一段PHP的代碼: class Human { pr...

    Wuv1Up 評(píng)論0 收藏0
  • ES2015入門(mén)系列11-模塊 Modules

    摘要:先來(lái)介紹下語(yǔ)法官方示例代碼模塊中對(duì)象暴露只需要即可,可以是任何類型的對(duì)象。手動(dòng)導(dǎo)入模塊下某個(gè)對(duì)象,需要和模塊中定義的名字對(duì)應(yīng),順序無(wú)關(guān)。 看一下官方介紹: Language-level support for modules for component definition. JS在ES2015開(kāi)始原生支持模塊化開(kāi)發(fā),我們之前也曾借助于諸如: AMD CommonJS 等的模塊加載...

    HitenDev 評(píng)論0 收藏0
  • 記一次作死 —— 被 Leetcode 封禁

    摘要:不過(guò)好消息是,在事件發(fā)生的二十四小時(shí)以后,我發(fā)現(xiàn)我的賬號(hào)解禁了,哈哈哈哈。 本文最初發(fā)布于我的個(gè)人博客:咀嚼之味 從昨天凌晨四點(diǎn)起,我的 Leetcode 賬號(hào)就無(wú)法提交任何代碼了,于是我意識(shí)到我的賬號(hào)大概是被封了…… 起因 我和我的同學(xué) @xidui 正在維護(hù)一個(gè)項(xiàng)目 xidui/algorithm-training。其實(shí)就是收錄一些算法題的解答,目前主要對(duì)象就是 Leetcode。...

    dackel 評(píng)論0 收藏0
  • 歷史首次!聯(lián)發(fā)科打敗高通成為全球第一,憑什么?

    摘要:據(jù)調(diào)研機(jī)構(gòu)數(shù)據(jù),年第三季度,全球智能手機(jī)芯片市場(chǎng)占有率中,聯(lián)發(fā)科力壓高通,歷史首次登頂全球第一。年月,聯(lián)發(fā)科發(fā)布全球首款十核處理器,以及它的升級(jí)版。聯(lián)發(fā)科本月表示,其最新的旗艦芯片將于明年第一季度發(fā)布,希望在農(nóng)歷新年前推出。在被喊了一年的MTK YES后,聯(lián)發(fā)科終于迎來(lái)了自己的YES時(shí)刻。據(jù)調(diào)研機(jī)構(gòu)Counterpoint數(shù)據(jù),2020年第三季度,全球智能手機(jī)芯片市場(chǎng)占有率中,聯(lián)發(fā)科力壓高通...

    Tecode 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<