几个常见题目

原文

下面这段代码,浏览器控制台上会打印什么?

var a = 10
function foo() {
	console.log(a)
	var a = 20
}
foo()
1
2
3
4
5
6

答案: undefind
解析: 执行 foo 函数的时候 a 导致了变量提升,但是变量提升只提升声明,不提升赋值,所以 a 为 undefind

我们使用 let 或 const 代替 var,输出是否相同

var a = 10
function foo() {
	console.log(a)
	var a = 20
}
foo()
1
2
3
4
5
6

答案: 在浏览器 console 种使用 let 替换导致了报错
解析: let 定义的变量必须要先申明

"newArray"中有哪些元素?

var array = []
for (var i = 0; i < 3; i++) {
	array.push(() => i)
}
var newArray = array.map(el => el())
console.log(newArray)
1
2
3
4
5
6

答案: [3,3,3]
解析: 首先要明确 array 中存放的是返回 i 的匿名函数即 () => i。在 for 循环中,array 的每一项保存了该匿名函数,其中的 i 为 i 这个值的引用。

运行foo函数,是否会导致堆栈错误?

function foo() {
	setTimeout(foo, 0)
}
1
2
3

答案: 不会
解析: foo函数的执行会导致死循环,但并不会造成堆栈错误。因为setTimeout是伪异步执行,当你将函数交由setTimeout处理后,原来的函数并不会等待,会继续执行,函数可以结束,资源也就可以释放。

深入参考12

运行foo函数,页面是否会有响应

function foo() {
	return Promise.resolve().then(foo)
}
1
2
3

答案: 页面直接卡爆,慎重测试!
解析: 本质上Promise是 es6 中为了异步操作解决地域回调问题来设计出的语法糖。简而言之,Promise是 基于 callback 实现的,在Promise resolve 以后,依然需要执行 callback 方法,此时内存不会释放。

我们能否以某种方式为下面的语句使用展开运算而不导致类型错误

var obj = {x:1,y:2,z:3}
[...obj];//TypeError
// 实际上对象的展开运算符在ES7中才添加
1
2
3

展开语法 和 for-of 语句遍历 iterable 对象定义要遍历的数据。Array 或 Map 是具有默认迭代行为的内置迭代器。对象不是可迭代的,但是可以通过使用 iterable 和 iterator 协议使它们可迭代。
Mozilla文档中,如果一个对象实现了@@iterator方法,那么它就是可迭代的,这意味着这个对象(或者它原型链上的一个对象)必须有一个带有@@iterator键的属性,这个键可以通过常量Symbol.iterator获得。 示例如下

var obj = { x: 1, y: 2, z: 3 }
obj[Symbol.iterator] = function() {
	// iterator 是一个具有 next 方法的对象,
	// 它的返回至少有一个对象
	// 两个属性:value&done。

	// 返回一个 iterator 对象
	return {
		next: function() {
			if (this._countDown === 3) {
				const lastValue = this._countDown
				return { value: this._countDown, done: true }
			}
			this._countDown = this._countDown + 1
			return { value: this._countDown, done: false }
		},
		_countDown: 0
	}
}
;[...obj] // 打印 [1, 2, 3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

还可以使用generator函数来定制对象的迭代行为:

var obj = {x:1, y:2, z: 3}
obj[Symbol.iterator] = function*() {
  yield 1;
  yield 2;
  yield 3;
}
[...obj]; // 打印 [1, 2, 3]

1
2
3
4
5
6
7
8

运行以下代码片段时,控制台上会打印什么?

var obj = { a: 1, b: 2 }
Object.setPrototypeOf(obj, { c: 3 })
Object.defineProperty(obj, 'd', { value: 4, enumerable: false })

// what properties will be printed when we run the for-in loop?
for (let prop in obj) {
	console.log(prop)
}
1
2
3
4
5
6
7
8

答案: a,b,c
解析: for-in 循环遍历对象本身的可枚举属性以及对象从其原型继承的属性。 可枚举属性是可以在 for-in 循环期间包含和访问的属性。enmuerable

xGetter()会打印什么值?

var x = 10
var foo = {
	x: 90,
	getX: function() {
		return this.x
	}
}
foo.getX() // prints 90
var xGetter = foo.getX
xGetter() // prints ??
1
2
3
4
5
6
7
8
9
10

答案: 10
解析: xGetter()中的this指向了window

上次更新时间: 10/12/2019, 8:35:23 PM