前端杂记

480 阅读8分钟

文章开头: 这仅是我对前端知识的浅薄的个人理解,请勿作为学习依据,也欢迎所有人相互交流,共同学习

前端知识点

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 伪造身份攻击

www.cnblogs.com/hyddd/archi…

9.git 命令

rebase 和 merge 区别

www.iteye.com/blog/josh-p…

  1. 原生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&&params2=xxxx')
xmlhttp.send()
xmlhttp.onreadystatuschange = function() {
    ...
}
post
xmlhttp = new XMLHttpRequest()
xmlhttp.open("post", "url")
xmlhttp.setRequestHeader('content-type','...')
xmlhttp.send('params1=xxx&&params2=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 使项目有单独的对齐方式

  1. 兼容问题

www.cnblogs.com/websmile/p/…

  1. 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=>{})

  1. 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

juejin.im/post/684490…

三种方式 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

  1. 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); 
  1. 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

  1. 两列布局 三列布局的方式
<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属性
        flex1 代表 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>

三列布局也可以将两端绝对定位 中间元素设置左右边距

  1. BFC问题

a.BFC触发方式 : overflow不为visible, float不为none position的值fixed或者absolute

b.生成BFC这样的特殊区域之后会有以下几点特性

(1).该区域margin与其他区域避免混叠

(2).该区域的与包含改块的父级对齐

(3).每个BFC之间不会发生重叠 (适用于两列布局)

(4).计算高度时,BFC也参与计算 (适用于清除浮动)

  1. VUE监听数组几种方法

双向绑定原理不适用于数组,VUE中对数组的修改不能够直接修改,有以下几点方法

1.splice 替换// this.text.splice(0, 1, '2')
2.$set 方法 // this.$set(this.text, 0, '123')
  1. 数组的方法

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,提升性能。

www.cnblogs.com/fundebug/p/….

40.条件断点调试

cloud.tencent.com/developer/a…

41.正则表达式

  1. 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事件名',数据)
  1. 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()
  1. 括号表达式合法判断
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. 响应头和请求头的参数以及相关知识

请求头

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即可

  1. 用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.线程与进程

  1. 1px边框

juejin.im/post/684490…

出现问题的原因是像素比 = 物理像素/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)
            })
  1. 数组、对象的键都是以字符串形式存储

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实现链表结构

队列和栈的区别