web前端
2023-02-14 09:27:46 15 举报
AI智能生成
面试题
作者其他创作
大纲/内容
js优化
防抖和节流
防抖:对于短时间内连续触发的事件(如滚动事件,搜索框.),
防抖的含义就是让某个时间期限内,事件处理函数只执行一次
防抖的含义就是让某个时间期限内,事件处理函数只执行一次
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay) // 简化写法
}
}
let timer = null //借助闭包
return function() {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay) // 简化写法
}
}
节流:(如上拉加载)节流就是保证一段时间内只执行一次核心代码
function throttle(fn,delay){
let valid = true
return function() {
if(!valid){
//休息时间 暂不接客
return false
}
// 工作时间,执行函数并且在间隔期内把状态位设为无效
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
let valid = true
return function() {
if(!valid){
//休息时间 暂不接客
return false
}
// 工作时间,执行函数并且在间隔期内把状态位设为无效
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
区别
防抖动是将多次执行变为最后一次执行
节流是将多次执行变成每隔一段时间执行
跨域
原因:浏览器“同源策略”
即同域名、同端口、同协议的才能互相获取资源
解决方法
jsonp
document.domain + iframe跨域
location.hash + iframe
window.name + iframe
postMessage跨域
跨域资源共享(CORS)
nginx代理跨域
nodejs中间件代理跨域
WebSocket协议跨域
回流重绘
回流
浏览器要花时间去渲染,当它发现了某个部分发生了变化并且影响了布局,就需要倒回去重新渲染
重绘
如果只是改变了某个元素的背景颜色或文字颜色等,不影响元素周围或内部布局,就只会引起浏览器的重绘
何时发生回流
(1)页面初始化的时候
(2)操作DOM的时候(增加或删除DOM元素)
(3)某些元素的尺寸改了(边距,填充,边框,宽高)
(4)CSS的属性发生变化(隐藏display:none)
(5)内容改变(文本改变或图片改变而引起的的计算值的宽高改变)
(6)浏览器窗口尺寸改变(当resize事件发生时)
(2)操作DOM的时候(增加或删除DOM元素)
(3)某些元素的尺寸改了(边距,填充,边框,宽高)
(4)CSS的属性发生变化(隐藏display:none)
(5)内容改变(文本改变或图片改变而引起的的计算值的宽高改变)
(6)浏览器窗口尺寸改变(当resize事件发生时)
如何减少回流
(1)不要逐个修改DOM样式,可以预先定义好css的class,然后修改DOM的className
,将多个需要进行相同操作的元素一次修改
(2)不要把DOM结点的属性值放在一个循环里当成循环的变量
(3)当动画元素使用fixed或absolute的position时(脱离了文档流),那么在修改他们的CSS时不会发生回流
(4)不要使用table布局,因为可能很小的一个改动都会造成整个table的重新布局
(5)在内存中多次操作结点,完成后再添加到文档中去
(6)如果要对一个元素进行复杂的操作,可以先隐藏它(display:none),操作完成后再显示
(7)对于需要经常取出的引起浏览器重排的属性值,要缓存到变量中
,将多个需要进行相同操作的元素一次修改
(2)不要把DOM结点的属性值放在一个循环里当成循环的变量
(3)当动画元素使用fixed或absolute的position时(脱离了文档流),那么在修改他们的CSS时不会发生回流
(4)不要使用table布局,因为可能很小的一个改动都会造成整个table的重新布局
(5)在内存中多次操作结点,完成后再添加到文档中去
(6)如果要对一个元素进行复杂的操作,可以先隐藏它(display:none),操作完成后再显示
(7)对于需要经常取出的引起浏览器重排的属性值,要缓存到变量中
http
状态码
2
200:请求被正常处理
204:请求被受理但没有资源可以返回
3
301:永久性重定向
302:临时重定向
304:在缓存中有该资源,可以直接获取
401:请求需要认证
403:禁止访问(譬如可以是未登录时禁止)
404:服务器无法找到对应资源
403:禁止访问(譬如可以是未登录时禁止)
404:服务器无法找到对应资源
4
5
500:服务器内部错误
503:服务器超过最大负荷
503:服务器超过最大负荷
缓存
强制缓存:存是我们在第一次请求资源时在 http 响应头设置一个过期时间,
在时效内都将直接从浏览器进行获取,
常见的 http 响应头字段如 Cache-Control 和 Expires,cache-control级别更高
在时效内都将直接从浏览器进行获取,
常见的 http 响应头字段如 Cache-Control 和 Expires,cache-control级别更高
协商缓存:是我们通过 http 响应头字段 etag 或者 Last-Modified
等判断服务器上资源是否修改,如果修改则从服务器重新获取,
如果未修改则 304 指向浏览器缓存中进行获取
等判断服务器上资源是否修改,如果修改则从服务器重新获取,
如果未修改则 304 指向浏览器缓存中进行获取
输入url后
1.浏览器解析主机名
2.DNS进行域名解析,即将语义化的主机名转换成IP地址
3.浏览器获得端口号
4.浏览器根据得到的ip地址和端口号发起TCP连接
5.浏览器发起HTTP请求
6.浏览器读取服务器返回的响应报文
7.浏览器对返回的HTML进行渲染
8.浏览器断开TCP连接
2.DNS进行域名解析,即将语义化的主机名转换成IP地址
3.浏览器获得端口号
4.浏览器根据得到的ip地址和端口号发起TCP连接
5.浏览器发起HTTP请求
6.浏览器读取服务器返回的响应报文
7.浏览器对返回的HTML进行渲染
8.浏览器断开TCP连接
与https区别
1.HTTP 是不安全的,而 HTTPS 是安全的
2.HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
3.HTTP 无法加密,而HTTPS 对传输的数据进行加密
4.HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
2.HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
3.HTTP 无法加密,而HTTPS 对传输的数据进行加密
4.HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
https的请求流程
客户端(浏览器)向服务器请求https连接。
服务器返回证书(公钥)到客户端。
客户端随机的秘钥A(用于对称加密)。
客户端用公钥对A进行加密。
客户端将加密A后的密文发送给服务器。
服务器通过私钥对密文进行解密得到对称加密的秘钥。
客户端与服务器通过对称秘钥加密的密文通信。
服务器返回证书(公钥)到客户端。
客户端随机的秘钥A(用于对称加密)。
客户端用公钥对A进行加密。
客户端将加密A后的密文发送给服务器。
服务器通过私钥对密文进行解密得到对称加密的秘钥。
客户端与服务器通过对称秘钥加密的密文通信。
GET与Post
GET请求参数放在URL上,POST请求参数放在请求体里
GET请求参数长度有限制,POST请求参数长度可以非常大
POST请求相较于GET请求安全一点点,因为GET请求的参数在URL上,且有历史记录
GET请求能缓存,POST不能
GET请求参数长度有限制,POST请求参数长度可以非常大
POST请求相较于GET请求安全一点点,因为GET请求的参数在URL上,且有历史记录
GET请求能缓存,POST不能
HTTP2新特性
多路复用
服务端推送
新的二进制格式
header压缩
服务端推送
新的二进制格式
header压缩
vue
computed、methods和watch的区别
computed:是基于响应式依赖进行缓存的。何为响应式依赖呢?
例如声明在data中的变量既有响应式的性质,用通俗一点的话讲就是,
计算属性的触发条件是他的依赖变化了才会重新执行
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter
例如声明在data中的变量既有响应式的性质,用通俗一点的话讲就是,
计算属性的触发条件是他的依赖变化了才会重新执行
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter
watch:侦听器是vue提供的一个来响应数据的变化。
当需要在数据变化时执行异步或开销较大的操作时,选择watch会更合适。
当需要在数据变化时执行异步或开销较大的操作时,选择watch会更合适。
key
需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。
作用主要是为了高效的更新虚拟DOM。
作用主要是为了高效的更新虚拟DOM。
vue原理
1. new Vue() 首先执行初始化,对data执行响应化处理,这个过程发生在Observer中
2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在 Compile中
3. 同时定义一个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
4. 由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家Dep来管理多个 Watcher
5. 将来data中数据一旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数
2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在 Compile中
3. 同时定义一个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
4. 由于data的某个key在一个视图中可能出现多次,所以每个key都需要一个管家Dep来管理多个 Watcher
5. 将来data中数据一旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数
methods:就像我们写的普通函数一样,需要我们主动去调用才会执行
keep-alive
生命周期钩子函数
activated、deactivated
include: 字符串或正则表达式,只有名称匹配的组件会被缓存
exclude: 字符串或正则表达式,名称匹配的组件不会被缓存》
max: 数字,最多可以缓存多少组件实例
exclude: 字符串或正则表达式,名称匹配的组件不会被缓存》
max: 数字,最多可以缓存多少组件实例
属性
VUE组件data为什么必须是函数
1.Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,
那么状态变更将会影响所有组件实例,这是不合理的;
2.采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。
3.而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。
那么状态变更将会影响所有组件实例,这是不合理的;
2.采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。
3.而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。
diff
1.通过新旧虚拟DOM作对比(即diff),将变化的地方更新在真实DOM上
2.vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方。
3、vue中diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称为patch。
4、diff过程整体遵循深度优先、同层比较的策略;两个节点之间比较会根据它们是否拥有子节点或者文本节点做不同操作;
Vue性能优化
●路由懒加载
●keep-alive缓存页面
●使用v-show复用DOM
●v-for 遍历避免同时使用 v-if
●长列表性能优化
●事件的销毁
●图片懒加载
●第三方插件按需引入
●无状态的组件标记为函数式组件
●子组件分割
●变量本地化
●SSR
●keep-alive缓存页面
●使用v-show复用DOM
●v-for 遍历避免同时使用 v-if
●长列表性能优化
●事件的销毁
●图片懒加载
●第三方插件按需引入
●无状态的组件标记为函数式组件
●子组件分割
●变量本地化
●SSR
Vue3.0的新特性
虚拟DOM重写
基于Proxy的响应式系统
TypeScript + 模块化
基于Proxy的响应式系统
TypeScript + 模块化
vue-router
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,
不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;
同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;
不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;
同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;
1 $router.push() //调用方法
2 HashHistory.push() //根据hash模式调用,设置hash并添加到浏览器历史记录(添加到栈顶)(window.location.hash= XXX)
3 History.transitionTo() //监测更新,更新则调用History.updateRoute()
4 History.updateRoute() //更新路由
5 {app._route= route} //替换当前app路由
6 vm.render() //更新视图
2 HashHistory.push() //根据hash模式调用,设置hash并添加到浏览器历史记录(添加到栈顶)(window.location.hash= XXX)
3 History.transitionTo() //监测更新,更新则调用History.updateRoute()
4 History.updateRoute() //更新路由
5 {app._route= route} //替换当前app路由
6 vm.render() //更新视图
History:HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,
就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;
就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;
守卫
全局:
router.beforeEach
router.afterEach
router.beforeEach
router.afterEach
独享:
配置内beforeEnter
配置内beforeEnter
组件内:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
注册全局
自定义指令
Vue.directive('指令名', {
bind(el, binding) {
bind声明周期, 只调用一次,指令第一次绑定到元素时调用
},
inserted(el, binding) {
被绑定元素插入父节点时调用
},
update() {},
componentUpdated() {},
unbind() {}
});
bind(el, binding) {
bind声明周期, 只调用一次,指令第一次绑定到元素时调用
},
inserted(el, binding) {
被绑定元素插入父节点时调用
},
update() {},
componentUpdated() {},
unbind() {}
});
组件
install:function(Vue) {
Vue.component('组件名', 组件)
}
Vue.component('组件名', 组件)
}
过滤器
方法
export default {
install (Vue, options) {
Vue.prototype.$toTop = function () {
console.log('Plugin Test')
}
}
}
install (Vue, options) {
Vue.prototype.$toTop = function () {
console.log('Plugin Test')
}
}
}
vuex
五大核心属性:state,getter,mutation,action,module
axios
1. 基于 promise 的异步 ajax 请求库,支持promise所有的API
2. 浏览器端/node 端都可以使用,浏览器中创建XMLHttpRequests
3. 支持请求/响应拦截器
4. 支持请求取消
5. 可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
6. 批量发送多个请求
7. 安全性更高,客户端支持防御 XSRF,就是让你的每个请求都带一个从cookie中拿到的key,
根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,
这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
2. 浏览器端/node 端都可以使用,浏览器中创建XMLHttpRequests
3. 支持请求/响应拦截器
4. 支持请求取消
5. 可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
6. 批量发送多个请求
7. 安全性更高,客户端支持防御 XSRF,就是让你的每个请求都带一个从cookie中拿到的key,
根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,
这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
$nextTick
需要在视图更新之后,基于新的视图进行操作。
网络安全
常见
SQL注入
把SQL命令插入到表单或输入URL查询字符串提交,欺骗服务器达到执行恶意的SQL目的
XSS(Cross Site Script),跨站脚本攻击
攻击者在页面里插入恶意代码,当用户浏览该页之时,执行嵌入的恶意代码达到攻击目的
CSRF(Cross Site Request Forgery),跨站点伪造请求
伪造合法请求,让用户在不知情的情况下以登录的身份访问,利用用户信任达到攻击目的
把SQL命令插入到表单或输入URL查询字符串提交,欺骗服务器达到执行恶意的SQL目的
XSS(Cross Site Script),跨站脚本攻击
攻击者在页面里插入恶意代码,当用户浏览该页之时,执行嵌入的恶意代码达到攻击目的
CSRF(Cross Site Request Forgery),跨站点伪造请求
伪造合法请求,让用户在不知情的情况下以登录的身份访问,利用用户信任达到攻击目的
防止
不要信任任何外部传入的数据
针对用户输入作相关的格式检查、过滤等操作
不要信任在任何传入的第三方数据
使用 CORS,设置 Access-Control-Allow-Origin
更安全地使用 Cookie
设置Cookie为HttpOnly,禁止了JavaScript操作Cookie
防止网页被其他网站内嵌为iframe
服务器端设置 X-Frame-Options 响应头,防止页面被内嵌
针对用户输入作相关的格式检查、过滤等操作
不要信任在任何传入的第三方数据
使用 CORS,设置 Access-Control-Allow-Origin
更安全地使用 Cookie
设置Cookie为HttpOnly,禁止了JavaScript操作Cookie
防止网页被其他网站内嵌为iframe
服务器端设置 X-Frame-Options 响应头,防止页面被内嵌
css
概念
盒子模型
概念
包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素
注意点
css 外边距合并(叠加)
box-sizing
content-box
默认值:即总宽度=margin+border+padding+width
border-box
即总宽度=margin+width
inherit
规定应从父元素继承 box-sizing 属性的值
盒模型做三角形
width : 0;height: 0;
border : 100px solid transparent;
border-top : 100px solid blue;
border : 100px solid transparent;
border-top : 100px solid blue;
CSS3单位
绝对单位
px
相对单位
rem
相对根节点html字体大小来计算
em
基准点为相对父节点字体的大小
%
相对于父元素的大小设定的比率
视窗单位
vw/vh
视窗宽度/高度的百分比,1vw代表视窗宽度/高低的1%
@@keyframes 动画名称{
0%{}
100%{}
}
0%{}
100%{}
}
vmin/vmax
当前vw和vh中较小/较高的一个值
css选择符
id选择器
类选择器
标签选择器
子代选择器
ul>li
后代选择器
ul li
属性选择器
a[rel="external"]
伪类选择器
a:hover,li:nth-child
通过给父级元素添加伪类after,并添加clear: both;属性
css优先级
同权重: 内联样式(标签内部)> 嵌入样式表(当前文件中)>外部样式(外部文件中)
!important >id >class >tag
!important 比内联优先级高
css3新特性
transition
CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
animation
动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)
transform
transform:rotate(30deg);
transform:translate(30px,30px);
transform:scale(.8);
常见问题
水平垂直居中
知宽高
设置父元素为相对定位,给子元素设置绝对定位,top: 0; right: 0; bottom: 0; left: 0; margin: auto;
置父元素为相对定位,给子元素设置绝对定位,left: 50%; top: 50%; margin-left: --元素宽度的一半px; margin-top: --元素高度的一半px;
不知宽高
设置父元素为相对定位,给子元素设置绝对定位,left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%);
设置父元素为flex定位,justify-content: center; align-items: center;
清除浮动的方法
父级添加overflow: auto
浮动元素后面加块级元素,并添加clear: both;属性
文字超出省略号
一行
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
white-space:nowrap;
text-overflow:ellipsis;
多行
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
es6新特性
const 与 let 变量
模板字面量
模板字面量用倒引号 ( `` )
${ } 表示的占位符
解构
数组解构
const point = [10, 25, -34];
const [x, y, z] = point;
console.log(x, y, z);
const [x, y, z] = point;
console.log(x, y, z);
对象解构
const gemstone = {
color: 'rose',
karat: 21.29
};
const {color, karat} = gemstone;
console.log(color, karat);
color: 'rose',
karat: 21.29
};
const {color, karat} = gemstone;
console.log(color, karat);
循环
for...of循环
遍历数组的value
for...in循环
是遍历数组、对象的key
展开运算符
...
箭头函数
与普通函数区别:this指向不一样
普通函数的this指向调用它的那个对象
箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
new Set()
Set()是指有序列表集合 (set中的元素是没有重复的)
add()
delete()
clear()
has()
new Map()
用来存放键值对的集合 key/value
set(key:value)
get(key)
has(key)
clear()
promise
3 种状态:pending、fulfilled 或 rejected。
解决的痛点
回调地狱,代码难以维护
promise可以支持多个并发的请求,获取并发请求中的数据
promise可以解决可读性的问题,异步的嵌套带来的可读性的问题
promise可以解决信任问题,即先后执行顺序的问题
Promise 常用的方法
Promise.race
类方法,多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败
Promise.all
类方法,多个 Promise 任务同时执行 ,如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果
async/await定义了异步函数,并在其内部可通过await等待promise对象,阻塞后续的执行
js
js类型
类型
Undefined、Null、Boolean、Number、String、Object、Symbol
判断方法
typeof
null,arr,obj都为object
instanceof
instanceof不能识别出基本的数据类型,
但是可以识别出Array、Object、Function,返回布尔
但是可以识别出Array、Object、Function,返回布尔
arr instanceof Array
obj instanceof Object
fun instanceof Function
constructor
null、undefined没有construstor方法,
因此constructor不能判断undefined和null,返回布尔
因此constructor不能判断undefined和null,返回布尔
num.constructor === Number
str.constructor === String
Object.prototype.toString.call()
返回[object 类型]
Object.prototype.toString.call(num)
Object.prototype.toString.call(str)
数据类型转换
转为字符串
.toString()
不可以转null和underfined
String()
都能转
隐式转换
num + ""
转为数值类型
Number()
如果要转换的字符串中有一个不是数值的字符,返回NaN
parseInt(),parseFloat()
如果第一个字符是数字会解析知道遇到非数字结束
如果第一个字符不是数字或者符号就返回NaN
隐式转换
str-0或者+str
转化为布尔
Boolean()
0 ''(空字符串) null undefined NaN 会转换成false
其它都会转换成true
隐式转换:!!x
object与string
obj-->string
JSON.stringify(obj)
string-->obj
JSON.parse(str)
数组的对象方法
会改变原来数组的有
push(x)
添加元素到数组末尾
pop()
删除数组末尾元素
shift()
删除数组头部元素
unshift(x)
向数组头部添加一个元素
reverse()
颠倒数组中元素的顺序
splice( 位置,几个)
删除元素,并向数组添加新元素
sort()
对数组进行排序
不会改变原来数组的有
slice()
从数组中返回特定的元素
join()
把数组所有元素放入一个字符串,元素通过指定分割符进行分隔
concat()
合并两个或多个数组,并合并
toString()
把数组转化为字符串,返回结果
valueOf()
-返回数组对象的原始值
every( item, index)
检测数组元素的每个元素是否都符合条件,返回布尔
some( item, index)
检测数组元素中是否有元素符合指定条件
filter()
检测数组元素,并返回符合条件所有元素的数组
map()
通过指定函数处理数组的每个元素,并返回处理后的数组
原型与原型链
原型
每个函数都有一个prototype属性,这个属性指向的就是原型对象. 实例有一个__proto__指向它构造函数的原型对象.
原型链
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
继承
原型链继承
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
借用构造函数继承
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
组合继承(组合原型链继承和借用构造函数继承)
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
原型式继承
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
2、无法实现复用。(新实例属性都是后面添加的)
寄生式继承
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
寄生组合式继承
js对象拷贝
浅拷贝
var obj = { foo: "foo", bar: "bar" };
var copy = { ...obj };
var copy = { ...obj };
var obj = { foo: "foo", bar: "bar" };
var copy = Object.assign({}, obj);
var copy = Object.assign({}, obj);
深拷贝
JSON.parse(JSON.stringify(obj));
区别
深拷贝:新对象改变,老对象始终不会改变
浅拷贝:第一层不会改变,大于一层会随新对象改变
浅拷贝:第一层不会改变,大于一层会随新对象改变
event-Loop
主线程
就是访问到的script标签里面包含的内容,或者是直接访问某一个js文件的时候,里面的可以在当前作用域直接执行的所有内容
宏队列
setTimeout、setInterval、setImmediate、I/O
微队列
promise.then、process.nextTick
执行顺序
1、先执行主线程
2、遇到宏队列(macrotask)放到宏队列(macrotask)
3、遇到微队列(microtask)放到微队列(microtask)
4、主线程执行完毕
5、执行微队列(microtask),微队列(microtask)执行完毕
6、执行一次宏队列(macrotask)中的一个任务,执行完毕
7、执行微队列(microtask),执行完毕
8、依次循环。。
2、遇到宏队列(macrotask)放到宏队列(macrotask)
3、遇到微队列(microtask)放到微队列(microtask)
4、主线程执行完毕
5、执行微队列(microtask),微队列(microtask)执行完毕
6、执行一次宏队列(macrotask)中的一个任务,执行完毕
7、执行微队列(microtask),执行完毕
8、依次循环。。
闭包
概念
闭包就是能读取其他函数内部变量的函数。
优点
1.避免全局变量的污染
2.希望一个变量长期存储在内存中(缓存变量)
2.希望一个变量长期存储在内存中(缓存变量)
缺点
内存泄露(消耗)
常驻内存,增加内存使用量
常驻内存,增加内存使用量
js中this指向的理解
1,函数是否是new中调用,如果是,则this绑定在新创建的这个对象上
2,是否使用了call,bind,appliy,如果是的话则this绑定在传入的那个函数当中
3,是否是在某个上下文对象中调用(隐式调用),如果是则this绑定是那个上下文对象,如aa.bb(),bb函数中的this绑定的就是aa
4,如果是箭头函数,则this继承的是外层代码块中的this
5, 以上都不是的话,则在严格模式下,this就是undifined,非严格模式下,this是window。
6,如果bind,call,appliy传入的参数是null或者undifined的话,那么this的指向就跟5是一样的
2,是否使用了call,bind,appliy,如果是的话则this绑定在传入的那个函数当中
3,是否是在某个上下文对象中调用(隐式调用),如果是则this绑定是那个上下文对象,如aa.bb(),bb函数中的this绑定的就是aa
4,如果是箭头函数,则this继承的是外层代码块中的this
5, 以上都不是的话,则在严格模式下,this就是undifined,非严格模式下,this是window。
6,如果bind,call,appliy传入的参数是null或者undifined的话,那么this的指向就跟5是一样的
call、bind、apply的相同点与不同点
相同点:
1,都是用来改变函数this指向的
2,第一个参数都是用来指定this指向的上下文、
3,都可以利用后续参数传参
1,都是用来改变函数this指向的
2,第一个参数都是用来指定this指向的上下文、
3,都可以利用后续参数传参
不同点:
1,bind的调用不可以直接调用必须,bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以,call跟apply都可以直接调用
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用
2,call的传参方式是一个一个的传,列如x.call(this,a1,a2)
3, apply的传参方式是数组,例如x.apply(this,[a1,a2]);
4, bind的传参方式是x.bind(this,a1,a2)()还可以是x.bind(this)(a1,a2);
1,bind的调用不可以直接调用必须,bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以,call跟apply都可以直接调用
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用
2,call的传参方式是一个一个的传,列如x.call(this,a1,a2)
3, apply的传参方式是数组,例如x.apply(this,[a1,a2]);
4, bind的传参方式是x.bind(this,a1,a2)()还可以是x.bind(this)(a1,a2);
DOM 事件有哪些阶段
1:一开始从文档的根节点流向目标对象(捕获阶段)
2:然后在目标对向上被触发(目标阶段)
3:之后再回溯到文档的根节点(冒泡阶段).
2:然后在目标对向上被触发(目标阶段)
3:之后再回溯到文档的根节点(冒泡阶段).
webpack
常见的Loader
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
常见的Plugin
define-plugin:定义环境变量
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
构建流程
1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
3.确定入口:根据配置中的 entry 找出所有的入口文件;
4.编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,
再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,
再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
3.确定入口:根据配置中的 entry 找出所有的入口文件;
4.编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,
再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,
再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
如何提高webpack的构建速度
1.多入口情况下,使用CommonsChunkPlugin来提取公共代码
2.通过externals配置来提取常用库
3.利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会
修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
4.使用Happypack 实现多线程加速编译
5.使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
6.使用Tree-shaking和Scope Hoisting来剔除多余代码
2.通过externals配置来提取常用库
3.利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会
修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
4.使用Happypack 实现多线程加速编译
5.使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度
6.使用Tree-shaking和Scope Hoisting来剔除多余代码
怎么配置单页应用?怎么配置多页应用?
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可,这里不再赘述
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。
多页应用中要注意的是:
1.每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
2.随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。
多页应用中要注意的是:
1.每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表
2.随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置
vue与react区别
1.React严格上只针对MVC的view层,Vue则是MVVM模式
2.virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.
而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
3.组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即'all in js';
Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
4.数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
5.state对象在react应用中不可变的,需要使用setState方法更新状态;
在vue中,state对象不是必须的,数据由data属性在vue对象中管理;
2.virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.
而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
3.组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即'all in js';
Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
4.数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
5.state对象在react应用中不可变的,需要使用setState方法更新状态;
在vue中,state对象不是必须的,数据由data属性在vue对象中管理;
0 条评论
下一页