文章开头: 这仅是我对前端知识的浅薄的个人理解,请勿作为学习依据,也欢迎所有人相互交流,共同学习
前端知识点
1.前端缓存问题 缓存分为强缓存和协商缓存,为了节省资源提高速度。
强缓存即状态码200 页面按步骤进行资源下载和解析
协商缓存 阅览器记录下首次请求后服务端返回得etag,last-Modifed字段字段 在下次进行请求时候会将这些字段放入请求头中的 if-none-match if-modified-since 字段中,服务器接收请求后会对照上一次发送的字段,如果值相同则会进入协商缓存,状态码304
2.状态码
301 302之前的异同: 二者都是重定向,301是永久重定向而302是临时重定向,安全性上301永久重定向会优秀很多,301适合做域名更改和网站迁移,302适合在不存在页面是返回首页,当用户未登陆是访问了用户中心等情景。
3.阅览器解析资源的过程
a.首先生成一个httpRequest对象,如果有本地缓存就会去解析缓存
b.查询本地host文件 > 本地的DNS服务器 > 域服务器 > 查到对应的IP地址并缓存
c.阅览器向WEB发出请求,通过三次握手建立连接,服务器对请求进行处理
d.解析html,构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树
解析过程中,浏览器首先会解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。这个过程涉及到两个概念:reflow(回流)和repain(重绘)
在浏览器显示HTML时,会获取其他地址内容的标签。浏览器会发送一个获取请求来重新获得这些文件。比如我要获取外图片,CSS,JS文件等浏览器自上而下执行,过程中如遇到css、图片等,请求是异步的当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。因为JS有可能会修改DOM;所以在编写 代码时尽可能的把js写在html的底部,等html主体和css加载完之后再进行加载js;
4.深拷贝与浅拷贝
深拷贝函数
function deepCopy(obj) {
let res = []
for (item in obj) {
if(typeof(obj[item]) == 'object') {
deepCopy(obj[item])
} else {
res[item] = obj[item]
}
}
return res
}
JSON.parse / JSON.stringfy 深拷贝
浅拷贝 Object.assign() 当拷贝对象只有一层时 该方法是深拷贝
5.跨域问题
a. jsonp 与后端同学商议好一个回调函数名称,在跨域标签中拼接上这个回调函数 这个方法只支持get求情。 b. 服务器代理, 服务器与服务器之间不存在跨域问题 c. CORS 目前最常见的跨域方式
请求头部添加了origin字段表示来源 同时返回头中包含Access-Control-Allow-Origin表示允许访问的源 默认情况下不会发送缓存,如果想要携带缓存需要添加withCredentials属性
6.判断一个变量是否是数组
var a = []
a instanceof Array
a.constructor === Array
Array.prototype.isProtypeOf(a)
Object.getPrototypeOf(a) === Array.prototype
Object.prototype.toString.apply(a) === '[object Array]'
Array.isArray(a)
7.继承问题
a.构造函数继承
问题在于使用构造函数继承之后子类的原型是子类本身,在父类原型上的方法就得不到了
b.原型继承
问题在于原型继承后子类实例修改属性后会对父类属性也进行修改,当再次创建子类实例之后修改的属性值依然在,而我希望每次子类的实例都是父类最初的样子
组合继承 = 构造函数继承 + 原型继承
function parent(name, age) {
this.name = name
this.age = age
this.gh = ['sing','dance']
}
parent.prototype.sayName = function() {
console.log(this.name)
}
let p1 = new parent('gh', 24)
p1.sayName();
let p2 = new parent('gh2',20)
function son(name, age, sex) {
this.sex = sex
// parent.apply(this,[name, age])
}
son.prototype = new parent()
var s1 = new son('s1',20,1)
var s2 = new son('s2',24,2)
s1.gh.push('213213')
console.log(s1.gh, s2.gh)
8.前端安全问题
XSS攻击 juejin.im/post/684490…
CRSF 伪造身份攻击
9.git 命令
rebase 和 merge 区别
- 原生Ajax请求
a.创建XMLhttpRequest 对象
var xmlhttp = new XMLhttpRequest()
b.向服务器发出请求,传递参数
open(method, url, async)
c.
xmlhttp.send()
d. xmlhttp.onreadystatechange = callback
xmlhttp.onreadystatechange = function() {
if(xmlhttp.state == 200 && xmlhttp.readyStatus == 4) {
do something...
}
}
get
xmlhttp = new XMLHttpRequest()
xmlhttp.open('get','url?params1=xxx&¶ms2=xxxx')
xmlhttp.send()
xmlhttp.onreadystatuschange = function() {
...
}
post
xmlhttp = new XMLHttpRequest()
xmlhttp.open("post", "url")
xmlhttp.setRequestHeader('content-type','...')
xmlhttp.send('params1=xxx&¶ms2=xxxx')
xmlhttp.onreadystatuschange = function() {
...
}
11.节流防抖
function debounce(fn, delay) {
var timer = null
return function(){
var context = this, args = arguments
clearTimeout()
timer = setTimeout(()=> {
fn.apply(context,arguments)
}, delay)
}
}
function throttle(fn, delay) {
var last = 0
return function() {
var context = this, args = arguments
var now = new Date()
if(now - last > delay) {
fn.apply(context,arguments)
last = now
}
}
}
12.双向绑定原理
var obj = {};
Object.defineProperty(obj, 'name', {
get: function() {
console.log('我被获取了')
return val;
},
set: function (newVal) {
console.log('我被设置了')
}
})
obj.name = 'fei';//在给obj设置name属性的时候,触发了set这个方法
var val = obj.name;//在得到obj的name属性,会触发get方法
13.js作用域 www.cnblogs.com/yeyuyuni/p/…
var i = 10
function a() {
i = 20
for(var i = 0; i<6; i++) {
console.log(i)
}
console.log(this.i, i)
}
a()
console.log(i)
依次输出为 0,1,2,3,4,5 10,6 10
var foo = {n:1};
(function (foo){
var foo ;
foo.n = 3;
console.log(foo.n) // 3
var foo = {n:2}
console.log(foo.n) // 2
})(foo);
console.log(foo.n) // 3
当变量是引用数据类型会发生改变 所以最后会输出3
14.一个页面时钟的JS
setInterval(()=>{
var date = new Date()
var day = date.getDate()
var year = date.getFullYear()
var month = date.getMonth()+1 // 月份要加1
var seconds = date.getSeconds()
var hours = date.getHours()
var min = date.getMinutes()
console.log( `${year}年${month}月${day}日${hours}:${min}:${seconds}`)
},1000)
15.一次flex布局的复习
设置在容器上的属性 flex-direction, flex-wrap, flex-flow, justify-content, align-items, align-content
flex-flow = flex-direction + flex-wrap align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线则不起作用
设置在项目上 order 排序
flex-grow 放大比例
flex-shrink 缩小比例
flex-basis 分配空间
flex 等于上述三者之和
align-self 使项目有单独的对齐方式
- 兼容问题
- css选择器
a[src^='http'] a[src$='http'] a[src*='http'] 上述分别表示 选择带有src属性分别是以http开头,结尾和存在http的a标签
加号选择器 (a + p)表示所有在a标签后面的p标签
子类选择器 > div>p 表示 div标签下的子类p标签
p:first-of-type
p:last-of-type
选择父元素中第一个p标签,最后一个p标签的每个p元素
p:nth-child(n) 选择p标签下的第n个元素
p:empty 选择p元素下的空标签
input:enabled 选择每个启用的input元素。
input:disabled 选择每个禁用的input 元素
input:checked 选择每个被选中的input 元素。
18.VUE中使用JSONP进行跨域
1.安装依赖 npm install vue-jsonp
2.导入jsonp
import VueJsonp from 'vue-jsonp'
Vue.use(VueJsonp)
3.let url = 'xxxx' this.jsonp(url, params) .then(res=>{}) .catch(rej=>{})
- opacity visibility display
a.display:none 会重排
b.如果父类设置opacity:0(子类opcacity:1)不显示子类
如果父类设置visibility:hidden (子类visibility: visible;)显示子类
c.visibility: visible 后不会触发事件 而opacity:0会触发事件(点空白也能触发事件)
20.line-height:150% 和 line-height:1.5
父元素设置字体20px, 子元素字体14px 前者的行高30px, 后者21px 个人理解就是百分号是计算父类,而无单位时计算子类
21.清浮动
1.最后位置加入div标签 样式clear:both
2.父类伪元素 .clearfix:after{ content: ""; display: block; clear:both; }
3.父类overflow:hidden
22 generator函数
function* gen() {
yield 'hello'
yield 'world'
return 'ending'
}
let it = gen()
it.next() // {value: "hello", done: false}
it.next() // {value: "world", done: false}
it.next() // {value: "ending", done: true}
it.next() // {value: undefined, done: true}
第一次执行next()到yield表达式处,将表达式的值作为返回值的value 执行到最后将return返回值作为value 如果next()有参数,参数将替代value
function* g(x) {
let y = 2 * (yield (x + 1))
let z = yield (y / 3)
z = 88
return x + y + z
}
let i = g(5)
// i.next() // 6
// i.next(3) // 2
// i.next() // 6 + 88 + 5
24.async,await
三种方式 promise, generator, async&await
function bypromise() {
promiseFn().then(()=>{
//...
})
}
function* bygenerator() {
const res = yield promiseFn()
return res
}
let g = bygenerator()
g.next().value.then()
async function byasync() {
const res = await promiseFn()
return res
}
let async = byasync()
async.then()
25.github.com/AkazaAkalin…
文件名称为test的文件 实现了一个波纹点击按钮
26.css3
1.animation: 动画效果 使用@keyframes {}创建动画 animation-fill-mode: forwards 停在最后一帧 animation-direction规定动画是否在下一周期逆向地播放。默认是 "normal"。
2.媒体查询 @media screen and (min-width: 480px) { body { background-color: lightgreen; } } 27.call apply bind function () { return Array.prototype.slice.call(args) //把参数变成数组 }
var numbers = [5, 6, 2, 3, 7]; var max = Math.max.apply(null, numbers); // 7 找到一个数组的最大数
var a = {
name: 'guohua',
say: function() {
console.log('hello guohua')
}
}
function bar(name) {
console.log(name)
console.log(this.name)
this.say()
}
bar.call(a,'ok')
28.事件冒泡和捕获
冒泡由内向外,捕获由外向内、 JS事件分为三个阶段: 捕获阶段,处理目标阶段和冒泡阶段 先进行捕获阶段,最后进行冒泡阶段 addEventListener 第三个参数默认值false 代表默认状态下事件在冒泡阶段处理,以便兼容性提升 e.stopPropagation()阻止冒泡和捕获行为
//有外向内是div1,div2,div3
odiv1.addEventListener('click',function(){
console.log('hello div1')
},true)
odiv1.addEventListener("click",function(){
console.log('div1');
},true)
odiv2.addEventListener("click",function(e){
console.log('div2');
},false)
odiv3.addEventListener("click",function(e){
console.log('div3');
e.stopPropagation();
},false)
前面两个是捕获事件流中处理 后面两个在冒泡事件流处理 div3中阻止了冒泡 依次输出为 hello div1, div1,div3
- promise 的then 和catch 之所以写在原型上,为了让实例能够使用该方法,(实例与构造函数的原型链接而不是与构造函数进行连接)
30.下拉列表(vue代码片段)
// getdata() 请求数据, dataList是列表数据, isLoading加载中提示,isEnd到达底端提示
window.onscroll = () =>{
let clientHeight = document.documentElement.clientHeight;//可视区域高度
let scrollTop = document.documentElement.scrollTop;//当前滚动高度
let scrollHeigth = document.documentElement.scrollHeight;//滚动条可滚动高度
// console.log(clientHeight,scrollTop,scrollHeigth)
if(clientHeight+scrollTop>=scrollHeigth && !this.isLoading && this.dataList.length !=25){
this.listStart+=10;
this.getData();
this.isLoading = true;
this.isEnd = false;
}
if(clientHeight+scrollTop>=scrollHeigth-10 && this.dataList.length >= 25){
this.isLoading = false;
this.isEnd = true;
}
if(!(clientHeight+scrollTop>=scrollHeigth-10 && this.dataList.length >= 25)){
this.isEnd=false;
}
}
31.vue 监听数组
this.list.unshift({id:this.id,name:this.name});
this.text.splice(0, 1, '2')
this.$set(this.text, 0, '123')
this.text = ['2','2','3','4']
32 函数提升和变量提升
console.log(a);
var a=1;
console.log(a);
function a(){console.log(2);}
console.log(a);
var a=3;
console.log(a);
function a(){console.log(3);}
// a();
console.log(a);
函数提升会优先于变量提升上面代码等价于
function a(){console.log(3);}
console.log(a);
a = 1
console.log(a);
console.log(a);
a = 3
console.log(a);
console.log(a);
- new
function O(name) {
this.name = name
}
function _new() {
let obj = {}
console.log(arguments)
let constructorFun = [].shift.call(arguments)
obj.__proto__ = constructorFun.prototype
constructorFun.apply(obj, arguments)
return obj
}
1.创建一个空对象obj
2.构造函数剃掉第一个参数
3.空对象obj的__proto__指向构造函数的prototype
4.obj使用构造函数的参数并返回obj
- 两列布局 三列布局的方式
<div class="box">
<div class="left">CSS + > 选择器</div>
<div class="right">权重问题</div>
</div>
<style>
*{
margin: 0;
padding: 0;
}
/* 弹性布局 flex 属性 */
/* .box{
display: flex;
}
.left{
height: 200px;
width: 150px;
background-color: #696969;
}
.right{
height: 200px;
flex: 1;
background-color: #708708;
} */
/* float:left + margin-left */
/* .left{
height: 200px;
width: 150px;
background-color: #696969;
float: left;
}
.right{
height: 200px;
background-color: #708708;
margin-left: 150px;
} */
/* 浮动 + BFC */
/* .left{
height: 200px;
width: 150px;
background-color: #696969;
float: left;
}
.right{
height: 200px;
background-color: #708708;
overflow: hidden;
} */
</style>
flex三列布局
<div class="box">
<div class="left">1111111111111</div>
<div class="mid">flex 属性是 flex-grow flex-shrunk flex-basis 三个属性之和
flex-basis 会覆盖掉元素的width属性
flex: 1 代表 flex-grow flex-shrunk 的值都是1 既该元素空间随着剩余空间伸缩
</div>
<div class="right">33333333333333</div>
</div>
*{
padding: 0;
margin: 0;
}
.box{
display: flex;
}
.left{
height: 200px;
width: 200px;
background-color: #748129;
flex: 0 300px;
}
.mid{
height: 200px;
background-color: #910473;
flex: 1;
}
.right{
height: 200px;
width: 200px;
background-color: #148623;
flex: 0 300px;
}
</style>
三列布局也可以将两端绝对定位 中间元素设置左右边距
- BFC问题
a.BFC触发方式 : overflow不为visible, float不为none position的值fixed或者absolute
b.生成BFC这样的特殊区域之后会有以下几点特性
(1).该区域margin与其他区域避免混叠
(2).该区域的与包含改块的父级对齐
(3).每个BFC之间不会发生重叠 (适用于两列布局)
(4).计算高度时,BFC也参与计算 (适用于清除浮动)
- VUE监听数组几种方法
双向绑定原理不适用于数组,VUE中对数组的修改不能够直接修改,有以下几点方法
1.splice 替换// this.text.splice(0, 1, '2')
2.$set 方法 // this.$set(this.text, 0, '123')
- 数组的方法
array 列举以下几种
1.push pop 在队尾加入/在队尾去除
2.splice slice 替换/截取
3.sort reverse 排序和倒置
4.join concat 数组拼接成字符串, 数组和数组之间拼接
5.shift unshift 删除点数组的第一个元素, 在数字头部插入元素
38.http 1.1 2.0
1.http1.1 相对于http1.0
a.增加了缓存处理
b.增加了状态码
c.添加了host头部
d.长连接,一个TCP连接上可以进行多次http请求
39.VUE 虚拟DOM
虚拟DOM的最大优势在于使用了Vnode 虚拟节点,每当更新DOM时,新旧Vnode进行对比修改 使用Diff算法修改DOM,提升性能。
40.条件断点调试
cloud.tencent.com/developer/a…
41.正则表达式
- VUE事件总线
a.在VUE原形上定义一个事件总线,并初始化为一个new Vue()(在main.js中)
vue.prototype.$Eventbus = new Vue()
b.创建一个bus.js,引用VUE 导出一个事件总线对象, 名为EventBus
import Vue from 'vue'
export const EventBus = new Vue()
c.事件的发送和接收。在使用事件总线时, 先引用
import { EventBus } from "../Bus.js";
EventBus.$emit('emit事件名',数据)
EventBus.$on('emit事件名',数据)
- VUE nextTick
VUE的主要特色就是数据驱动DOM变化,但这一个变化是异步的。数据更新就会出现以下问题
<span @click='click'>{{a}}</span>
data:{
a:1
},
methods:{
click(){
this.a = 'hello'
console.log(document.querySelector('span').innerHTML)
}
}
上述代码,点击span后页面的1会变为hello,但是控制台输出的仍是1,因为DOM变化是异步的,Vue 实现的响应式并不是数据发生变化之后视图立即变化。
<span @click='click'>{{a}}</span>
data:{
a:1
},
methods:{
click(){
this.a = 'hello'
this.$nextTick(()=>{
console.log(document.querySelector('span').innerHTML)
})
}
}
添加$nextTick之后,在其回调函数里面就会得到更新后的DOM
44.JS 如何实现多线程
JS worker 能够创建一个线程
1.
var worker = new Worker("index.js")
// 引入文件必须是网络上的文件,且满足同源策略
2.
主线程页面和线程JS之间通过postMessage和onmessage方法来通信
3.关闭线程时
//主线程中
worker.terminate()
//worker线程
self.close()
- 括号表达式合法判断
public class check (string s){
Stack<Character> stack = new Stack<Character>();
if (str.length() % 2 == 1) {
System.out.println("No");
}//奇数不匹配
} else {
for (int i = 0; i < s.length(); i++){
stack = new Stack<Character>();
for (int i = 0; i < str.length(); i++) {
if (stack.isEmpty()) {
stack.push(str.charAt(i)); // 当前栈是空的 存入当前位置的字符
} else if ((stack.peek() == '[' && str.charAt(i) == ']')
|| (stack.peek() == '(' && str.charAt(i) == ')')) {
stack.pop(); // 满足上面的条件 表示相邻的两个字符是一对匹配的括号 进行出栈操作
} else {
stack.push(str.charAt(i));
}
}
}
function STACK() {
let stack = []
this.length = ()=>stack.length
this.push = (value) => {
stack.push(value)
}
this.pop = () => {
stack.pop()
}
this.top = () => {
return stack[stack.length-1] || 'empty'
}
this.toString = () => {
return stack.reverse().join('')
}
}
'()'
function check(str) {
if(str.length %2 === 1) {
return false
} else {
let temp = new STACK()
for(let i = 0; i < str.length; i++){
if(!temp.length()) {
temp.push(str[i])
} else {
if(temp.top() === '('&& str[i] === ')'|| temp.top() === '{'&& str[i] === '}'){
temp.pop()
} else {
temp.push(str[i])
}
}
}
if(temp.length() === 0 ) return true
else return false
}
}
check('()')
46.JS实现Stack
function STACK() {
let stack = []
this.length = ()=> {
return stack.length
}
this.push = (value) => {
stack.push(value)
}
this.pop = () => {
stack.pop()
}
this.top = () => {
return stack[stack.length-1] || 'empty'
}
this.toString = () => {
return stack.reverse().join('')
}
}
- 响应头和请求头的参数以及相关知识
请求头
1.Accept-xxx Accept-Charset, Accept-Encoding, Accept-Language, 表示和接受的文件类型,编码方式,可接受的语言列表
2.cache-control 指定是否使用缓存机制
3.cookie
4.origin 针对于一个跨域请求,配置请求的源,为服务器判断提供依据
5.If-Modified-Since, If-None-Match 缓存字段
响应头
1.Access-Control-Allow-Origin 指定跨域资源共享的源
2.cache-control 指定是否使用缓存机制
3. Expires 过期时间
4. Last-Modified,Etag 缓存字段
5.Content-Type... 当前响应的类型
48.库里化函数
如果一个函数fun的参数有多个,例如
function fun(a,b,c,d) {
// do something
}
我们想创造一个函数curry,把多个参数分离出来达到fun(a,b,c,d) = curry(a)(b)(c)(d) 我们的思路就是curry函数返回一个匿名函数 在匿名函数中逐个收集参数,当参数的数量达到fun函数的参数数量时,引用fun并执行
function curry(fn, args) {
let args = args || []
let len = fn.length
return function () {
var newArgs = [].slice.call(arguments)
var allArgs = [...args,...newArgs]
// 当前参数数量不够fun参数数量时,调用本身来收集参数,把收集的参数传到下一轮做参数
if(allArgs.length < len) {
return curry.call(this, fun, allArgs)
} else {
return fn.apply(this, allArgs)
}
}
}
function fun(a,b) { return a + b}
var test = curry(fun)
test(1)(2) == fun(1,2)
49.多维数组化作一维
var arr = ['1',['2',['3','4']]]
function tool(arr) {
return arr.reduce((total, item) => {
if(Array.isArray(item)) {
total = total.concat(tool(item))
} else {
total.push(item)
}
return total
},[])
}
let res = tool(arr)
50.border: transparent 实现CSS三角形和梯形
.triangle {
width: 0px;
height: 0px;
border-top: 10px solid red;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
梯形设置width即可
- 用js将 386485473.88 转换为 386,485,473.88(千位分割符):
(386485473.88).toLocaleString('en-US') // "386,485,473.88" 由掘金大神 (sRect)补充
52 MVC MVVM
MVC
model 处理数据逻辑部分 通常负责存取数据库的数据
view 视图层 展示数据
controller 处理交互功能,控制展示逻辑,控制用户输入并发送数据
MVVM 数据层和视图层 核心是数据驱动 ViewModel
ViewModel向上与视图层View进行双向数据绑定,向下与Model通过接口请求进行数据交互,起到承上启下的作用。
53.vue slot
<div id="app">
<child-component>
<h2 slot="header">标题</h2>
<p slot="header">正文内容</p>
<p>更多正文内容</p>
<div slot="footer">底部信息</div>
</child-component>
</div>
<script>
Vue.component('child-component', {
template: '\
<div class="component">\
<div class="header">\
<slot name="header"></slot>\
</div>\
<div class="main">\
<slot></slot>\
</div>\
<div class="footer">\
<slot name="footer"></slot>\
</div>\
</div>'
});
var app = new Vue({
el: '#app'
})
</script>
54.线程与进程
- 1px边框
出现问题的原因是像素比 = 物理像素/CSS像素
解决方法
1.boxshadow
box-shadow: 0 -1px 1px -1px #e5e5e5, //上边线
1px 0 1px -1px #e5e5e5, //右边线
0 1px 1px -1px #e5e5e5, //下边线
-1px 0 1px -1px #e5e5e5; //左边线
2.伪元素
:: after{
content:'';
width:100%;
height:1px;
transfrom: scale(1, 0.5)
position: absolute;
top:0;
left:0;
}
56.watch computed
watch 监听属性的值 当监听值发生变化之后执行handler函数,函数接受两个参数 oldval和 newval
官网给出的示例 watch分别监听 firstname lastname 在handler中修改fullname 相比之下情景中更适合使用computed
watch: {
firstname: {
handler: function(val){
this.fullname = val + this.lastname
},
// deep
// immediate:true
},
lastname: function(val){
this.fullname = this.firstname + val
},
},
computed: {
fullname: function() {
return this.firstname + this.lastname
}
},
computed中定义的值在一开始就被计算了一次 而watch 只在当监听值改变时发生变化 watch中三个属性 handler deep immediate 设置immediate就能够立即观察并发生变化
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log("wut");
}
a 是长度1的数组,==左右的转换,会使用如果一个操作值为布尔值,则在比较之前先将其转换为数值的规则来转换,Number([0]),也就是0,于是变成了0 == true,结果自然是false
function foo() {}
var old = foo.name
foo.name = 'bar'
// old = = ? foo.name = ?
old = 'foo' foo.name = 'foo' 函数名不会被赋值改变
var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
filter不会调用undefined的元素
[1 < 2 < 3, 3 < 2 < 1]
A: [true, true]
B: [true, false]
C: error
D: other
运算符的运算顺序和隐式类型转换的题,从MDN上运算符优先级,'<'运算符顺序是从左到右,所以变成了[true < 3, false < 1]
接着进行隐式类型转换,'<'操作符的转换规则(来自雨的文章《Javascript类型转换的规则》):
如果两个操作值都是数值,则进行数值比较
如果两个操作值都是字符串,则比较字符串对应的字符编码值
如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较
如果一个操作数是对象,则调用valueOf()方法(如果对象没有valueOf()方法则调用toString()方法),得到的结果按照前面的规则执行比较
如果一个操作值是布尔值,则将其转换为数值,再进行比较
所以,这里首先通过Number()转换为数字然后进行比较,true会转换成1,而false转换成0,就变成了[1 < 3, 0 < 1]
所以结果为A
61 VUEX juejin.im/post/684490…
states 存储数据
mutations
在对应mutations.js中 添加方法
mutationsfun(state, obj) {
state.xxx = obj
}
在使用时,this.$store.commit('mutationsfun', {...})
getttes
getttes.js
gettersfun(states) {
return states.xxx++ // 返回对states的修改
}
使用时,this.$store.getters.gettersfun
action 实现mutations中不能实现的异步功能
getParamSync (context,Object) {
setTimeout(()=>{
context.commit('mutationsfun',Object)
},3000)
}
this.$store.dispatch('getParamSync',{...})
actions. 组合使用
export default {
getParamSync (context,Object) {
return new Promise((reslove,reject)=>{
setTimeout(()=>{
context.commit('getParam',Object)
return reslove('成功')
},3000)
})
},
changetitleSync ({commit},title){
setTimeout(()=>{
commit('changetitle',title)
},3000)
}
}
this.$store.dispatch('getParamSync',{
keyCode,
keyWord,
hunterCode,
sid,
ck,
tm
}).then((res)=>{
this.$store.dispatch('changetitleSync',res)
})
- 数组、对象的键都是以字符串形式存储
63.Set Map
set类型是一个不会有重复值的有序列表 add has delete clear
Array.from(new Set(arr)) // 经典数组去重
let set = new Set();
let key={};
let key2 = {};
set.add(key);
set.add(key2);
console.log(set.size); //2
key=null;
console.log(set.size); //2
set 存对象类型的数据时,存在垃圾无法回收的问题
对应这个问题可以使用weakSet类型
Map 存放键值对 键通过Object.is()去重,键的数据类型可以是基本类型数据也可以是对象,而值也可以是任意类型数据。
set get has delete clear
Weak Map 同理于 weak set 能支持垃圾回收
强类型语言和弱类型语言比较
面向对象和面向过程的区别
JS实现链表结构
队列和栈的区别