刷面试题
刷题的重要性,不用多说。对于应届生或工作年限不长的人来说,刷面试题一方面能够尽可能地快速自己对某个技术点的理解,另一方面在面试时,有一定几率被问到相同或相似题,另外或多或少也能够为自己面试增加一些自信心,可见适当的刷题是很有必要的。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
前端字节跳动真题解析
-
【269页】前端大厂面试题宝典
最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。
@testDec
class Demo {
// …
}
function testDec(target) {
target.isDec = true
}
console.log(Demo.isDec)
//输出true
打印出来了true,说明@testDec这个装饰器已经成功了,函数是个装饰器,用@testDec给Demo装饰了一遍。这个target其实就是class Demo,然后给她加一个isDec。
拆解后就是下面的内容:
// 装饰器原理
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
装饰器参数的形式
@testDec(false)
class Demo {
}
function testDec(isDec) {
return function (target) {
target.isDec = isDec
}
}
console.log(Demo.isDec);
验证是否是一个真正的装饰器模式需要验证以下几点:
1.将现有对戏那个和装饰器进行分离,两者独立存在
2.符合开放封闭原则
2. 适配器模式
适配器模式:旧接口格式和使用者不兼容,中间加一个适配转换接口。
比如国外的插座跟国内的插座不一样,我们需要买个转换器去兼容。
上代码:
class Adaptee {
specificRequest() {
return ‘德国标准的插头’;
}
}
class Target {
constructor() {
this.adaptee = new Adaptee();
}
request() {
let info = this.adaptee.specificRequest();
return ${info} -> 转换器 -> 中国标准的插头
}
}
// 测试
let client = new Target();
client.request();
结果:
德国标准的插头 -> 转换器 -> 中国标准的插头
场景上可封装旧接口:
// 自己封装的ajax,使用方式如下:
ajax({
url: ‘/getData’,
type: ‘Post’,
dataType: ‘json’,
data: {
id: ‘123’
}
}).done(function(){
})
// 但因为历史原因,代码中全都是:
// $.ajax({…})
这个时候需要一个适配器:
// 做一层适配器
var $ = {
ajax: function (options) {
return ajax(options)
}
}
3. 代理模式
代理模式:使用者无权访问目标对象,中间加代理,通过代理做授权和控制。
明星经纪人:比如有个演出,要请明星,要先联系经纪人。
或者理解为:为一个对象提供一个代用品或者占位符,以便控制对它的访问。例如图片懒加载、中介等。
/**
-
pre:代理模式
-
小明追求A,B是A的好朋友,小明比不知道A什么时候心情好,不好意思直接将花交给A,
-
于是小明将花交给B,再由B交给A.
*/
// 花的类
class Flower{
constructor(name){
this.name = name
}
}
// 小明拥有sendFlower的方法
let Xioaming = {
sendFlower(target){
var flower = new Flower(“玫瑰花”)
target.receive(flower)
}
}
// B对象中拥有接受花的方法,同时接收到花之后,监听A的心情,并且传入A心情好的时候函数
let B = {
receive(flower){
this.flower =flower
A.listenMood(()=>{
A.receive(this.flower)
})
}
}
// A接收到花之后输出花的名字
let A = {
receive(flower){
console.log(A收到了${flower.name}
)
// A收到了玫瑰花
},
listenMood(func){
setTimeout(func,1000)
}
}
Xioaming.sendFlower(B)
虚拟代理用于图片的预加载
图片很大,页面加载时会空白,体验不好,所以我们需要个占位符,来短暂替代这个图片,等图片加载好了放上去。
let myImage = (function(){
let img = new Image
document.body.appendChild(img)
return {
setSrc:(src)=>{
img.src = src
}
}
})()
let imgProxy =(function(){
let imgProxy = new Image
// 这个地方我使用了setTimeout来增强演示效果,否则本地加载太快,根本看不到。
imgProxy.οnlοad=function(){
setTimeout(()=>{
myImage.setSrc(this.src)
},2000)
}
return (src)=>{
myImage.setSrc(“…/…/img/bgimg.jpeg”)
imgProxy.src=src
}
})()
imgProxy(“…/…/img/background-cover.jpg”)
ES6 Proxy
其实在ES6中,已经有了Proxy,这个内置的函数。我们来用一个例子来演示一下他的用法。这是一个明星代理的问题。
let star={
name : “张XX”,
age:25,
phone : “1300001111”
}
let agent = new Proxy(star,
{
get:function(target,key){
if(key === “phone”){
return “18839552597”
}else if(key === “name”){
return “张XX”
}else if(key === “price”){
return “12W”
}else if(key === “customPrice”){
return target.customPrice
}
},
set:function(target,key,value){
if(key === “customPrice”){
if(value < “10”){
console.log(“太低了!!!”)
return false
}else{
target[key] = value
return true
}
}
}
}
)
console.log(agent.name)
console.log(agent.price)
console.log(agent.phone)
console.log(agent.age)
agent.customPrice = “12”
console.log(agent)
console.log(agent.customPrice)
设计原则验证
代理类和目标类分离,隔离开目标类和使用者
符合开放封闭原则
行为型模式
1. 策略模式
策略模式是一种简单却常用的设计模式,它的应用场景非常广泛。我们先了解下策略模式的概念,再通过代码示例来更清晰的认识它。
策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 Context。通过组合和委托来让 Context 拥有执行策略的能力,从而实现可复用、可扩展和可维护,并且避免大量复制粘贴的工作。
策略模式的典型应用场景是表单校验中,对于校验规则的封装。接下来我们就通过一个简单的例子具体了解一下:
/**
- 登录控制器
*/
function LoginController() {
this.strategy = undefined;
this.setStrategy = function (strategy) {
this.strategy = strategy;
this.login = this.strategy.login;
}
}
/**
- 用户名、密码登录策略
*/
function LocalStragegy() {
this.login = ({ username, password }) => {
console.log(username, password);
// authenticating with username and password…
}
}
/**
- 手机号、验证码登录策略
*/
function PhoneStragety() {
this.login = ({ phone, verifyCode }) => {
console.log(phone, verifyCode);
// authenticating with hone and verifyCode…
}
}
/**
- 第三方社交登录策略
*/
function SocialStragety() {
this.login = ({ id, secret }) => {
console.log(id, secret);
// authenticating with id and secret…
}
}
const loginController = new LoginController();
// 调用用户名、密码登录接口,使用LocalStrategy
app.use(‘/login/local’, function (req, res) {
loginController.setStrategy(new LocalStragegy());
loginController.login(req.body);
});
// 调用手机、验证码登录接口,使用PhoneStrategy
app.use(‘/login/phone’, function (req, res) {
loginController.setStrategy(new PhoneStragety());
loginController.login(req.body);
});
// 调用社交登录接口,使用SocialStrategy
app.use(‘/login/social’, function (req, res) {
loginController.setStrategy(new SocialStragety());
loginController.login(req.body);
});
从以上示例可以得出使用策略模式有以下优势:
-
方便在运行时切换算法和策略
-
代码更简洁,避免使用大量的条件判断
-
关注分离,每个strategy类控制自己的算法逻辑,strategy和其使用者之间也相互独立
2. 观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一或一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。典型代表vue/react等。
使用观察者模式的好处:
-
支持简单的广播通信,自动通知所有已经订阅过的对象。
-
目标对象与观察者存在的是动态关联,增加了灵活性。
-
目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
当然给元素绑定事件的
addEventListener()
也是一种:
target.addEventListener(type, listener [, options]);
Target就是被观察对象Subject,listener就是观察者Observer。
观察者模式中Subject对象一般需要实现以下API:
-
subscribe()
: 接收一个观察者observer对象,使其订阅自己 -
unsubscribe()
: 接收一个观察者observer对象,使其取消订阅自己 -
fire()
: 触发事件,通知到所有观察者
用JavaScript手动实现观察者模式:
// 被观察者
function Subject() {
this.observers = [];
}
Subject.prototype = {
// 订阅
subscribe: function (observer) {
this.observers.push(observer);
},
// 取消订阅
unsubscribe: function (observerToRemove) {
this.observers = this.observers.filter(observer => {
return observer !== observerToRemove;
})
},
// 事件触发
fire: function () {
this.observers.forEach(observer => {
observer.call();
});
}
}
验证一下订阅是否成功:
const subject = new Subject();
function observer1() {
console.log(‘Observer 1 Firing!’);
}
function observer2() {
console.log(‘Observer 2 Firing!’);
}
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.fire();
输出:
Observer 1 Firing!
Observer 2 Firing!
验证一下取消订阅是否成功:
subject.unsubscribe(observer2);
subject.fire();
输出:
Observer 1 Firing!
3. 迭代器模式
ES6中的迭代器 Iterator 相信大家都不陌生,迭代器用于遍历容器(集合)并访问容器中的元素,而且无论容器的数据结构是什么(Array、Set、Map等),迭代器的接口都应该是一样的,都需要遵循 迭代器协议。
迭代器模式解决了以下问题:
-
提供一致的遍历各种数据结构的方式,而不用了解数据的内部结构
-
提供遍历容器(集合)的能力而无需改变容器的接口
一个迭代器通常需要实现以下接口:
-
hasNext()
:判断迭代是否结束,返回Boolean -
next()
:查找并返回下一个元素
为Javascript的数组实现一个迭代器可以这么写:
const item = [1, ‘red’, false, 3.14];
function Iterator(items) {
this.items = items;
this.index = 0;
}
Iterator.prototype = {
hasNext: function () {
return this.index < this.items.length;
},
next: function () {
return this.items[this.index++];
}
}
验证一下迭代器:
const iterator = new Iterator(item);
while(iterator.hasNext()){
console.log(iterator.next());
}
输出:
1, red, false, 3.14
ES6提供了更简单的迭代循环语法 for...of
,使用该语法的前提是操作对象需要实现 可迭代协议(The iterable protocol),简单说就是该对象有个Key为 Symbol.iterator
的方法,该方法返回一个iterator对象。
比如我们实现一个 Range
类用于在某个数字区间进行迭代:
function Range(start, end) {
return {
[Symbol.iterator]: function () {
return {
next() {
if (start < end) {
return { value: start++, done: false };
}
return { done: true, value: end };
}
}
}
}
}
文末
如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。
同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。
这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。
269页《前端大厂面试宝典》
包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
前端面试题汇总
JavaScript