JavaScript面试题集合

数据类型

null 和 undefined 的区别

浮点数精度

请问对表达式 0.1 + 0.2 === 0.3 求值,结果是什么?

0.1 加上 0.2 ,数学上结果应该是 0.3 ,因此表达式的值应该是 true 。如果你这样回答,就错啦!正确答案应该是 false 。这是为什么呢?

众所周知,计算机内部以二进制处理数据,浮点数也不例外。准确来说,计算机内部采用二进制版的科学计数法来表示浮点数。因为在二进制中,1 不能被 10 整除,十进制的 0.1 无法用二进制小数精确表示。

类比 $\frac{1}{3}$ 在十进制中,只能用无穷无尽的小数 0.3333…… 不断逼近;$\frac{1}{10}$ 在二进制中也是一个无限循环的小数,也只能不断逼近。但由于计算机表示浮点数小数部分的位数是有限的,这样就会有误差。

误差在计算的过程中会不断积累,以致出现 0.1 + 0.2 不等于 0.3 的现象,使用不当就会酿成大祸。为了避免浮点数精度不足的坑,我们可以采用高精度的十进制类库( decimal )。

更多关于浮点数精度问题,可以参考这篇文章:IEEE-754浮点数那些坑

语法

for in VS for of

请问 for in 循环和 for of 循环有什么区别?

  • for in 循环用于遍历对象属性;
  • for of 循环用于遍历可迭代对象,即遍历容器对象中保存的元素;

for in 循环以任意顺序遍历一个对象的可枚举属性,包括继承的可枚举属性,Symbol除外:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const me = {
  name: 'fasionchan',
  org: '小菜学编程',
}

for (let field in me) {
  console.log(`${field}=${me[field]}`)
}

// name=fasionchan
// org=小菜学编程

for of 循环用于遍历可迭代对象,包括 ArrayMapSetStringTypedArrayarguments 对象等等。

1
2
3
4
5
6
7
8
9
const numbers = [10, 20, 30];

for (let number of numbers) {
  console.log(number)
}

// 10
// 20
// 30

let var const 区别

  • let: 局部作用域
  • var: 全局作用域
  • const: 常量

这个例子,变量 i 在循环外申明,生命周期覆盖整个循环。因此,改动对闭包函数可见:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const buttons = [];
let i = 0;
while (i<5) {
  buttons.push(<Button
    onClick={() => {
      console.log(`点击按钮${i}`)
    }}
  >{`按钮${i}`}</Button>)
  i++
}

// 不管点哪个按钮都是输出5

而这个例子,变量 i 在循环中申明,具有块级作用域。它的生命周期仅限于当前循环体,在后续循环中的改变,对当前循环体中的闭包函数不可见:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const buttons = [];
for (let i=0; i<5; i++) {
  buttons.push(<Button
    onClick={() => {
      console.log(`点击按钮${i}`)
    }}
  >{`按钮${i}`}</Button>)
}

// 点某个按钮输出它的序号
1
2
3
4
5
const buttons = new Array(5).fill(0).map((_, i) => <Button
  onClick={() => {
    console.log(`点击按钮${i}`)
  }}
>{`按钮${i}`}</Button>)

箭头函数和普通函数的区别

  1. this指向不同:箭头函数 this 指向外层代码块的 this ;而普通函数的 this 指向函数调用者;callapplybind 可以修改普通函数的 this 指向,但不能修改箭头函数的 this 指向;
  2. 箭头函数没有原型,不能用作构造函数,而普通函数可以;

代码题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function foo() {
  let id = 10;
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 20;

foo();
foo.call({ id: 30 });
  • foo 第一次调用,this 指向的是 windows 对象,输出 20
  • foo 第二次调用,this 指向的是对象 {id : 30 } ,输出 30

小菜笔记】系列文章首发于公众号【小菜学编程】,敬请关注:

【小菜笔记】系列文章首发于公众号【小菜学编程】,敬请关注: