💻 前端高频面试题—JavaScript篇(四)🏠专栏:前端面试题
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁
文章目录
- 前端高频面试题—JavaScript篇(四)
- 一. 原型 / 构造函数
- (1) 原型
- (2) 构造函数
- 二. 讲讲原型链?
- 三. 说一下Promise
- 四. 事件轮询机制
- 五. 设计模式
- 六. 继承
- (1). 为什么要学习继承?
- (2). 什么是继承?
- (3). 原型继承
- (4). 借用继承
- (5). 组合继承
- (6). 拷贝继承
- (7). 类继承
前端高频面试题—JavaScript篇(四)
本文主要讲述的前端高频面试题知识有:
- 原型 / 构造函数
- 原型链
- 说一下Promise
- 事件轮询机制
- 设计模式
- 继承
一. 原型 / 构造函数
(1) 原型
什么是原型?
将公共的方法提取出来,都写在原型上(只用书写和创建一次)
原型概念:
每一个函数都有一个特殊的属性叫做原型(prototype)
每一个对象:天生自带一个属性
__proto__
(指向所属构造函数的原型)
原型对象有一个自有属性constructor
,这个属性指向该函数
问答?
-
原型是什么 ?
一个对象,我们也称为 prototype 为原型对象。
JavaScript
常被描述为一种基于原型的语言——每个对象拥有一个原型对象 -
原型的作用是什么 ?
共享方法。
-
为什么要使用原型对象
因为构造函数方法虽然很好用,但是存在浪费内存的问题。每一次调用构造函数中的方法都会重新开辟一块新的内存存储(浪费了空间),而原型对象(prototype)可以对象共享可以节省内存。
(2) 构造函数
1. 概念
构造函数其实就是一个函数,只不过使用的时候需要和new 关键字连用,首字母大写。
和普通函数一样, 只不过调用的时候要和 new 调用 ,不然就是一个普通函数调用
const fn = function(age) {
let a = 1; // 块作用域,外面无法获取,内部使用
var b = 2; // 局部变量,外面无法获取,内部使用
this.age = age; // 属性,实例对象可以自由获取,this->实例对象
};
let f1 = new fn(18);
let f2 = new fn; // 这种写法也支持,弊端是无法传递参数
注意: 不写 new 的时候就是普通函数调用,没有创造对象的能力,但如果只是首字母不大写,只要和 new 连用,就有创造对象的能力。
2. 构造函数特点总结
-
首字母大写(推荐)
方便区分
-
构造函数里面不要书写return
构造函数里没有显式调用return,默认返回的是this对象,也就是新创建的实例对象。
当构造函数里调用return时,分两种情况:
1.return的是五种简单数据类型:String,Number,Boolean,Null,Undefined。
这种情况下,忽视return值,依然返回this对象。
2.return的是Object
这种情况下,不再返回this对象,而是返回return语句的返回值。
-
构造函数的调用必须和new连用
只有和new连用,才有构造函数的能力,不和new连用,就是一个普通函数
-
构造函数的this
构造函数的this指向:本次调用被自动创建的对象
- 自动创建出来的对象叫做 实例对象
- 这个创建对象的过程叫做 实例化 的过程
-
箭头函数没有this , 构造函数不能使用箭头函数书写
二. 讲讲原型链?
面试官主要询问点:
__proto__
和prototype之间的关系,以及对于属性的向上查找这些一定要清楚的
原型链:使用__proto__
串联起来的链状结构
对象的访问机制:
当访问一个对象成员的时候
- 首先在该对象自己身上查找,如果有直接使用,停止查找
- 如果没有,会自动去到
__proto__
查找,如果有直接使用,停止查找 - 如果仍然没有,继续去到
__proto__
在上一级查找 - 如果没有找到,返回undefined, (找到了原型链的顶级 null)
官方:每个实例对象(object)都有一个私有属性(称之为 proto)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
/*
七个指向问题:(p ==> Person的实例对象)
寻找思路主要还是要先了解:该对象所属的构造函数是什么?
1.p.__pro__ ==> Person.prototype
2.Person.prototype.__proto__ ==> Object.prototype
3.Person.__proto__ ==> Function.prototype
4.Function.__proto__ ==> Function.prototype
5.Object.__proto__ ==> Function.prototype
6.Function.prototype.__proto__ ==> Object.prototype
7.Object.prototype.__proto__ ==> null
原型链指向图:
三. 说一下Promise
面试官主要询问的点:
- a. 目的
- b. 状态
- c. 改变状态
- d. 方法
- e. async await
-
目的:解决回调地狱
-
状态:
持续:pending
成功:fulfilled
失败:rejected
-
改变状态
从持续状态转换到成功
从持续状态转换到失败
-
方法
Promise 的实例原型方法:
- then(函数):成功状态的时候执行的方法
- catch(函数):失败状态的时候执行的方法
- finally(函数) :结束时执行的方法,不管状态是成功还是失败,finally都会执行
Promise 本身的一些方法:
-
all
语法:Promise.all([多个 Promise])
作用:用于将多个 Promise 实例,包装成一个新的 Promise 实例,接受一个数组作为参数,只有数组里面的每个状态都变成resolve,则新的 Promise 实例状态才会变成resolve。
-
race
语法:Promise.race([多个promise])
作用:将多个 Promise 实例,包装成一个新的 Promise 实例,接受一个数组作为参数,只要其中有一个实例率先改变状态,则整个的状态就跟着改变。
-
allSettled (ES2020)
语法:Promise.allSettle([多个promise])
作用:方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。
简单理解就是:不管是成功还是失败,都会触发,并会把结果用数组的形式返回,数组里面放着每一个promise的结果
-
Promise的方法(主要是开发人员调试用的)
resolve()强行把promise的状态改为成功
reject()强行把Promise的状态改为失败
四. 事件轮询机制
事件轮询 (客户端)
开始轮询时间:从开始执行代码的时候就开始执行轮询
规则:
- 从第一个宏任务开始(一般是整个JavaScript代码段)
- 每执行完一个宏任务,清空一次微任务队列里面的所有内容
- 然后再执行一个宏任务
- 往复执行以上操作,直到所有队列任务都清空结束
关键词:
- 单线程:JS是一个单线程的代码执行机制,如果逐行执行代码, 会阻塞代码执行
- 调用栈:用来执行代码的空间 (栈: 后进先出)
- 队列:存放异步任务 (队列: 先进先出)
- 宏任务队列:JS整块代码(script)、setTimeout、setInterval…
- 微任务队列:Promise.then…
五. 设计模式
常见的设计模式:
-
单例模式
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式核心:实例化一个类的时候
先判断,之前有没有实例化过
- 如果有,就用之前的
- 如果没有,就实例化一个新的
场景:在点击按钮需要出现一个弹窗时,我们只希望无论点击多少次,都出现只出现一个弹窗。
-
策略模式
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
策略模式的目的是:将算法的使用与算法的实现分离开来
-
发布订阅模式
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
例子:比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。
上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。
六. 继承
继承:一个构造函数中的实例使用另一个构造函数上的属性和方法
(1). 为什么要学习继承?
写的构造函数, 定义了⼀个类型 (⼈类), 万⼀项⽬⾮常⼤, ⼜有了细化的多个类型 (⽼师, ⼯⼈, 学⽣)
学习继承, 可以让多个构造函数之间建⽴关联, 便于管理和复⽤
(2). 什么是继承?
继承: 从别⼈那⾥, 继承东⻄过来 (财产, 房产)
代码层⾯的继承: 继承⼀些属性构造的过程和⽅法
(3). 原型继承
1. 原型继承的概念
- 利用自定义原型的方法来实现继承关系
- 核心:子类的原型指向父类的实例
Son.prototype = new Father()
2. 原型继承的原理
子类的原型(Son.prototype)指向了父类的实例(new Father()也就是f)
子类实例化的对象想要访问一个属性时:
- 首先在自己身上寻找,
- 如果没有,沿着
__proto__
寻找, - 子类的实例化对象的
s.__proto__
指向的是所属的构造函数的原型Son.prototype == f
3. 原型继承的优缺点
优点:可以实现继承父类的属性和方法
缺点:
- 子类的原型被占用,之后往子类的原型上加属性和方法无效
- 继承下来的属性不在子类身上,在原型身上
(4). 借用继承
1. 概念
借用继承又叫:借用构造函数继承、call继承
核心:把父类构造函数当做普通函数用,并利用call()、apply()、bind()()修改this的指向
2. 优缺点
优点:
- 可以把属性继承在自己身上
- 有自己的原型
缺点:只能继承父类的属性,不能继承原型的方法
(5). 组合继承
1. 概念
把原型继承和借用继承组合在一起
(2) 优缺点
优点:
- 可以继承属性和方法
- 继承的属性在自己身上
缺点:原型上存在一套属性
(6). 拷贝继承
拷贝继承:把父类身上的所有内容复制一份放在子类的原型上
实现:利用 for…in 循环遍历对象
in 关键字的作用:
判断字符串是不是对象上的一个属性
返回值:true/false
特点:不只是对象本身,原型上的也能访问到
(7). 类继承
class 子类 extends 父类{
constructor(){
// 必须先写一个super() 相当于借用继承中把父类的方法用call在子类中执行一次
super()
/*
super 关键字用于访问和调用一个对象的父对象上的函数。
在构造函数中使用时,super关键字将单独出现,并且必须在使用 this 关键字之前使用。super 关键字也可以用来调用父对象上的函数。
*/
}
}
结束语:
希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪