1 Star 0 Fork 0

计爱玲 / fed-e-task-01-01

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 7.92 KB
一键复制 编辑 原始数据 按行查看 历史
计爱玲 提交于 2020-05-06 18:42 . 简单题答案

简答题

1. 请说出下列最终的执行结果,并解释为什么?

var a = []
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i)
  }
}
a[6]() // 10

答:输出结果为10。因为var是全局变量,当执行a6的时候,函数体中的变量i,JS引擎会根据作用域去查到,在函数作用域里查不到i的定义,就会往上层作用域查找,直到在全局作用域中查到i,此时i已经变成了10。 如果希望调用ai的结果输出i,可以将for循环中的i的声明由var改为let。因为let会产生块级作用域。执行函数时函数内的变量i可以在for循环里面每次产生的块级作用域里查到i的值。

var a = []
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i)
  }
}
a[6]() // 6

除此之外,还可以通过闭包的形式,用函数作用域摆脱全局作用域的影响。将每一轮的变量i放到闭包中,执行函数的时候,JS引擎根据作用域查找时,在当前闭包中就可以查到当前的i的值,而当前i的值就是每轮循环时的i。

var a = []
for (let i = 0; i < 10; i++) {
  a[i] = (function(i){
    return function () {
      console.log(i)
    }
  })(i)
}
a[6]() // 6

2. 请说出下列最终的执行结果,并解释为什么?

var tmp = 123
if (true) {
  console.log(tmp)
  let tmp
}

答:会在console.log(tmp)时报错:ReferenceError: Cannot access 'tmp' before initialization 因为在ES6中,let定义的变量会产生块级作用域,虽然在全局用var tmp = 123 定义了tmp,但是在进入if里面后,又用let重新定义了tmp,此时的if作用域的tmp都是let变量声明的块级变量,全局变量tmp已经被屏蔽了。当执行console.log(tmp)时,根据作用域的查找原则,JS引擎会先在代码执行处的最内层的块级作用域中查找,如果查找不到才会往上级作用域查找。而在if块级作用域中有tmp的声明,但是console.log(tmp)在执行的时候,tmp还未被初始化,所以会报错。


3. 结合ES6新语法,用最简单的方式找出数组中的最小值

var arr = [12, 34, 32, 89, 4]
const minValue = Math.min(...arr)
console.log(minValue) // 4

4. 请详细说明var、let、const三种声明变量的方式之间的具体差别?

答:let const都是块级作用域,let是变量,const是常量。var定义的变量在创建和初始化的过程会提升。let和const定义的变量创建过程会提升,但初始化过程没有提升。而const只有创建和初始化过程,没有赋值过程,不可以被重新赋值。

console.log(t) // undefined
var t
console.log(t) // ReferenceError: Cannot access 't' before initialization
let t

5. 请说出下列代码最终输出的结果,并解释为什么?

var a = 10
var obj = {
  a: 20,
  fn() {
    setTimeout(() => {
      console.log(this.a)
    })
  }
}
obj.fn()

答:输出20。setTimeout中的函数是箭头函数,箭头函数中的this指向的是上层作用域中的this,也就是普通函数fn(){}函数体的this。而fn()是对象obj的成员方法,在调用时fn内的this指向函数的调用者,也就是obj,所以this.a就是obj.a,所以输出20。


6. 简述Symbol类型的用途?

答:Symbol是ES6新增的一种基础数据类型,最主要的作用就是为对象添加独一无二的属性名。console.log(Symbol() === Symbol()) // false

const obj = {
  [Symbol()]: 11
}

此时obj的这个Symbol属性不可被枚举。


7. 说说什么是浅拷贝,什么是深拷贝?

答:JS的数据类型分为值类型和引用类型。值类型变量是存放在栈中,引用类型变量是将内存地址放在栈中,而栈中的地址指向了堆中的一块区域,堆中这个地址存放的内容才是这个引用类型变量的真正的内容。 在浅拷贝时,值类型会直接拷贝,而引用类型只拷贝了变量的地址,新的变量和原变量还会指向同一个堆中的区域。新变量的改变会对原变量产生影响,因为内存地址相同,其中一个变量的改变,其实改变的是同一个内存中的东西。

let a = 1
let b = a
b = 2
// 值类型拷贝新变量不会对原变量产生影响。
console.log(a === b, a, b) // false 1 2

let c = {
  name: 'cathy'
}
let d = c
d.name = 'jal'
// 引用类型拷贝新变量会对原变量产生影响。
console.log(c === d, c, d) // true { name: 'jal' } { name: 'jal' }

而在深拷贝时,遇到值类型会直接拷贝,遇到引用类型时,会进行递归拷贝,如果这个引用类型是数组/对象,则判断数组的每一个元素/属性值,如果是值类型,则直接拷贝,如果是引用类型,则再对这个元素/属性值进行判断,递归下去,直到拷贝完整个对象为止。 这是我之前写的深拷贝案例:

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj
  let newObj
  if (obj instanceof Array) {
    newObj = []
  } else {
    newObj = {}
  }
  for (let key in obj) {
    if (obj.hasOwnProperty(key))
      newObj[key] = deepClone(obj[key])
  }
  return newObj
}

8. 谈谈你是如何理解JS异步编程的,Event Loop是做什么的,什么是宏任务,什么是微任务?

JS是单线程语言,指JS执行环境中那个负责执行代码的线程只有一个。但是JS的运行环境以及JS的某些API在运行时是可以开启新的线程的。当JS代码的回调栈中进行某些耗时任务时,会将这些耗时任务放到WebAPI中,等到可以执行的时候,就会进入消息队列中。当回调栈空的时候,会被Event Loop监听到,Event Loop会从消息队列中取出第一个任务放到回调栈中让主任务执行。 notes/img/IMG_0159.jpeg JS回调队列中的任务称之为【宏任务】,而宏任务执行过程中可以临时加上一些额外需求,可以选择作为一个新的宏任务进到队列中排队(如setTimeout),也可以作为当前任务的【微任务】,直接在当前任务结束后立即执行。

微任务的目的是为了提高整体的响应能力,目前绝大多数异步调用都是作为宏任务执行,Promise 、MutationObserver、process.nextTick 是作为微任务在本轮调用的末尾执行。


9. 将下面异步代码使用Promise改进?

setTimeout(function() {
  var a = 'hello'
  setTimeout(function () {
    var b = 'lagou'
      setTimeout(function () {
        var c = 'I love U'
        console.log(a + b + c)
      }, 10)
  }, 10)
}, 10)

改为Promise后:

new Promise((resolve, reject) => {
  setTimeout(() => {
    var a = 'hello'
    resolve(a)
  }, 10);
})
.then(res=>{
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      var b = ' lagou'
      resolve(res + b)
    }, 10);
  })
})
.then(res => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      var c = ' I love U'
      resolve(res + c)
    }, 10);
  })
})
.then(res => {
  console.log(res)
})
.catch(err=>{
  console.log(err)
})

10. 请简述TypeScript和JavaScript之间的联系

答:TypeScript是JavaScript的超集,是基于JavaScript之上的编程语言,它解决了JavaScript类型系统的问题。TypeScript的语法上对JavaScript兼容,JavaScript代码完全可以当做TypeScript代码运行。不过TypeScript在JavaScript基础上,有了更严格的类型要求。如果有错误的类型问题,JavaScript在运行时才会暴露出来,而TypeScript则会在项目编译初期就会报错。


11. 请谈谈你所认为的TypeScript优缺点

答: 优点:

  • JavaScript的超集/扩展集
  • 任何一种JavaScript运行环境都支持
  • 功能更为强大,生态也更健全、更完善

缺点:

  • 语言本身多了很多概念
  • 项目初期,TypeScript会增加一些成本
1
https://gitee.com/jiailing/fed-e-task-01-01.git
git@gitee.com:jiailing/fed-e-task-01-01.git
jiailing
fed-e-task-01-01
fed-e-task-01-01
master

搜索帮助