大挑战! JS前端知识闯关,你过得了几关?

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

前言

基础知识真有趣,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);
716d9a7b1d821f6665a9169a590eb34f.png
image.png

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')
复制代码
39704d18ec8165bc1dd3010d52f46bf2.png
截图_20212014102047.png

null在全局上却查询不到描述信息:

Object.getOwnPropertyDescriptor(global, 'null')
复制代码
9dd8da9774dff14626ba492b5fed5f2e.png
截图_20212114102114.png

结果

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

注意两点

  1. 预期转为字符串这种字样, 比如 `${person}`

  2. 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)

问题解析

  1. 有默认值的参数,不计入长度

  2. 剩余参数不计入长度

  3. 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[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.参数传递

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位尾数位来表示。

借助:http://www.binaryconvert.com/result_double.html

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个有问题的字符需要密切的注意:(,[, +, -, /, 其作为一行代码的开头,很可能产生意外的情况,所以,没事代码最后写个分号,保准没错。

答案

8abf3d722ffe762f71ca13aa97e36cb1.png
image.png

写在最后

Node 社群

我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

1cc78a6b5b825368edb532555b5bf8e2.png

   “分享、点赞、在看” 支持一波👍

引用

JavaScript深入之从ECMAScript规范解读this[3]
<<编写高质量JavaScript代码的68的有效方法>>

参考资料

[1]

JavaScript深入之从ECMAScript规范解读this: https://github.com/mqyqingfeng/Blog/issues/7

[2]

https://juejin.cn/pin/6994350401550024741: https://juejin.cn/pin/6994350401550024741

[3]

JavaScript深入之从ECMAScript规范解读this: https://github.com/mqyqingfeng/Blog/issues/7

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值