1.Js 是如何实现异步操作的?
Js 虽然是单线程的, 但是浏览器是多线程的, js 中的异步操作基本都是由浏览器提供的子线程来完成的.
2.分别介绍下 MVC, MVVM, MVP 这三种设计模式?
MVC 是后端语言的一种设计模式, 主要是实现对代码分层, M(model) 数据模型层, 主要负责操作数据库; V(view)视图层, 主要负责进行界面 展示, 可以认为前端的 html,css,js 充当的就是视图层; C(controller) 业 务控制层, 主要负责控制具体的业务逻辑, 负责将 model 数据层的数 据交给 view 视图层进行展示.
MVVM 是前端的一种设计模式, vue 就是基于这种模式来设计的, 是从 MVC 演变过来的. M(model)数据层, 主要负责数据和方法的初始化; V(view)视图层, 可以认为 html,css 充当的就是视图层的角色; VM(view model)视图模型层, 负责连接数据层和视图层, 将数据层的数据交给 视图层展示, 将视图层的行为传递给数据层.
MVP 也是从后端的 MVC 设置模式中演化过来的, 主要应用于安卓开 发中. M(model) 数据层, V(view) UI 逻辑; P(Presenter)业务逻辑
3.ES6/7/8 新特性
- Symbol 类型(基本)
- Set 类型(复杂)
- Map 类型(复杂)
- WeakSet 类型(复杂)
- WeakMap 类型(复杂)
- TypedArray 类型(复杂)
4.ES6 新增了那些特性?
- const(声明常量), let(声明变量)关键字;
- map 和 set 数据类型;
- 模板字符串;
- 对象数组解构赋值;
- 函数剩余参数;(...arg)
- 延展运算符;(...)
- 函数默认参数;fn(name=’zs’)
- 对象字面量的增强(属性名和属性值相同, 可缺省);
- Promise 异步对象;
- class 类的支持
5.使用 let 声明的变量和 var 声明的变量有什么区别?
使用 let 声明的变量有块级作用域, 并且没有变量的声明提升( 使用let 声明的变量在声明之前调用会报语法错误); 使用 var 声明的变量有声明提升(在声明之前调用会报 undefined), 没有块级作用域.
6.谈谈 async/await 的使用方式和场景
async 是用来修饰函数的声明, 使用async 修饰的函数会变成一个异步函数. await 用来修饰函数的调用, 被 await 修饰的函数必须返回一个 promise 异步对象, 使用 await 修饰后, 就会将 promise 异步对象转换成一个同步操作.
7.箭头函数有什么作用及实际应用场景
箭头函数可以使函数内部的 this 指向和函数外部保持一致; 箭头函数之所以可以让函数内部的 this 指向和外部保持一致是因为箭头函数内部没有 this 指向. 可以在ajax 的回调函数中使用箭头函数让回调函数中的 this 指向事件源; 可以在定时器的第二个参数中使用箭头函数, 避免函数内部的 this 指向全局 window.
8.class 类的如何实现继承
使用 extends 关键字实现继承
class Person{
constructor(props){
this.name=props.name;
this.age=props.age;
}
}
// Student 继承 Person
class Student extends Person{
super(props);
this.score=props.score;
}
}
9.谈谈对 Promise 的理解
Promise 本身并没有提供任何的代码逻辑, 它可以帮助我们改造或优化传统的使用回调函数实现的异步操作, 让我们以一种更优雅的方式来实现异步操作.
最显著的一个特点就是通过 Promise 可以解决传统的回调地狱. 代码层面 Promise 提供了一个构造函数, 在使用的时候必须通过 new 创建一个实例对象, 在创建实对象的时候需要传递一个匿名函数, 这个匿名函数需要两个参数(resolve,reject), resolve 成功处理函数, reject 失败处理函数. 什么时候触发成功处理函数和失败处理函数, 由具体的业务逻辑来决定.
resolve 和 reject 需要通过Promise 实例对象提供的 then 方法来传递.Promise 提供了两个静态方法 all,race,all 可以一次执行多个 Promise 实例, 返回值是数组; race 也可以一次执行多个 Promise 实例, 哪个实例最先执行完, 就返回哪个的执行结果.
10.你能手写一个Promise嘛
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function MyPromise(fn) {
// 保存初始化状态
let self = this;
// 初始化状态
this.state = PENDING;
// 用于保存 resolve 或者 rejected 传入的值
this.value = null;
// 用于保存 resolve 的回调函数
this.resolvedCallbacks = [];
// 用于保存 reject 的回调函数
this.rejectedCallbacks = [];
//状态改变为 resolved 方法
function resolve(value) {
// 判断传入元素是否为 Promise 值,
// 如果是,则改变状态必须等待前一个状态改变后在进行改变
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
// 保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
// 只有状态为 pending 是才能转变
if (self.state === PENDING) {
// 修改状态
self.state = RESOLVED;
// 设置传入的值
self.value = value;
// 执行回到函数
self.resolvedCallbacks.forEach(callback => {
callback(value);
})
}
}, 0);
}
// 状态改变为 rejected 方法
function reject(value) {
// 保证代码的执行顺序为本轮事件循环的末尾
setTimeout(() => {
// 只有状态为 pending 时才能转变
if (self.state === PENDING) {
// 修改状态
self.state = REJECTED;
// 设置传入的值
self.value = value;
// 执行回调函数
self.rejectedCallbacks.forEach(callback => {
callback(value);
});
}
}, 0);
}
// 将两个方法传入函数执行
try {
fn(resolve, reject);
} catch (e) {
// 遇到错误时,捕获错误,执行 reject 函数
reject(e);
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
// 首先判断两个参数是否为函数类型,因为这两个参数是可选参数
onResolved = typeof onResolved === "function" ?
onResolved : function (value) {
return value;
};
onRejected = typeof onRejected === "function" ?
onRejected : function (error) {
throw error;
}
// 如果是等待状态,则将函数加入对应列表中
if (this.state === PENDING) {
this.rejectedCallbacks.push(onResolved);
this.rejectedCallbacks.push(onRejected);
}
// 如果状态已经凝固,则直接执行对应状态的函数
if (this.state === RESOLVED) {
onResolved(this.value);
}
if (this.state === REJECTED) {
onRejected(this.value);
}
}