一点小笔记

185 阅读9分钟

let和var、const的区别

var 用于声明全局变量,变量提升只是声明提升,并不是赋值提升

console.log(a);//undefined
var a = 1;
var a;
console.log(a);//undefined
a = 1;

let 用于声明局部变量,块级作用域,不允许重复定义;不具有变量提升,变量未声明前不能使用,否则报错,就是let声明存在暂时性死区

let a = 1;
console.log(a);//1
console.log(b);//Uncaught ReferenceError: b is not defined
let b = 2;
function foo(){
    let a = 1;
    let a = 2;//Uncaught SyntaxError: Identifier 'a' has already been declared
}

const 用于声明常量,块级作用域,一旦赋值不能修改

const a = 1;
console.log(a);//1
a = 2;
console.log(a);//Uncaught TypeError: Assignment to constant variable.
const obj = {a:1,b:2};
console.log(obj.a);//1
obj.a = 3;
console.log(obj.a);//3

const 声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。

箭头函数的使用场景

1. 不适用场景

  • 对象中的方法
var cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

当调用cat.jumps时,lives的值并没有递减,因为this没有绑定值

  • 带有动态上下文的回调函数
var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

点击按钮后会报错,typeError的错误,因为this并没有绑定到button上

  • 当箭头函数影响到代码的可读性时 普通函数可以知道预期的返回等,但是对于箭头函数却很难从代码上进行解读。

2.适用场景

  • 在任何需要绑定this到当前上下文,而不是函数本身时。
  • 无复杂逻辑的纯函数场景,例如用在 map、reduce、filter 的回调函数定义中

promise的all方法和race方法的使用场景和主要功能

1. promise.all

使用场景:多个异步结果合并到一起,比如一个页面需等待多个异步的ajax返回数据来显示,在此之前只能显示正在加载的图标

promise.all可以将多个promise实例包装到一起组成一个新的实例

promise.all([p1,p2,p3])
  • 它接受一个数组作为参数
  • 数组可以是promise对象也可以是其他的值,只有promise对象会等待状态的改变
  • 当所有子promise完成,该promise完成,返回的是全部值得数组
  • 如果有任何一个promise失败,则该promise失败,返回第一个失败的子promise的值
let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})

ps:promise.all成功数组里面返会的数据的顺序,和接收到的数组的顺序是一致的

2. promise.race

使用场景:把异步操作和定时器结合到一起,如果定时器先触发认为超时告知用户,比如点击一个查询按钮,超过几秒接口还没有返回数据我们就提示用户“您的查询已超时!”

promise.race和promise.all一样都是把多个实例包装到一起,但是不同的是,promise.race()中任意一个返回成功后,就算完成,但是进程不会立刻停止

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了')
  }, 2000);
})

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')    
  }, 5000);
})


Promise.race([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

race顾名思义比赛,里面哪一个结果先返回,就返回那个结果,不管结果是成功或者失败。

js的继承,组合继承和寄生组合继承的优缺点

快排原理

var quickSort = function (arr) {
    if(arr.length <=1) return arr;
    var pivot = arr.slice(0,1);
    var leftArr = [],rightArr =[];
    for(var i = 1 ; i < arr.length ; i++){
        if(arr[i] < pivot){
            leftArr.push(arr[i]);
        }else{
            rightArr.push(arr[i]);
        }
    }
    return quickSort(leftArr).concat(pivot,quickSort(rightArr));
}

思路:快速排序是对冒泡排序的一种改进,第一趟排序时将数据分成两部分,一部分比另一部分的的所有数据都要小,然后进行递归调用,在两边都实行快速排序

css可以继承和不可以继承的属性各列举5种

  • 可继承的:font,font-size,font-weight,text-align,text-indent,line-height,visibility,color,list-style,cursor
  • 不可继承的:display,vertical-align,width,height,marign,border,padding,background,float,position

vue的路由

1. vue-router是什么?有哪些组件

路由管理器,用来构建单页面应用的,实现不同组件之间的跳转

常用组件:router-link(设置路由的跳转)、router-view(根据路由显示组件)

2.active-class是哪个组件的属性

active-class是router-link用来作选中样式的切换

在vue-router中使用active-class有两种方式:

  • 直接在路由js文件中设置
export default new Router({
  linkActiveClass: 'active'
})
  • 在router-link中直接写入active-class
<router-link to="/home" class="menu-home" active-class="active">首页</router-link>

ps:如果使用在router-link中加入active-class的方法,可能会出现两个路由都有选中的样式,

<div class="menu-btn">
  <router-link to="/" class="menu-home" active-class="active">
    首页
  </router-link>
</div>
<div class="menu-btn">
  <router-link to="/my" class="menu-my" active-class="active">
    我的
  </router-link>
</div>
  • 解决方案A
export default new Router({
  linkExactActiveClass: 'active',
})
<router-link to="/" class="menu-home" active-class="active" exact>首页</router-link>

现在路由的js文件中配置linkExactActiveClass,在router-link中加入exact

  • 解决方案B
<router-link to="/home" class="menu-home" active-class="active" exact>首页</router-link>
路由中加入重定向
{
  path: '/',
  redirect: '/home'
}

3.怎么定义vue-router的动态路由?怎么获取传过来的值

{ 
    path: '/details/:id'
    name: 'Details' 
    components: Details
}

动态路由的创建主要是通过使用path属性过程是,使用动态路径参数以冒号开头 当匹配到/details的时候就会把参数设置到this.$route.params上,可以通过

this.$route.params.id

来获取传递过来的参数

4.vue-router有哪几种导航钩子?

  • 全局导航钩子 router.beforeEach(to,from,next)路由改变前的钩子
const router = new Router({ ... })
router.beforeEach((to, from, next) => {
  //
})

to:即将要进入的路由目标对象

from:当前正要离开的路由,也是一个路由对象

next:一定要调用该方法来resolve这个钩子

router.beforeResolve在导航被确认前,同时在所有组件内守卫和异步路由组件被解析之后,该钩子就被调用

router.afterEach路由改变后的钩子

  • 路由独享钩子

可以在路由配置上直接定义beforeEnter

cont router = new Router({
   routes: [
       {
           path: '/home',
           component: Home,
           beforeEnter: (to, from ,next) => {
               // do someting
           }
       }
   ]
});
  • 组件内的导航钩子

beforeRouterEnter在进入当前组件对应的路由前调用

beforeRouterUpdate在当前路由改变,但是该组件被复用时调用

beforeRouterLeave在离开当前组件对应的路由前调用

export default {
    data() { ... },
    beforeRouteEnter(to, from, next) {
        ... ...
    }
}

ps:beforerRouterEnter不能获取组件实例this,因为这个守卫执行前,组件实例还没有被创建出来,剩下两个可以正常获取

5.routeroute和router的区别

router是vueRouter的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。

route是路由跳转的对象,每一个路由都会有一个route对象,是一个局部对象,包括path、params、hash、query、name等路由信息参数

6.vue-router响应路由参数的变化

  • 用watch检测路由的变化
watch: { 
    $route(to, from){ 
    console.log(to.path) // 对路由变化做出响应 
    } 
}
  • 组件内导航钩子函数
beforeRouteUpdate(to, from, next){ 
    // to do somethings 
}

7.vue-router传参

  • params
this.$router.push({ 
    name: Home, 
    params: { number: 1 , code: '999' } 
}) 

接收参数this.$route.params

ps:只是用name,不使用path,参数不会显示在路径上,浏览器强制刷新参数会被清空

  • query
this.$router.push({ 
    name: Home, 
    query: { number: 1 , code: '999' } 
}) 

接收参数this.$route.query

ps:参数会显示在路径上,刷新不会清空参数,name可以使用path路径

  • router-link标签
<router-link target="_blank" :to="{path:'/login',query:{userId: "33333"}}"></router-link>

8.vue-router实现路由懒加载

把不同路由对应的组件分割成不同的代码块,当路由被访问时才加载对应组件,即为路由的懒加载。

  • vue的异步组件
{
  path: '/home',
  name: 'home',
  component: resolve => require(['@/components/home'],resolve)
}
  • import引入
const router = new VueRouter({ 
    routes: [ 
        { 
            path: '/home', 
            name: 'Home', 
            component:() = import('../views/home') 
        }
   ] 
})
  • webpack提供的require.ensure()
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}

vue的双向绑定如何实现,原理是啥

vue的双向数据绑定是通过数据劫持结合发布订阅的方式来实现的,数据和视图同步,数据发生变化视图跟着变化,视图变化数据也随之发生改变。

关于数据双向绑定,核心就是object.defineProperty()方法。

  • object.defineProperty()方法:

object.defineProperty(obj,prop,descriptor),这个方法接收三个参数:

obj:要定义其上属性的对象

prop:要定义或修改的属性

descriptor:具体的改变方法

可以理解为用这个方法来定义一个值,用它里面的get方法获取对应内容,用set方法给对应内容赋值。

var obj = {}
Object.defineProperty({},'hello',{
    get:function(){
        console.log('调用了get方法')
    },
    set:function(newVal){
        console.log('调用了set方法,新的值是'+newVal)
    }
})
obj.hello;//调用了get方法
obj.hello = 'hi';//调用了set方法,新的值是‘hi’

svg和canvas的区别

- svg

是一种使用XML描述2d图形的语言

SVG基于xml这也就意味着SVG DOM中的每个元素都可用

在svg中每个被绘制的图形都被视为对象,如果svg对象的属性发生变化,那么浏览器能够自动重现图形

- canvas

canvas通过JavaScript来绘制的2d图形,是逐像素进行渲染的

在canvas中一旦图形被绘制完成,他就不会得到浏览器的继续关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
  • 区别

    SVG:

    不依赖分辨率

    支持事件处理

    最适合带有大型渲染区域的应用程序(例如谷歌地图)

    复杂度高会减慢渲染速度

    不适合游戏应用

    canvas:

    依赖分辨率

    不支持事件处理

    弱的文本渲染能力

    能够以.png或.jpg格式保存结果图像

    最适合图像密集型的游戏,其中的许多对象会被频繁重绘

节流和防抖你是如何实现的,他们两个根本的区别在哪里,代码上如何体现

css的bfc你了解吗,他们在哪些场景可以实现,你还知道关于哪些清除浮动的方法

BFC(BLOCK formatting context)块级格式化上下文,他是一个独立的渲染区域,这个区域与外部毫不相干

BFC的布局规则

  • 内部的box会在垂直方向上,一个接着一个的放
  • box垂直方向上的距离由margin决定,属于同一个BFC的两个相邻的box的margin会重叠
  • 每个盒子(块盒与行盒)的margin box的左边,与包含border-box的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也如此
  • 计算BFC的高度时,浮动元素也参与计算

如何创建BFC

  • float的值不是none
  • position的值不是relative或static
  • display的值是inline-block,table-cell,flex,inline-flex,table-caption
  • overflow的值不是visible

BFC的作用

  • 利用BFC来避免margin重叠
  • 自适应两栏布局
  • 清除浮动

可以理解为BFC就是页面中的一个独立的容器,容器里面的子元素不会影响到外面的元素。

因为BFC内部的元素和外部的元素绝对不会互相影响,所以, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。

前端跨域了解多少,jsonp如何实现,有啥缺陷

什么是跨域?

不满足同源策略(协议、域名、端口号任意一个不同)即跨域。

解决跨域的方法

  • jsonp解决
    //原生
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参并指定回调执行函数为onBack
    script.src = 'http://www.demo2.com:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);

    // 回调执行函数
    function onBack(res) {
        alert(JSON.stringify(res));
    }
    //jquery
    $.ajax({
        url: 'http://www.demo2.com:8080/login',
        type: 'get',
        dataType: 'jsonp',  // 请求方式为jsonp
        jsonpCallback: "onBack",    // 自定义回调函数名
        data: {}
    });
    //vue
    this.$http.jsonp('http://www.demo2.com:8080/login', {
        params: {},
        jsonp: 'onBack'
    }).then((res) => {
        console.log(res); 
    })

缺点:只能实现get一种请求

  • document.domain+iframe
  • location.hash +iframe
  • window.name+iframe
  • postMessage
  • 跨域资源共享(cors)
  • ngnix代理
  • node中间件代理
  • websocket协议跨域

实现一个滚动条你如何实现

深浅拷贝,各自原理,深拷贝有啥缺点

如何用原生js实现一个拖拽

性能优化有哪些?

  • 减少http请求
  • 使用服务端渲染
  • 静态资源使用cdn
  • 将css放在文件头部,js放在文件底部
  • 使用字体图标iconfont代替图片图标
  • 善用缓存不重复加载重复资源
  • 压缩文件
  • 图片优化(图片延迟加载,响应式图片,调整图片大小,降低图片质量,尽可能使用css3效果代替图片,使用webp格式图片)
  • 按需加载(通过webpack等)
  • 减少重绘重排
  • 使用事件委托
  • 使用web worker
  • 降低css选择器的复杂性
  • 合理使用规则,避免过度优化

数组去重列举2种方法

  • 循环遍历
function removeRepeat(arr){
    if(arr.length < 1) return arr;
    var arr2 = [];
    for(let i = 0 ; i < arr.length; i ++){
        if(arr2.indexOf(arr[i]) == -1){
            arr2.push(arr[i]);
        }
    }
    return arr2;
}
  • ES6中的new Set()方法
function removeRepeat(arr){
    return Arrar.from(new Set(arr))
}
function removeRepeat(arr){
    var newArr = new Set(arr)
    return [...newArr]
}
  • filter()方法
function unique(arr) {
    return arr.filter(function(item, index, arr) {
        //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
        return arr.indexOf(item, 0) === index;
    });
}

css的盒模型

  • 标准盒模型
box-sizing:content-box;

宽度:内容宽+padding+margin+border

  • 怪异盒模型
box-sizing:border-box;

宽度:内容宽+margin

block   inlineblock,inline的区别

  • block 块级元素独占一行,默认情况下块级元素宽度会自动填满父级元素的宽度; 块级元素可以设置宽高,可以设置margin和padding; 块级元素内可以写块级和行内元素;
  • inline-block 行内块元素不会独占一行; 行内块可以设置宽高和margin及padding
  • inline 行内元素不会独占一行,一行可以有多个行内元素,宽度随内容的大小决定; 行内元素设置宽高不生效; 行内元素的padding-top,padding-bottom,margin-top,margin-bottom不生效

flex布局

display:flex;

设置为flex布局后,设置float,clear,vertical-align不生效

  • flex-direction 决定主轴的排列方向,即项目的排列方向
.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

row(默认值):主轴为水平方向,起点在左端。

row-reverse:主轴为水平方向,起点在右端。

column:主轴为垂直方向,起点在上沿。

column-reverse:主轴为垂直方向,起点在下沿。

  • flex-wrap 默认项目都展示在一条线上,如果战士不下要如何显示
.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}

no-wrap:默认不换行

wrap:换行,第一行在上方

wrap-reverse:换行,第一行在下方

  • ** flex-flow** flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
  • justify-content 定义了项目在主轴上的展示方式
.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

flex-start(默认值):左对齐

flex-end:右对齐

center: 居中

space-between:两端对齐,项目之间的间隔都相等。

space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

  • align-items 属性在交叉轴上怎么展示
.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

flex-start:交叉轴的起点对齐。

flex-end:交叉轴的终点对齐。

center:交叉轴的中点对齐。

baseline: 项目的第一行文字的基线对齐。

stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

  • align-content 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

flex-start:与交叉轴的起点对齐。

flex-end:与交叉轴的终点对齐。

center:与交叉轴的中点对齐。

space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。

space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。

stretch(默认值):轴线占满整个交叉轴。

实现一个单行文本溢出显示

单行文本溢出省略号显示:

.div{
    overflow:hidden;
    tex-overflow:ellipsis;
    white-space:nowrap;
}

多行文本溢出省略号显示:

.mult_line_ellipsis{//多行文本溢出
     overflow: hidden;
     text-overflow:ellipsis;//文本溢出显示省略号
     display: -webkit-box;
     -webkit-line-clamp: 3;
     -webkit-box-orient: vertical;
      width:130px;
      background-color:cornflowerblue;
}

重排重绘,如何减少

  • 重排 当页面布局和几何属性改变就会发生重排 以下情况会导致重排:
  1. 添加或者删除可见的dom元素
  2. 元素位置改变,display、position、float、overflow等
  3. 元素尺寸改变,边距,填充,高度,宽度
  4. 内容改变,比如文本内容改变或者图片大小改变而引起的宽度和高度的改变
  5. 页面渲染初始化
  6. 浏览器窗口改变----resize事件发生时
  • 重绘 当页面的样式发生改变就会发生重绘,背景色、边框色、可见性等
  • 重排重绘的代价 导致浏览器很卡很慢
  • 减少重排重绘
  1. 减少直接操作dom元素,改用className用于控制
  2. 尽量减少table的使用,table的属性发生变化会直接导致布局发生重排或重绘
  3. 当dom元素的position属性的值为fixed或absolute,可通过css形变触发动画效果,此时是不会触发reflow
  4. 不要把dom节点的属性值放在一个循环里当成循环变量
  5. 如果需要创建多个dom节点,可以使用documentFragment创建完成后一次性加入document

浏览器解析渲染过程

  1. 构建dom
  2. 构建CSSOMTree
  3. 渲染树的构建
  4. 布局
  5. 渲染 构建对象模型(DOM,CSSOM)->构建渲染树(RenderTree)->布局->渲染

什么会阻塞浏览器的解析

  • 输入url地址到页面加载都发生了什么?
  1. 根据网址进行DNS解析,将相应的域名解析成对应的IP地址
  2. 客户端根据对应的IP地址去寻找对应的服务器进行TCP三次握手,建立TCP连接
  3. 客户端发起http请求,请求对应资源
  4. 服务器响应并返回相应数据(例如:html)
  5. 浏览器将获取到的html文档由html解析器解析成dom树
  6. 同时由css解析器将css样式解析成css规则树
  7. 将生成的dom树和css规则树合并成rendering tree(渲染树)
  8. 根据渲染树,在屏幕上对元素进行布局
  9. 根据渲染树将各个元素绘制到屏幕
  10. 客户端与服务器进行四次挥手
  • 浏览器渲染网页阻塞顺序
  1. 构建dom树时,如遇到js元素时,会阻塞dom树和css规则树的构建,优先执行js文件
  2. 构建dom树时,如遇到css元素,会开启异步请求线程,该线程会先下载css文件,在构建css规则树,该线程会阻塞JavaScript引擎线程,但不会阻塞dom树的构建
  3. css解析和js解析互斥,也就是说js解析时会阻塞css解析,css解析时会阻塞js解析
  4. js解析时,如果js还操作了css,而这个css还没构建或解析,则会延迟执行js,直到完成css的下载解析构建,再继续执行js

js的defer和async属性

<script src='example.js'></script>

浏览器会立即加载并执行js脚本,此标签后的文件需等待该文件执行完毕,那么无疑会阻塞后面文件的加载。

<script async src='example.js'></script>

增加了async属性,该文件会和后面的文件内容并行加载执行,即异步执行。

<script defer src='example.js'></script>

增加了defer属性,加载后续的文档和js脚本的加载是并行的,此时只是并行加载并不执行,js的执行需要等到所有文档解析完成在开始。

defer 和 async 的共同点是都是可以并行加载JS文件,不会阻塞页面的加载,不同点是 defer的加载完成之后,JS会等待整个页面全部加载完成了再执行,而async是加载完成之后,会马上执行JS,所以假如对JS的执行有严格顺序的话,那么建议用 defer加载。

浏览器缓存

浏览器分为强缓存和协商缓存,缓存的作用是为了提高客户端速度,节省网络流量,降低服务器压力。

  • 强缓存:浏览器请求资源,如果header中Cache-control和Expries没有过期,直接从缓存(本地)读取资源,不需要再向服务器请求资源。
  • 协商缓存:浏览器请求的资源如果是过期的,就会向服务器发送请求,header中带有etag字段。服务器在进行判断,如果etag匹配就给客户端返回300的状态码,客户端继续使用本地缓存,否则客户端会重新获取数据资源。

es6的新特性

this的指向

手写一个bind

手写利用promise实现失败后重新请求

手写一个发布订阅模式

vue的双向绑定

nexttick实现原理

webpack的运行机制

手写继承