作者:魚頭的Web海洋 公號(hào) / 陳大魚頭
此題目的答案可以分為三大類:
- 類型轉(zhuǎn)換時(shí)的劫持
首先我們要知道鹃彻,在 JS 中類型轉(zhuǎn)換只有三種情況,分別是:
轉(zhuǎn)換為布爾值
轉(zhuǎn)換為數(shù)字
轉(zhuǎn)換為字符串
轉(zhuǎn)換為原始類型
對(duì)象在轉(zhuǎn)換類型的時(shí)候筒占,會(huì)執(zhí)行原生方法ToPrimitive贪庙。
其算法如下:
如果已經(jīng)是 原始類型,則返回當(dāng)前值翰苫;
如果需要轉(zhuǎn) 字符串 則先調(diào)用 toSting方法止邮,如果此時(shí)是 原始類型 則直接返回,否則再調(diào)用 valueOf方法并返回結(jié)果奏窑;
如果不是 字符串导披,則先調(diào)用 valueOf方法,如果此時(shí)是 原始類型 則直接返回埃唯,否則再調(diào)用 toString方法并返回結(jié)果盛卡;
如果都沒有 原始類型 返回,則拋出 TypeError類型錯(cuò)誤筑凫。
當(dāng)然滑沧,我們可以通過(guò)重寫 Symbol.toPrimitive來(lái)制定轉(zhuǎn)換規(guī)則并村,此方法在轉(zhuǎn)原始類型時(shí)調(diào)用優(yōu)先級(jí)最高。
所以以此定義我們可以有以下四種答案:
?var a = {
arr: [3, 2, 1],
valueOf () {
console.group('valueOf')
console.log(this.arr)
console.groupEnd('valueOf')
return this.arr.pop()
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('biu')
}
var b = {
arr: [3, 2, 1],
toString () {
console.group('toString')
console.log(this.arr)
console.groupEnd('toString')
return this.arr.pop()
}
}
if (b == 1 && b == 2 && b == 3) {
console.log('biu')
}
var c = {
arr: [3, 2, 1],
[Symbol.toPrimitive] () {
console.group('Symbol.toPrimitive')
console.log(this.arr)
console.groupEnd('Symbol.toPrimitive')
return this.arr.pop()
}
}
if (c == 1 && c == 2 && c == 3) {
console.log('biu')
}
var d = [1, 2, 3]
d.join = d.shift
if (d == 1 && d == 2 && d == 3) {
console.log('biu')
}
注:事實(shí)上滓技,這四種可以算是同一種哩牍。關(guān)于最后一種,我們可以來(lái)看看ECMA中的 Array.prototype.toString() 定義:
定義 array 為 ToObject(thisvalue)(原生方法令漂,將當(dāng)前數(shù)組轉(zhuǎn)換成對(duì)象)膝昆;
定義 func 為 Get(array,'join')(原生方法,在這一步調(diào)用 join 方法)叠必;
如果 IsCallble(func) (原生方法荚孵,判斷是否有內(nèi)部可調(diào)用的函數(shù))為 false,則 設(shè)置 func 原生函數(shù) %ObjProto_toString%(原生函數(shù)纬朝, toString 的具體實(shí)現(xiàn))收叶;
返回 Call(func,array)。
- 對(duì) getter 的劫持
所謂的 getter 就是對(duì)象屬性在進(jìn)行查詢時(shí)會(huì)被調(diào)用的方法 get共苛,利用此函數(shù)也可以實(shí)現(xiàn)題目功能判没。
代碼如下:
window.val = 0
Object.defineProperty(window, 'd', {
get () {
return ++this.val
}
})
if (d == 1 && d == 2 && d == 3) {
console.log('biu')
}
const e = new Proxy({}, {
val: 1,
get () {
return () => this.val++;
}
});
if (e == 1 && e == 2 && e == 3) {
console.log('biu')
}
- 正則表達(dá)式
JS 中的 RegExp.prototype.exec() 作用是在一個(gè)指定字符串中執(zhí)行一個(gè)搜索匹配,返回一個(gè)結(jié)果數(shù)組或 null隅茎。
當(dāng)正則表達(dá)式使用 " g" 標(biāo)志時(shí)澄峰,可以多次執(zhí)行 exec 方法來(lái)查找同一個(gè)字符串中的成功匹配。當(dāng)你這樣做時(shí)辟犀,查找將從正則表達(dá)式的 lastIndex 屬性指定的位置開始俏竞。( test() 也會(huì)更新 lastIndex 屬性)。
lastIndex 是正則表達(dá)式的一個(gè)可讀可寫的整型屬性堂竟,用來(lái)指定下一次匹配的起始索引胞此。只有正則表達(dá)式使用了表示全局檢索的 " g" 標(biāo)志時(shí),該屬性才會(huì)起作用跃捣。
注:只有正則表達(dá)式使用了表示全局檢索的 " g" 標(biāo)志時(shí),該屬性才會(huì)起作用夺蛇。
綜上所述疚漆,我們可以有方案如下:
var f = {
reg: /\d/g,
valueOf () {
return this.reg.exec(123)[0]
}
}
if (f == 1 && f == 2 && f == 3) {
console.log('biu')
}
注:上述方法其實(shí)也利用了類型轉(zhuǎn)換的特點(diǎn)。然后暫時(shí)就寫下以上三種答案刁赦,不知道聰明的你是否還有別的解法呢娶聘?