大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
author: aSuncat
JavaScript知识点大全:https://www.yuque.com/webfront/js
所有最新最全面试题,持续更新在语雀。见
语雀-前端面试题,欢迎点击关注~
阅读目录
- html/ css:https://blog.csdn.net/aSuncat/article/details/88789368
- javascript:2022年版(见语雀)、2019年版
- es6:https://blog.csdn.net/aSuncat/article/details/88818661
- vue:https://blog.csdn.net/aSuncat/article/details/88978775
- react:2022年版(见语雀)、2019年版
- jQuery:https://blog.csdn.net/aSuncat/article/details/108577468
- webpack、gulp、grunt
- node
- 前后端通信http、https、tcp:https://blog.csdn.net/aSuncat/article/details/109180153
- web安全
- 前端性能
- 浏览器:https://blog.csdn.net/aSuncat/article/details/116934548
- 多端
- 算法相关
- 设计模式
- 正则表达式
- hybrid
- 全栈
- 项目
- svn、git
webpack、gulp、grunt
11、前端技术体系
(1)多版本/覆盖
时间戳
发布新版本回滚
(2)ssr & 同构
(3)webpack
vendor:commonchunk
external:全局变量
默认css处理
模块化发展历程? |
可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、<script type="module">
这几个角度考虑。
参考答案
模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。
IIFE:使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突。
(function(){
return {
data:[]
}
})()
AMD:使用requireJS 来编写模块化,特点:依赖必须提前声明好。
define('./index.js',function(code){
// code 就是index.js 返回的内容
})
CMD:使用seaJS 来编写模块化,特点:支持动态引入依赖文件。
define(function(require, exports, module) {
var indexCode = require('./index.js');
})
CommonJS:nodejs 中自带的模块化。
var fs = require('fs');
UMD:兼容AMD,CommonJS 模块化语法。
webpack(require.ensure):webpack 2.x 版本中的代码分割。
ES Modules:ES6 引入的模块化,支持import 来引入另一个 js 。
import a from 'a';
- webpack
webpack优化方式? |
待完善
24、webpack在使用层面,对插件和loader不够理解。
- gulp
1、
- grunt
1、
grunt和gulp的区别? |
1、易用:Gulp相比Grunt更简洁,而且遵循代码优于配置策略,维护Gulp更像是写代码。
2、高效:Gulp相比Grunt更有设计感,核心设计基于Unix流的概念,通过管道连接,不需要写中间文件。
3、高质量:Gulp的每个插件只完成一个功能,这也是Unix的设计原则之一,各个功能通过流进行整合并完成复杂的任务。例如:Grunt的imagemin插件不仅压缩图片,同时还包括缓存功能。他表示,在Gulp中,缓存是另一个插件,可以被别的插件使用,这样就促进了插件的可重用性。目前官方列出的有673个插件。
4、易学:Gulp的核心API只有5个,掌握了5个API就学会了Gulp,之后便可以通过管道流组合自己想要的任务。
5、流:使用Grunt的I/O过程中会产生一些中间态的临时文件,一些任务生成临时文件,其它任务可能会基于临时文件再做处理并生成最终的构建后文件。而使用Gulp的优势就是利用流的方式进行文件的处理,通过管道将多个任务和操作连接起来,因此只有一次I/O的过程,流程更清晰,更纯粹。
6、代码优于配置:维护Gulp更像是写代码,而且Gulp遵循CommonJS规范,因此跟写Node程序没有差别。
node
(1)nodejs 实践
(2)nodejs性能高在哪里
高并发非阻塞
IO 密集
(3)stream pipe
说不出背压机制
6、node
线上oom(通过重启,打profile,复现寻找bug点)。
基本的node性能监控
alinode等profile工具
浏览器渲染帧率、动画、性能相关,h5页面优化实践,
对小程序深度性能分析优化等方面很感兴趣
13、node服务线上的稳定,日志,安全,监控都有一定的了解,也有一定的线上运维经验
npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块? |
1.npm 模块安装机制:
发出npm install命令
查询node_modules目录之中是否已经存在指定模块
npm 向 registry 查询模块压缩包的网址
下载压缩包,存放在根目录下的.npm目录里
解压压缩包到当前项目的node_modules目录
若存在,不再重新安装
若不存在
2. npm 实现原理
输入 npm install 命令并敲下回车后,会经历如下几个阶段(以 npm 5.5.1 为例):
(1)执行工程自身 preinstall
当前 npm 工程如果定义了 preinstall 钩子此时会被执行。
(2)确定首层依赖模块
首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)。
工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。
(3)获取模块
获取模块是一个递归的过程,分为以下几步:
- 获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 package.json 中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有该模块信息直接拿即可,如果没有则从仓库获取。如 packaeg.json 中某个包的版本是 ^1.1.0,npm 就会去仓库中获取符合 1.x.x 形式的最新版本。
- 获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。
- 查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。
(4)模块扁平化(dedupe)
上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 loadsh,B 模块同样依赖于 lodash。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。
从 npm3 开始默认加入了一个 dedupe 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃。
这里需要对重复模块进行一个定义,它指的是模块名相同且 semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe 过程中被去掉。
比如 node-modules 下 foo 模块依赖 lodash@^1.0.0,bar 模块依赖 lodash@^1.1.0,则 ^1.1.0 为兼容版本。
而当 foo 依赖 lodash@^2.0.0,bar 依赖 lodash@^1.1.0,则依据 semver 的规则,二者不存在兼容版本。会将一个版本放在 node_modules 中,另一个仍保留在依赖树里。
举个例子,假设一个依赖树原本是这样:
node_modules
– foo
—- lodash@version1
– bar
—- lodash@version2
假设 version1 和 version2 是兼容版本,则经过 dedupe 会成为下面的形式:
node_modules
– foo
– bar
– lodash(保留的版本为兼容版本)
假设 version1 和 version2 为非兼容版本,则后面的版本保留在依赖树中:
node_modules
– foo
– lodash@version1
– bar
—- lodash@version2
(5)安装模块
这一步将会更新工程中的 node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)。
(6)执行工程自身生命周期
当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。
最后一步是生成或更新版本描述文件,npm install 过程完成。
了解v8引擎吗,一段js代码如何执行的? |
在执行一段代码时,JS 引擎会首先创建一个执行栈
然后JS引擎会创建一个全局执行上下文,并push到执行栈中, 这个过程JS引擎会为这段代码中所有变量分配内存并赋一个初始值(undefined),在创建完成后,JS引擎会进入执行阶段,这个过程JS引擎会逐行的执行代码,即为之前分配好内存的变量逐个赋值(真实值)。
如果这段代码中存在function的声明和调用,那么JS引擎会创建一个函数执行上下文,并push到执行栈中,其创建和执行过程跟全局执行上下文一样。但有特殊情况,即当函数中存在对其它函数的调用时,JS引擎会在父函数执行的过程中,将子函数的全局执行上下文push到执行栈,这也是为什么子函数能够访问到父函数内所声明的变量。
还有一种特殊情况是,在子函数执行的过程中,父函数已经return了,这种情况下,JS引擎会将父函数的上下文从执行栈中移除,与此同时,JS引擎会为还在执行的子函数上下文创建一个闭包,这个闭包里保存了父函数内声明的变量及其赋值,子函数仍然能够在其上下文中访问并使用这边变量/常量。当子函数执行完毕,JS引擎才会将子函数的上下文及闭包一并从执行栈中移除。
最后,JS引擎是单线程的,那么它是如何处理高并发的呢?即当代码中存在异步调用时JS是如何执行的。比如setTimeout或fetch请求都是non-blocking的,当异步调用代码触发时,JS引擎会将需要异步执行的代码移出调用栈,直到等待到返回结果,JS引擎会立即将与之对应的回调函数push进任务队列中等待被调用,当调用(执行)栈中已经没有需要被执行的代码时,JS引擎会立刻将任务队列中的回调函数逐个push进调用栈并执行。这个过程我们也称之为事件循环。
14、koa源码了解
web安全
Web攻击方式有哪几种? |
1、CSRF
2、XSS
3、SQL注入攻击
就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
简述HTTPS中间人攻击? |
参考答案
https协议由 http + ssl 协议构成,具体的链接过程可参考SSL或TLS握手的概述
中间人攻击过程如下:
服务器向客户端发送公钥。
攻击者截获公钥,保留在自己手上。
然后攻击者自己生成一个【伪造的】公钥,发给客户端。
客户端收到伪造的公钥后,生成加密hash值发给服务器。
攻击者获得加密hash值,用自己的私钥解密获得真秘钥。
同时生成假的加密hash值,发给服务器。
服务器用私钥解密获得假秘钥。
服务器用加秘钥加密传输信息
防范方法:
服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性
- CSRF
CSRF基本概念和缩写? |
CSRF,Cross-site request forgery,通常被称为跨站请求伪造。
CSRF攻击原理? |
1、前提:①用户在注册网站A登录过,②接口有漏洞。
2、引诱点击,往往是一个链接(这个链接自动携带cookie,不会带token),指向网站A的api,接口是get类型。浏览了A,浏览器自动生成新的cookie,网站A拿到cookie,接口运行。
CSRF防御措施? |
1、token验证。
注册网站,或者访问网站,服务器自动向本地存储一个token。
2、refer验证。
服务器判断页面是不是我这个站点来的页面。
3、隐藏令牌。
http的head头,不会放在链接上。
- XSS
XSS基本概念和缩写? |
XSS,cross-site scripting ,跨域脚本攻击。
XSS攻击原理? |
原理:向页面注入html标签或js脚本。
eg:提交区(评论区)写img标签,script标签,利用合法渠道向页面注入js
XSS防御措施? |
宗旨:让xss不可执行。
1、前端替换关键字,如替换<
为<
>
为>
2、后台替换。
3、任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。
- CSRF ,XSS的区别
CSRF ,XSS的区别? |
1、XSS是向页面注入js去运行,然后在js函数体中做他想做的事情。
CSRF是利用网站漏洞,自动执行接口。用户需要登陆网站。
2、XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。
CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。
- SQL注入
SQL注入防御措施? |
1、永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双”-“进行转换等。
2、永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3、永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4、不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。
前端性能
1、原则
(1)多使用内存、缓存或者其他方法。
(2)减少cpu占用,减少网络。
提升页面性能的方法有哪些? |
一、加载页面和静态资源
1、静态资源压缩合并,减少http请求。
(1)减少http请求数量
(2)减少请求资源大小
2、非核心代码异步加载。
3、静态资源缓存:通过链接名称控制缓存,只有内容改变的时候,链接名称才会改变。
4、利用浏览器缓存
5、使用cdn让资源加载更快
6、预解析dns
7、使用ssr后端渲染,数据直接输出到html中(ssr:server site render)
二、页面渲染
1、css、js及放置位置
(1)尽量避免在HTML标签中写style属性
(2)css放前面,js放后面。
(3)避免使用CSS Expression
2、图片
(1)避免图片和iFrame等的空Src。空Src会重新加载当前页面,影响速度和效率
(2)懒加载(图片懒加载,下拉加载更多)
<img id="img1" src="preview.jpg" data-realsrc="abc.jpg">
<script type="text/javascript">
var img1 = document.getElementById('img1');
img1.src = img1.getAttribute('data-realsrc');
</script>
3、dom操作
(1)减少dom查询,对dom查询做缓存。
// 未缓存dom查询
var i;
for (i = 0; i < document.getElementsByTagName('p').length; i++) {\
// todo
}
// 缓存了dom查询
var pList = document.getElementByTagName('p');
var i;
for (i = 0; i < pList.length; i++) {
// todo
}
(2)减少dom操作,多个操作尽量合并在一起执行。
var frag = document.createDocumentFragment(); // 片段,循环插入dom,改成先插入到片段,再append到文档流
(3)用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
4、事件
(1)尽早执行操作(如DOMContentLoaded)
(2)事件节流
var textarea = document.getElementById('text');
var timeoutId;
textarea.addEventListener('keyup', function() {
if(timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
// 触发change事件
}, 100)
})
5、代码细节优化
(1)用hash-table来优化查找
(2)多个变量声明合并
(3)少用全局变量
(4)避免全局查询
(5)避免使用with(with会创建自己的作用域,会增加作用域链长度)
(6)用setTimeout来避免页面失去响应
三、移动端性能优化
1、css
(1)不滥用Float。Float在渲染时计算量比较大,尽量减少使用
(2)不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用。
(3)避免使用css3渐变阴影效果。
2、css动画
(1)尽量使用css3动画,开启硬件加速。
可以用transform: translateZ(0)来开启硬件加速。
CSS中的属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过渡使用会引发手机过耗电增加
3、合理使用requestAnimationFrame动画代替setTimeout
4、适当使用touch事件代替click事件。
什么是防抖和节流?有什么区别?如何实现?? |
防抖
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
思路:
每次触发事件时都取消之前的延时调用方法
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
思路:
每次触发事件时都判断当前是否有等待执行的延时函数
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () {
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(this, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
- 非核心代码异步加载
异步加载的方式? |
1、动态脚本加载
script标签,加入到body中
2、defer
加载js的时候,script标签加defer和async
3、async
异步加载的区别? |
1、defer是在html解析完之后才会执行,如果是多个,按照加载的顺序依次进行。
2、async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关。
- 预解析dns
预解析dns的方式? |
1、
<link rel="dns-prefetch" href="//host_name_to_prefetch.com">
2、强制打开a标签的dns预解析
<meta http-equiv="x-dns-prefetch-control" content="on">
页面中所有a标签,默认打开了dns预解析,如果链接是https开头的,默认关闭dns预解析
多端
小程序和 H5 有什么区别? |
1、渲染方式与 H5 不同,小程序一般是通过 Native 原生渲染的,但是小程序同时也支持 web 渲染,如果使用 web 渲染的方式,我们需要初始化一个WebView 组件,然后在 WebView 中加载 H5 页面;
所以当我们开发一个小程序时,通常会使用 hybrid 的方式,即会根据具体情况选择部分功能用小程序原生的代码来开发,部分功能通过 WebView 加载 H5 页面来实现。Native 与 Web 渲染混合使用,以实现项目的最优解;
这里值得注意的是,小程序下,native 方式通常情况下性能要优于 web 方式。
2、小程序特有的双线程设计。 H5 下我们所有资源通常都会打到一个 bundle.js 文件里(不考虑分包加载),而小程序编译后的结果会有两个bundle,index.js封装的是小程序项目的 view 层,以及 index.worker.js 封装的是项目的业务逻辑,在运行时,会有两条线程来分别处理这两个bundle,一个是主渲染线程,它负责加载并渲染 index.js 里的内容,另外一个是 Service Worker线 程,它负责执行 index.worker.js 里封装的业务逻辑,这里面会有很多对底层api调用。
算法相关
通常情况下,搞金融的都会考算法。
一、排序
快速排序:https://segmentfault.com/a/1190000009426421
选择排序:https://segmentfault.com/a/1190000009366805
希尔排序:https://segmentfault.com/a/1190000009461832
二、堆栈、队列、链表
堆栈:https://juejin.im/entry/58759e79128fe1006b48cdfd
队列:https://juejin.im/entry/58759e79128fe1006b48cdfd
链表:https://juejin.im/entry/58759e79128fe1006b48cdfd
(1)js数组本身就具备堆栈和队列特性。
(2)堆栈:先进后出。
三、递归
递归:https://segmentfault.com/a/1190000009857470
(1)60%的算法题都用到递归。
四、波兰式和逆波兰式
理论:http://www.cnblogs.com/chenying99/p/3675876.html
源码:https://github.com/Tairraos/rpn.js/blob/master/rpn.js
手写一个冒泡排序? |
1、比较两个相邻的元素,如果后一个比前一个大,则交换位置。
2、 第一轮的时候最后一个元素应该是最大的一个。
3、按照第一步的方法进行两个相邻的元素的比较,由于最后一个元素已经是最大的了,所以最后一个元素不用比较。
function bubbleSort(arr) {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len - i - 1; j++) { // j=0时,得到最大的元素,放在了最后面
if (arr[j] > arr[j+1]) {
[arr[j], arr[j+1]] = [arr[j+1], arr[j]];
}
}
}
return arr;
}
let arr = [3,5,1,2,7,8,4,5,3,4];
let sortedArr = bubbleSort(arr);
console.log(sortedArr);
快速排序的思想? |
1、在数据集之中,找一个基准点,将数据分成两个部分,一部分比另外一部分所有的数据都要小,
2、建立两个数组,分别存储左边和右边的数组
3、利用递归进行下次比较
手写一个快速排序? |
function quickSort(arr) {
if (arr.length <= 1) { // 如果数组长度小于等于1无需判断直接返回即可
return arr;
}
var pivotIndex = Math.floor(arr.length / 2); // 取基准点
var pivot = arr.splice(pivotIndex, 1)[0]; // 取基准点的值,splice(index,1)函数可以返回数组中被删除的那个数
var left = []; // 存放比基准点小的数组
var right = []; // 存放比基准点大的数组
for (var i = 0; i < arr.length; i++) { // 遍历数组,进行判断分配
if (arr[i] < pivot) {
left.push(arr[i]); // 比基准点小的放在左边数组
} else {
right.push(arr[i]); // 比基准点大的放在右边数组
}
}
//递归执行以上操作,对左右两个数组进行操作,直到数组长度为<=1;
return quickSort(left).concat([pivot], quickSort(right));
};
var arr = [1, 2, 3, 55, 7, 99, 8, 100, 1021];
var sortedArr = quickSort(arr);
console.log(sortedArr);
设计模式
用过哪些设计模式? |
1、工厂模式:
主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。
工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。
function createObject(name,age,profession){//集中实例化的函数var obj = newObject();
obj.name =name;
obj.age = age;
obj.profession= profession;
obj.move =function () {
returnthis.name + ' at ' + this.age + ' engaged in ' + this.profession;
};
return obj;
}
var test1 = createObject('trigkit4',22,'programmer');//第一个实例
var test2 =createObject('mike',25,'engineer');//第二个实例
2、构造函数模式
使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:
①构造函数方法没有显示的创建对象 (new Object());
②直接将属性和方法赋值给 this 对象;
③没有 renturn 语句。
JS的四种设计模式? |
工厂模式
简单的工厂模式可以理解为解决多个相似的问题;
function CreatePerson(name,age,sex) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function(){
return this.name;
}
return obj;
}
var p1 = new CreatePerson("longen",'28','男');
var p2 = new CreatePerson("tugenhua",'27','女');
console.log(p1.name); // longen
console.log(p1.age); // 28
console.log(p1.sex); // 男
console.log(p1.sayName()); // longen
console.log(p2.name); // tugenhua
console.log(p2.age); // 27
console.log(p2.sex); // 女
console.log(p2.sayName()); // tugenhua
单例模式
只能被实例化(构造函数给实例添加属性与方法)一次
// 单体模式
var Singleton = function(name){
this.name = name;
};
Singleton.prototype.getName = function(){
return this.name;
}
// 获取实例对象
var getInstance = (function() {
var instance = null;
return function(name) {
if(!instance) {//相当于一个一次性阀门,只能实例化一次
instance = new Singleton(name);
}
return instance;
}
})();
// 测试单体模式的实例,所以a===b
var a = getInstance("aa");
var b = getInstance("bb");
沙箱模式
将一些函数放到自执行函数里面,但要用闭包暴露接口,用变量接收暴露的接口,再调用里面的值,否则无法使用里面的值
let sandboxModel=(function(){
function sayName(){};
function sayAge(){};
return{
sayName:sayName,
sayAge:sayAge
}
})()
发布者订阅模式
就例如如我们关注了某一个公众号,然后他对应的有新的消息就会给你推送,
//发布者与订阅模式
var shoeObj = {}; // 定义发布者
shoeObj.list = []; // 缓存列表 存放订阅者回调函数
// 增加订阅者
shoeObj.listen = function(fn) {
shoeObj.list.push(fn); // 订阅消息添加到缓存列表
}
// 发布消息
shoeObj.trigger = function() {
for (var i = 0, fn; fn = this.list[i++];) {
fn.apply(this, arguments);//第一个参数只是改变fn的this,
}
}
// 小红订阅如下消息
shoeObj.listen(function(color, size) {
console.log("颜色是:" + color);
console.log("尺码是:" + size);
});
// 小花订阅如下消息
shoeObj.listen(function(color, size) {
console.log("再次打印颜色是:" + color);
console.log("再次打印尺码是:" + size);
});
shoeObj.trigger("红色", 40);
shoeObj.trigger("黑色", 42);
代码实现逻辑是用数组存贮订阅者, 发布者回调函数里面通知的方式是遍历订阅者数组,并将发布者内容传入订阅者数组
对mvvm的理解? |
1、MVVM 是 Model-View-ViewModel 的缩写。
2、Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。
3、View 代表UI 组件,它负责将数据模型转化成UI 展现出来。
4、ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。
5、在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
mvvm框架实现的三要素/ vue的三要素? |
1、响应式:vue如何监听到data的每个属性变化?
(1)修改data属性后,vue立刻监听到。Object.defineProperty
var __name = 'may';
Object.defineProperty(obj, 'name',{
get: function() {
return __name;
},
set: function(newVal) {
__name = newVal; // 修改__name = 'april',obj.name就会变成april
}
})
(2)data属性代理到vm上
2、模板引擎:vue的模板如何被解析,指令如何处理?
(1)模板是什么
①本质:字符串
②有逻辑,如v-if, v-for等
③与html格式很像,但有很大区别
④模板最终必须转换成Js代码(js函数-render函数),因为
有逻辑(v-if, v-for),必须用js才能实现(图灵完美语言)
转换为html渲染页面,必须用js才能实现
(2)render函数
(3)render函数与vdom
3、渲染:vue的模板如何被渲染成Html?以及渲染过程?
正则表达式
写一个function,清除字符串前后的空格。(兼容所有浏览器)? |
function trim(str) {
if (str && typeof str === 'string') {
return str.replace(/(^\s*)|(\s*)$/g, '');
}
}
hybrid
15、hybrid业务开发经验,对离线包机制熟悉,多各种优化方案也了解得比较清楚。
7、离线包加载和更新机制,
22、servive worker, web worker
全栈
8、图片加载的一个细节,能够从全栈角度给出一些高并发情况下的系统扩展思路
27、跨域access-control-allow-origin多域名白名单处理
cdn部署
前端框架选型
人员协调项目延期
整个部门没有用到mock平台,前后端分离
自己写了服务在服务端用webpack+multi方式融合不同的业务模块打包
Mbox的数据管理方案(mbox的数据状态流转机制)
数据库,数据索引,事务,数据库锁的问题
5、前端核心监控数据来源(performance api + 业务定义为主)
31、逻辑外链如何保持多个数据同步
项目
16、资讯类的项目,有哪些技术特点(本想了解list相关的回答)
详情里面做了哪些
详情页对性能要求高,有哪些优化?配置缓存来优化。
缓存如何配置,
哪些缓存头来控制的缓存
类似静态化的性能优化,采用ssr比较适合详情页的技术
1、哪些工作是偏技术的,需要技术来解决的
svn、git
get fetch、git pull的区别 |
1、git fetch是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
2、git pull 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/174796.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...