前言
基础知识真有趣,10个基础知识的题目,请君来战!
1. a.x = a = {n:2}
var a = {n:1}; a.x = a = {n:2}; // 求a.x alert(a.x); 复制代码
解析
JavaScript 总是严格按照从左至右的顺序来计算表达式。
a.x 最后执行赋值的时候,保留的是对 原来a的引用
, alert的时候,a是被重新赋值过后的a。
var a = {n:1}, ref = a; a.x = a = {n:2}; console.log("a:", a); console.log("ref:",ref); 复制代码
2. 按位或取整数部分
求值:
100.8 | 0 -101.6 | 0 8589934592.8 | 0 复制代码
解析
位运算符将数字视为32位的有符号整数,而32位整数的取值范围是 -2147483648 ~ 2147483647
。
超过32位有符号整数范围取值的数,进行位或操作取整都是不准确的。
2147483647.1 | 0 // 2147483647 正确 2147483648.1 | 0 // -2147483648 错误 -2147483648.1 | 0 // -2147483648 正确 -2147483649.1 | 0 // 2147483647 错误 复制代码
同样的,我们可以用~~
来取整数部分, 当然依旧存在超范围就不准确的问题。
~~ 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函数具备访问调用它那是的整个作用域的能力。
间接调用, 例如绑定eval函数到另外一个变量名,通过变量名调用函数会使代码失去去所有局部作用域访问的能力。
(0, eval)
其也是eval的间接调用。
log1(); // local log2(); // global log3(); // global log4(); // global 复制代码
答案
4. delete知多少
delete null; delete undefined; 复制代码
解析
undefined
在实现上是一个全局属性, 而null
是一个关键字。
Oject.getOwnPropertyDescriptor(global, 'undefined') 复制代码 复制代码
null在全局上却查询不到描述信息:
Object.getOwnPropertyDescriptor(global, 'null') 复制代码 复制代码
结果
delete null; // true delete undefined; // false 复制代码
5. 类型转换
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()); 复制代码
分析
对象转换成基础数据类型
- Symbol.toPrimitive 优先
- 如果预期转为字符串,Object.prototype.toString
- 如果无预期转为字符串, 先走 Oject.prototye.valueOf, 再走Object.prototype.toString, 特例是Date类型,是先toString,再valueOf
注意两点
预期转为字符串
这种字样, 比如`${person}`
- Date是特别的,是优先toString
结果
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. 函数的length
function add(num1, num2, num3=1, ...args){ } const boundAdd = add.bind(null, 10); console.log(boundAdd.length) 复制代码
问题解析
- 有默认值的参数,不计入长度
- 剩余参数不计入长度
- bind之后,减少对应的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规范中,引用类型(Reference类型)有一个获取对应值的方法: GetValue。 简单模拟 GetValue 的使用:
var foo = 1; var fooReference = { base: EnvironmentRecord, name: 'foo', strict: false }; GetValue(fooReference) // 1; 复制代码
GetValue 返回对象属性真正的值,但是要注意: 调用 GetValue,返回的将是具体的值,而不再是一个 Reference
本题目如果调用了 GetValue, 那么其作用域就变成了全局。
(foo.bar)
并没有调用取值操作,而其余的均调用了取值操作。
更多详情: JavaScript深入之从ECMAScript规范解读this
答案
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.参数传递
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'); 复制代码
解析
非严格模式下:传入的参数,实参和 arguments 的值会共享,当没有传入时,实参与 arguments 值不会共享。
严格模式下,实参和 arguments 是不会共享的。
答案
test('param1', 'param2') test_strict('param1', 'param2'); // true // false // false // false 复制代码
9. 小数相加
(0.1 + 0.2) + 0.3 === 0.1 + (0.2 + 0.3) 复制代码
解析
简略的回答就是精确问题。
更多的回答 IEEE 754, 双精度浮点数(64位),使用1为符号位、11位指数位、52位尾数位来表示。
借助:www.binaryconvert.com/result_doub…
0.1 0-01111111011-1001100110011001100110011001100110011001100110011010 0.2 0-01111111100-1001100110011001100110011001100110011001100110011010 0.3 0-01111111101-0011001100110011001100110011001100110011001100110011 复制代码
当然,计算还好好几个步骤
- 对阶(大阶对小阶)
- 位数运算
- 结果规格化
- 舍入处理
- 移除检查
当然,本题,后面两项都不存在。 具体细节,改篇文章再见!
答案
(0.1 + 0.2) + 0.3 === 0.1 + 0.2 + 0.3 // false 0.6000000000000001 === 0.6 // false 复制代码
10. 自动补全
如下代码输出的值
var a = [[1,2],2,3] console.log(a) [0,2,3].map(v=> console.log(v*v)) console.log(a) 复制代码
解析
javascript能智能的插入分号,但是有5个有问题的字符需要密切的注意: (
,[
, +
, -
, /
, 其作为一行代码的开头,很可能产生意外的情况,所以,没事代码最后写个分号,保准没错。
答案
写在最后
技术交流群请到 这里来。 或者添加我的微信 dirge-cloud,带带我,一起学习。