打卡学习-JavaScript面试题(七)

108 阅读5分钟

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);
    }

}