大挑戰(zhàn)! JS前端知識闖關(guān),你過得了幾關(guān)?
前言
基礎(chǔ)知識真有趣,10個基礎(chǔ)知識的題目,請君來戰(zhàn)!
1. a.x = a = {n:2}
var?a?=?{n:1};
a.x?=?a?=?{n:2};
//?求a.x
alert(a.x);?
解析
JavaScript 總是嚴(yán)格按照從左至右的順序來計算表達(dá)式。
a.x 最后執(zhí)行賦值的時候,保留的是對 原來a的引用, alert的時候,a是被重新賦值過后的a。
var?a?=?{n:1},?ref?=?a;
a.x?=?a?=?{n:2};
console.log("a:",?a);?
console.log("ref:",ref);
image.png2. 按位或取整數(shù)部分
求值:
100.8?|?0???
-101.6?|?0???
8589934592.8?|?0
解析
位運算符將數(shù)字視為32位的有符號整數(shù),而32位整數(shù)的取值范圍是 -2147483648 ~ 2147483647。
超過32位有符號整數(shù)范圍取值的數(shù),進(jìn)行位或操作取整都是不準(zhǔn)確的。
?2147483647.1?|?0??//??2147483647?正確
?2147483648.1?|?0??//?-2147483648?錯誤
-2147483648.1?|?0??//?-2147483648?正確
-2147483649.1?|?0??//??2147483647?錯誤
同樣的,我們可以用~~來取整數(shù)部分, 當(dāng)然依舊存在超范圍就不準(zhǔn)確的問題。
~~?100.8?//?100??正確
~~?2147483649.1??//?-2147483647??錯誤
答案
100.8?|?0????//?100
-101.6?|?0???//?-101
8589934592.8?|?0??//?0
3. 神奇的eval
var?x?=?"global";
function?log1(){
????var?x?=?"local";
????return?eval("x")
}
function?log2(){
????var?x?=?"local";
????return?window.eval("x")
}
function?log3(){
????var?x?=?"local";
????var?fn?=?eval
????return?fn("x")
}
function?log4(){
????var?x?=?"local";
????return?(0,?eval)(x)
}
log1();
log2();
log3();
log4();
解析
eval函數(shù)具備訪問調(diào)用它那是的整個作用域的能力。
間接調(diào)用, 例如綁定eval函數(shù)到另外一個變量名,通過變量名調(diào)用函數(shù)會使代碼失去去所有局部作用域訪問的能力。
(0, eval) 其也是eval的間接調(diào)用。
log1();???//?local
log2();???//?global
log3();???//?global
log4();???//?global
答案
4. delete知多少
delete?null;
delete?undefined;
解析
undefined在實現(xiàn)上是一個全局屬性, 而null是一個關(guān)鍵字。
Oject.getOwnPropertyDescriptor(global,?'undefined')
復(fù)制代碼
截圖_20212014102047.pngnull在全局上卻查詢不到描述信息:
Object.getOwnPropertyDescriptor(global,?'null')
復(fù)制代碼
截圖_20212114102114.png結(jié)果
delete?null;?//?true
delete?undefined;?//?false
5. 類型轉(zhuǎn)換
function?Person(name,?age)?{
????this.name?=?name;
????this.age?=?age;
}
Person.prototype.valueOf?=?function?()?{
????return?this.age;
}
Person.prototype.toString?=?function?()?{
????return?this.name
}
Date.prototype.valueOf?=?function?()?{
????return?this.getTime()
}
Date.prototype.toString?=?function?()?{
????return?this.getTime()?+?""
}
var?person?=?new?Person("tom",?100);
console.log(person?+?10);
console.log(`${person}`)
console.log(""?+?person)
var?date?=?new?Date(2001,?0,?0);
console.log(date?+?0,?typeof?(date?+?0))
console.log(date?+?date.getTime());
分析
對象轉(zhuǎn)換成基礎(chǔ)數(shù)據(jù)類型
- Symbol.toPrimitive 優(yōu)先
- 如果預(yù)期轉(zhuǎn)為字符串,Object.prototype.toString
- 如果無預(yù)期轉(zhuǎn)為字符串, 先走 Oject.prototye.valueOf, 再走Object.prototype.toString, 特例是Date類型,是先toString,再valueOf
注意兩點
預(yù)期轉(zhuǎn)為字符串這種字樣, 比如`${person}`- Date是特別的,是優(yōu)先toString
結(jié)果
var?person?=?new?Person("tom",?100);?
console.log(person?+?10);??//?110
console.log(`${person}`)???//?tom
console.log(""?+?person)???//?100
var?date?=?new?Date(2001,?0,?0);
console.log(date?+?0,?typeof?(date?+?0))?
//?9781920000000?string
console.log(date?+?date.getTime());
//?978192000000978192000000
6. 函數(shù)的length
function?add(num1,?num2,?num3=1,?...args){?
}
const?boundAdd?=?add.bind(null,?10);
console.log(boundAdd.length)
問題解析
- 有默認(rèn)值的參數(shù),不計入長度
- 剩余參數(shù)不計入長度
- bind之后,減少對應(yīng)的length長度
答案
console.log(boundAdd.length)?//?1
7. this的指向
var?value?=?1;
var?foo?=?{
??value:?2,
??bar:?function?()?{
????return?this.value;
??}
}
console.log(foo.bar());
console.log((foo.bar)());
console.log((foo.bar?=?foo.bar)());
console.log((false?||?foo.bar)());
console.log((foo.bar,?foo.bar)());
解析
ES規(guī)范中,引用類型(Reference類型)有一個獲取對應(yīng)值的方法:GetValue。簡單模擬 GetValue 的使用:
var?foo?=?1;
var?fooReference?=?{
????base:?EnvironmentRecord,
????name:?'foo',
????strict:?false
};
GetValue(fooReference)?//?1;
GetValue 返回對象屬性真正的值,但是要注意:調(diào)用 GetValue,返回的將是具體的值,而不再是一個 Reference
本題目如果調(diào)用了 GetValue, 那么其作用域就變成了全局。
(foo.bar) 并沒有調(diào)用取值操作,而其余的均調(diào)用了取值操作。
更多詳情:JavaScript深入之從ECMAScript規(guī)范解讀this[1]
答案
console.log(foo.bar());???//?2
console.log((foo.bar)());??//?2
console.log((foo.bar?=?foo.bar)());??//?1
console.log((false?||?foo.bar)());???//?1
console.log((foo.bar,?foo.bar)());???//?1
8.參數(shù)傳遞
function?test(param1,?param2,?param3)?{
????param1?=?"new?param1";
????param3??=?"new?param3"
????console.log(param1?==?arguments[0]);
????console.log(param3?==?arguments[2]);
}
function?test_strict(param1,?param2,?param3)?{
????"use?strict"
????param1?=?"new?param1";
????param3??=?"new?param3"
????console.log(param1?==?arguments[0]);
????console.log(param3?==?arguments[2]);
}
test('param1',?'param2')
test_strict('param1',?'param2');
解析
非嚴(yán)格模式下:傳入的參數(shù),實參和 arguments 的值會共享,當(dāng)沒有傳入時,實參與 arguments 值不會共享。
嚴(yán)格模式下,實參和 arguments 是不會共享的。
答案
test('param1',?'param2')
test_strict('param1',?'param2');
//?true
//?false
//?false
//?false
9. 小數(shù)相加
(0.1?+?0.2)?+?0.3??===?0.1?+?0.2?+?0.3?
解析
簡略的回答就是精確問題。
更多的回答 IEEE 754, 雙精度浮點數(shù)(64位),使用1為符號位、11位指數(shù)位、52位尾數(shù)位來表示。
借助:http://www.binaryconvert.com/result_double.html
0.1?0-01111111011-1001100110011001100110011001100110011001100110011010
0.2?0-01111111100-1001100110011001100110011001100110011001100110011010
0.3?0-01111111101-0011001100110011001100110011001100110011001100110011
當(dāng)然,計算還好好幾個步驟
- 對階(大階對小階)
- 位數(shù)運算
- 結(jié)果規(guī)格化
- 舍入處理
- 移除檢查 當(dāng)然,本題,后面兩項都不存在。具體細(xì)節(jié),改篇文章再見!
答案
(0.1?+?0.2)?+?0.3??===?0.1?+?0.2?+?0.3??//?false
0.6000000000000001?===?0.6?//?false
10. 自動補(bǔ)全
如下代碼輸出的值
var?a?=?[[1,2],2,3]
console.log(a)
[0,2,3].map(v=>?console.log(v*v))
console.log(a)
解析
javascript能智能的插入分號,但是有5個有問題的字符需要密切的注意:(,[, +, -, /, 其作為一行代碼的開頭,很可能產(chǎn)生意外的情況,所以,沒事代碼最后寫個分號,保準(zhǔn)沒錯。
答案
image.png寫在最后
技術(shù)交流請到?
引用
JavaScript深入之從ECMAScript規(guī)范解讀this[3]
<<編寫高質(zhì)量JavaScript代碼的68的有效方法>>
參考資料
[1]JavaScript深入之從ECMAScript規(guī)范解讀this: https://github.com/mqyqingfeng/Blog/issues/7
[2]https://juejin.cn/pin/6994350401550024741: https://juejin.cn/pin/6994350401550024741
[3]JavaScript深入之從ECMAScript規(guī)范解讀this: https://github.com/mqyqingfeng/Blog/issues/7
