-
1.以下代码执行结果及原因:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function() { console.log(i) } } a[6]()
由于var声明的变量是不产生作用域依附于全局,此时js预编译的时候会发现,全局作用域中存在
a = [], i = 0
变量(提升变量), 接着执行循环的时候给每一个a[i]赋值上了一个函数。当执行a[6]()
的时候,进入a[6]函数所在的词法作用域,运行代码console.log(i)
, 此时,在a[6]
函数的词法作用域中不存在变量i
,于是js开始往上一个词法作用域寻找,直至发现变量i
存在于全局,拿到此时全局的变量i
, 此时for
循环早已走完,变量i
必然为10
,所以输出为10。解决的方案有很多,例如改为使用let声明变量i, 使用闭包保存变量等..以下列举俩解决方案var a = []; for (let i = 0; i < 10; i++) { a[i] = function() { console.log(i) } } a[6]() var a = []; for (var i = 0; i < 10; i++) { (i =>{ a[i] = function() { console.log(i) } })(i) } a[6]()
-
2.以下代码执行结果及原因:
var tmp = 123 if (1) { console.log(tmp) let tmp }
以上代码会报错,let变量会形成作用域,不可以先使用后声明(好像有个什么暂死区的概念,也是一知半解,就不扯了..)
-
3.es6 找数组最小值
var arr = [12, 34, 32, 89, 4] Math.min(...arr)
-
4.var let const 区别
声明方式 变量提升 初始值 作用域 重复声明 var ✅ ❌ 全局 ✅ let ❌ ❌ 块级 ❌ const ❌ ✅ 块级 ❌ -
5.以下代码执行结果及原因:
var a = 10 var obj = { a: 20, fn () { setTimeout(() => { console.log(this.a) }) } } obj.fn()
输出应该是:
20
, obj.fn定义的时候
其内部this是指向window的(浏览器环境),具体分析: obj.fn定义的时候(编译阶段),底层需要对该函数创建及确定一个词法作用域来入栈,setTimeout中对入参函数也是同理,顺序就是obj.fn入栈,内部this指向obj,然后setTimeout中对入参函数入栈,因为其是一个箭头函数,箭头函数创建的时候是不绑定this的,箭头函数内部的this指向是继承自函数词法作用域创建时(执行阶段)其作用域链上一层的内部this, 详细如下方例子
,与常规的函数在编译阶段其内部this就已经被绑定了不同,箭头函数内this是在执行阶段作用域链创建时从上一级作用域继承而来。此时,setTimeout中入参函数的上层作用域为window(浏览器环境), 所以内部的打印的this.a为20a = 1 const obj = { a: 2, fn() { console.log(this.a) } } obj.fn.call(window) // output: 1, function声明的函数内部this在创建的时候被分配了this指向window a = 1 const obj = { a: 2, fn: () => { console.log(this.a) } } obj.fn.call(obj) // output: 1, 箭头函数创建的时候不分配this, 函数内部的this继承自上层作用域链,只和上层作用域的this有关
-
6.symbol 用途
- 创建一个唯一的值,可以用于拓展第三方库的sdk以防止冲突
- Symbol.iterator 可以使对象被迭代遍历
- Symbol.toStringTag 可以指定对象toString方法的返回值,常用户自定义对象或数据结构
-
7.深/浅拷贝
与原数据同指向 包含数据为基本数据类型时 包含数据为引用类型时 浅拷贝 ❌ 改变不影响原数据 改变影响原数据 深拷贝 ❌ 改变不影响原数据 改变不影响原数据 -
8.JS异步编程, Event Loop作用? 宏/微任务
- 使用
回调函数
方式,此方式使用简单易理解,但对代码对阅读和维护不友好,当存在多个异步逻辑的时候,彼此之间高耦合。[思路:使用回调] - 改进版本回调方式就是使用
发布订阅模式
,异步逻辑由事件驱动,但依然没有改变异步逻辑增多时代码逻辑混乱(除非在底层全封好了),代码流程会很不直观。[思路:发布订阅/事件池] - 使用
Promise
异步任务扁平化,根据Promise规范书写的代码看起来流程较为清晰,支持链式调用,[思路:函数式编程,maybe函子切割任务状态] - 使用
Generator
+co
的方式,该方式异步逻辑从代码层面“同步化”,利用了generator的执行特性,代码直观,逻辑清晰,应用广泛:Koa1.0, redux-saga
- 使用
async/await
,async/await看起来很像是Generator
+co
的一个语法糖,async声明的函数体内
所有被await
的函数都是阻塞的,书写的代码清晰直观,业务中应用广泛。
- 主线程会不断的从
任务队列
中调用事件,在当前事件存在宏任务的时候,宏任务将成为下一个事件进入任务队列
之中,当存在微任务当时候,微任务会进入当前事件末尾,可以认为当前事件中也存在一个微任务队列,微任务会被塞进这个队列中,当当前事件结束当时候,会读取微任务队列中的事件并执行,所有微任务事件执行完毕之后,当前事件出栈,当前事件之前存其的宏任务开始进栈执行。
-
宏任务 浏览器 Node I/O ✅ ✅ setTimeout ✅ ✅ setInterval ✅ ✅ setImmediate ❌ ✅ requestAnimationFrame ✅ ❌ 微任务 浏览器 Node process.nextTick ❌ ✅ MutationObserver ✅ ❌ Promise.then catch finally ✅ ✅ 关于宏/微任务执行顺序如以上Event Loop
- 使用
-
9.改进以下异步代码
setTimeout(() => { var a = 'hello' setTimeout(() => { var b = 'world' setTimeout(() => { var c = '!' console.log(a + b + c) }) }) }) Promise.resolve('hello') .then(s => s + 'world') .then(s => s + '!')
-
- TS/JS 关系
- TS是JS类型的超集
-
- TS 优缺点
TS 优点 缺点 编译阶段便可发现类型不匹配的错误 类型应当作为辅助信息却被强制需要 类型信息有利于编译器优化 不指定类型便无法编码 IDE自动补全,TS DOC 失去了JS很大灵活性 用别人的TS很爽 自己写TS很惨 诚然,当项目体量起来之后,TS可以帮我们规避掉一些问题并且增强我们代码的健壮性,个人觉得不应该为了TS而去写TS,而是站在项目体量,团队人数,去考虑用不用,每一种技术栈都应如此。
-
Notifications
You must be signed in to change notification settings - Fork 0
valonY/fed-e-task-01-01
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
About
The first work of Part One
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published