前端八股

面试题预测之八股


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

HTML CSS

0、选择器优先级

  1. !important无条件优先
  2. 内联样式 style = ‘color:red’ 1000
  3. id选择器 100
  4. class类选择器 伪类选择器 属性选择器10
  5. 元素选择器 伪元素选择器 1
  6. *通配符选择器 >子类选择器 +兄弟选择器 0
  7. 继承来的没有优先级

1、块级元素与行内元素区别

  1. 块级元素独占一行,可以设置宽度和高度;行内元素会在一行显示,不能设置宽度高度 padding margin,由元素的内容撑开的
  2. 通过display:inline display:block转换两者
  3. 行内块元素inline-block既有块级元素可以设置宽高的特性,也有行内元素一行显示的特性,行内块元素独有一个vertical-align属性
  4. 块级:div p h ul li ol form
  5. 行内:span input img a select

2、script的defer async标签

script会阻塞DOM加载,从外部引入js会出现空白页问题,引入defer async属性

  1. defer:不会阻塞页面加载;并行下载对应的js文件,下载完后不会立即运行;当其他的js脚本下载完成后,页面加载之前触发
  2. async:不会阻塞DOM加载;并行下载对应的js文件,下载完成后立即运行js文件

3、css的flex布局

  1. flex布局是弹性布局
  2. 给父元素设置display:flex可以将它变成flex盒子
  3. 父元素称为容器,有以下几个属性:flex-direction 、flex-wrap、flex-flow、justify-content、align-items、align-content
  4. 子元素称为项目,有以下几个属性:order、flex-grow0、flex-shrink1、flex-basis、align-self

4、grid网格布局

5、清除浮动的方式

  1. 额外标签法:在浮动元素的后面添加一个元素,设置clear:both属性
  2. 给父元素清除浮动触发BFC:父元素增加overflow:hidden
  3. after伪元素法:给父元素增加一个after伪元素,IE6-7不支持after,需要给父元素设置 *zoom:1
  4. before after双伪元素法:
  5. 给父元素手动设置高度

6、BFC是什么 如何触发

  1. BFC是块级格式化上下文,形成一个独立的渲染区,内部布局规则是独立的

  2. 触发方式:
    (1)float不为none
    (2)position为absolute fixed
    (3)display为Inline-block flex table
    (4)overflow不为hidden(hidden auto scroll)

  3. BFC布局方式
    (1)内部是box,在垂直方向上排列
    (2)同一个BFC中的两个相邻盒子的margin会发生重叠
    (3)BFC区域不会与浮动元素发生重叠
    (4)BFC计算高度时,浮动的元素也参与计算

  4. BFC的作用
    (1)解决垂直方向上的margin重叠问题:可以使用div将两个盒子分别包起来,设置overflow:hidden,触发两个不同的BFC,两个BFC之间不会互相影响
    (2)解决包含子元素的margin-top塌陷问题:当子元素设置margin-top时,会带动父元素一起向下移动,因为内部的布局规则影响到父元素了。这时候触发父元素的BFC,使其内部形成独立的渲染规则,这样可以解决margin-top塌陷问题。
    也可以对父元素设置一个大小不为0的边框
    (3)清除浮动:当父元素没有设置高度时,子元素浮动时父元素会高度塌陷,可以给父元素触发BFC,因为BFC计算高度时,浮动的盒子也参与计算
    (4)自适应布局栏,左侧设置浮动,右侧设置成BFC,因为BFC不会与浮动区域发生重叠

7、 px rem em vh vw

(1)px是相对于屏幕显示器分辨率而言的,无法适应页面大小
(2)rem是相对单位,相对根元素html的字体大小font-size来决定的
(3)em是相对单位,相对当前元素的字体大小,如果当前元素没有设置字体大小,则继承父元素的字体大小,否则,相对浏览器默认的字体大小16px。
默认 1em = 16px,所以10px = 0.625em,在body中声明Font-size = 62.5%;
(4)vh vw是视口高度和视口宽度,1vw是1/100的视口宽度, 1vh是1/100的视口高度
(5)rpx是自适应屏幕宽度的,规定屏幕宽度 = 750rpx

8、 HTML5新特性

  1. 声明方式 !DOCTYPE html 告诉浏览器文档使用哪一种HTML5规范
  2. 新增的语义化标签 header nav footer section
  3. 新增的audio video播放视频和音频
  4. input的type属性值新增了:number tel email file等,可以进行数字 电话 邮箱验证
  5. 表单新增的属性:placholder放占位文本,required表示文本框不能为空,autofocus默认获取焦点,min最小长度,max最大长度
  6. 新增canvas标签:与js联合 通过getContent(2d)获取2d环境,进行画图
  7. 新增svg标签:用来画图,比canvas更好,不失帧
  8. web worker:js是单线程,前面一个任务在执行时 后面的任务只能等待,降低了性能。web worker为js创建多线程执行环境。js在主线程执行,new一个线程在后台执行,使用webworker计算数据返回给主线程,两个进程互不影响,独立运行。
  9. web storage:新增了浏览器本地存储localStorage sessionStorage,比cookie存储空间大,有5MB,而且可以使用自带的getItem() setItem() removeItem() clear()存储或读取数据,数据以key value的形式存储在本地。localStorage的作用域:可以在同源的不同页面 不同标签 不同窗口中共享数据。sessionStorage不能在不同页面 不同标签 不同窗口中共享数据。同源:协议相同 域名相同 端口号相同
  10. web socket:是一个基于TCP连接的全双工通信协议。当浏览器向服务器发送建立socket连接请求时,服务器返回信息给客户端,建立完成后,浏览器和服务器可以进行数据传输。

9、CSS3新特性

  1. border-radius
  2. box-shadow
  3. translate3d
  4. 动画 @keyframes
  5. 3d旋转
  6. box-sizing怪异盒模型

10、DOM事件流和事件委托

10.1事件流

  1. 事件分为三个阶段:事件捕获阶段、目标阶段、冒泡阶段
  2. 事件捕获阶段:从window传导到目标对象,从上到下
  3. 目标阶段:事件发生阶段
  4. 事件冒泡阶段:从目标对象向window传导,从下到上
  5. 一般事件在冒泡阶段执行,addEventListener的第三个参数默认为false表示在冒泡阶段执行。如果把第三个参数改为true表示在捕获阶段进行。

10.2事件委托

  1. 原理:事件冒泡
  2. 把原本该绑定在子元素上的事件委托到父元素身上,使用父元素来监听事件
  3. 优点:可以减少内存占用,减少子事件注册。比如把li的click事件绑定到父元素ul身上。

11、盒模型

分为标准盒模型和怪异盒模型
当box-sizing设置为content-box时,是标准盒模型,盒子宽度=width+padding+border+margin
当box-sizing设置为border-box时,是怪异盒模型,盒子宽度=width+margin,因为width已经包含了padding和border

JS

1、数据类型

数据类型共8种

  1. 基本数据类型:Number String Boolean Null Undefined BigInt Symbol
  2. 引用数据类型:Object,包括Array Function Date等

2、如何判断数据类型

判断数据类型1

  1. typeof a
    不能区分Null Object。由于null是空对象指针,使用typeof(null) 值为Object
    不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
  2. a instanceof b
    null和undefined除外
    判断对象的原型链中是不是能找到类型的 prototype Object instanceof Object为true
    判断一个对象是否为数据类型的实例对象,返回布尔值,主要用于判断引用类型
    当简单数据类型以字面量形式创建时,instanceof 无法判断 1 instanceof Number 返回false
    可以以new形式创建简单数据类型,new Number(1) instanceof Number 返回true
  3. Object.prototype.toString.call(a)
  4. a.constructor
    null和undefined除外

3、== 与 ===

Null == Undefined ->true

4、call apply bind

1 区别

  1. 传参方式不同:这三个函数的第一个参数都是this的指向对象,第二个参数不同。call bind是将参数以逗号分隔放进去的,apply是将参数放在数组中传入
  2. 调用方式不同:bind的返回值是一个函数,需要二次调用

2 手写

call

Function.prototype.myCall = function(context) {
	// 先判断调用call的对象是否为函数。因为只有函数才能调用call来进行改变this指向
	if(typeof this !== 'function') {
		throw new TypeError('not a function');
	}
	context = context || window;
	context.fn = this; //将函数方法保存到context身上,方便后续的调用
	//将为数组转为真实数组,从1索引开始截取到最后形成args参数数组
	let args = [...arguments].slice(1); 
	let result = context.fn(...args); 
	delete context.fn;
	return args;
}

apply

Function.prototype.myApply = function(context) {
	if(typeof this !== 'function') {
		throw new TypeError('not a function');
	}
	context = context || window;
	context.fn = this;
	//已知arguments有两项,第一项是this,第二项是一个参数数组,解构出来,形成args参数数组
	let args = [...arguments[1]]; 
	let result = context.fn(...args);
	delete context.fn;
	return result;
}

bind

Function.prototype.myBind = function(context) {
	if(typeof this !== 'function') {
		throw new TypeError('not a function');
	}
	context = context || window;
	context.fn = this;
	let args = [...arguments].slice(1);
	return function() {
		// bind涉及二次调用,可能存在initObj.bind(this,args)(args2);多个参数
		let otherargs = [...arguments]; 
		return context.fn.apply(context, args.concat(otherargs));
	}
}

5、手写new

  1. new做了什么
    (1)创建了一个空对象
    (2)将空对象的隐式原型属性proto指向构造函数的显示原型prototype
    (3)调用apply改变this指向,将构造函数的this指向新创建的实例对象
    (4)判断执行结果是否为Null或undefined,如果是则返回新创建的对象obj,否则返回执行结果
function myNew(fn, args) {
	const obj = {};
	obj.__proto__ = fn.prototype;
	let result = fn.apply(fn, ...args);
	return result instanceof Object ? result : obj;
}

6、setTimeOut()与setInterval()

  1. setTimeOut和setInterval都是JS中的定时器,第一个参数是要执行的表达式,第二个参数是延迟时间,单位是毫秒,也可以有第三个参数,作为表达式的补充参数
  2. setTimeOut和setInterval执行的返回结果是唯一的ID,可以作为定时器的ID
  3. 可以使用clearTimeOut或clearInterval,把ID作为参数,清除定时器
  4. setTimeOut()表示延迟多少毫秒后,执行表达式,只执行一次
  5. setInterval()表示每隔多少毫秒后就执行一次表达式,会一直执行,直到clearInterval或窗口关闭
  6. 使用setInterval可能存在两个问题:定时器的间隔比预设的小或者没有间隔。如果想每隔200ms就执行一次程序,但是程序执行需要300ms时,就会不间隔地重复执行,因此可以使用链式setTimeOut()进行

JS新特性

1、作用域与作用域链

规定函数或变量可使用范围的称为作用域。

  1. 全局作用域:
    在函数外部声明的变量,或者没有声明直接使用的变量是全局变量。它可以在全局条
    件下访问
  2. 局部作用域:
    在函数内部声明的变量或函数,它只能在函数内部访问,在函数外部访问不到
    作用域之间可以互相嵌套
  3. 作用域链
    各个作用域的嵌套形成了作用域链,主要用来进行变量或函数的访问。沿着作用域链由内向外一层一层查找变量
    如果自身作用域中声明了该变量,则直接访问
    如果自身作用域中没有该变量,则沿着作用域链,从内向外查找

2、变量声明提升和函数声明提升

  1. 变量提升:使用var声明的变量,提升到作用域顶部,变量的赋值语句是不提升的,所以在赋值语句之前,变量的值都为Undefined
  2. 函数声明提升:使用function关键字声明的函数,提升到作用域的顶部
    函数表达式不提升

3、闭包

  1. 闭包是什么:本质是函数内部嵌套函数,用来实现全局作用域下访问局部变量,或函数内部访问其他函数内部的变量
  2. 特性:(1)函数内部嵌套函数(2)函数内部可以引用函数外部的变量和参数(3)参数和变量不会被垃圾回收机制回收
  3. 两种形式:(1)作为返回值(2)作为参数传递
  4. 优点:保护+保存(1)保护函数内部的变量,防止流入其他环境造成命名冲突(2)在内存中维持一个变量,作为缓存(3)匿名函数自执行减少性能的消耗
  5. 缺点:(1)被引用的私有变量不会被回收,造成内存泄漏,可以手动赋值为null(2)闭包涉及到跨域访问,可以将跨域的变量作为局部变量,提高性能

4、执行上下文与执行栈

1 执行上下文

  1. 全局执行上下文:创建一个window对象,this执行window,在执行js时,压入栈底,关闭浏览器时弹出
  2. 函数执行上下文:每次执行函数时,都会创建一个新的函数执行上下文。分为创建阶段和执行阶段

2 执行栈

  1. 先进后出
  2. 进入一个执行环境后,创建对应的执行上下文,压入栈中,当执行完毕后,销毁执行上下文,弹出栈
  3. 栈底是全局执行上下文,栈顶是当前正在执行的函数执行上下文
  4. 只有当浏览器关闭后,全局执行上下文才会弹出栈

5、原型与原型链

1 原型

  1. 分为显示原型prototype和隐式原型__proto__
  2. 实例对象的隐式原型指向构造函数的显示原型
  3. 所有的显式原型prototype都是一个对象,所有它的隐式原型proto指向Object.prototype
  4. 构造函数的隐式原型指向Function的显示原型
  5. Object的隐式原型指向null

2 原型链

查找对象的某个属性时,先从对象自身查找,如果没找到,则从对象的隐式原型 即构造函数的显式原型上查找,如果仍然没找到,则向上从显式原型prototype的隐式原型 即Object的显式原型上找,这样一层层向上查找形成的链式,称为原型链。

  1. 所有的prototype是对象,所以它的隐式原型是Object的显式原型
  2. 原型链的尽头是null。Object.prototype.proto === null
  3. 如果到尽头仍然没找到,则返回undefined

6、继承

1 原型继承

  1. 父类的实例对象作为子类的原型 ch.proto === Child.prototype === new Parent();
  2. 子类共享父类原型上的属性和方法;实例既是父类的实例对象,也是子类的实例对象
  3. 只能单一继承;创建子类实例时不能传参
function Parent(){
	this.name = name;
	this.age = age;
	showName = function(name) {
		console.log(this.name);
	}
}
Parent.prototype.working = function(work){
	console.log('is' + 'work');
}

function Child(){
}

// 父类的实例作为子类的原型
Child.prototype = new Parent();

2 构造继承

  1. 在子类中调用父类的构造函数,通过call改变this指向,继承父类实例中的属性和方法
  2. 子类能获得父类实例中的属性和方法;创建子类时可以传入参数;可以多个继承
  3. 不能获得父类原型上的属性和方法;实例是子类的实例,并不是父类的实例
function Parent(name,age){
	this.name = name;
	this.age = age;
	showName = function(name) {
		console.log(this.name);
	}
}
Parent.prototype.working = function(work){
	console.log('is' + 'work');
}
function Child(name,age){
	// 调用父类构造函数,将父类的属性和方法给子类
	Parent.call(this);
}

3 组合继承

  1. 在子类中调用父类构造函数,继承父类实例中的属性和方法
  2. 将父类的实例挂载到子类构造函数的原型上,继承父类原型中的属性和方法
  3. 优点:实例既是父类的实例,也是子类的实例;创建实例时可以传入参数;可以继承父类实例和原型上的属性和方法;
  4. 缺点:调用两次父类构造函数,生成两份实例(子类身上那份会被销毁)
function Parent(name,age){
	this.name = name;
	this.age = age;
	showName = function(name) {
		console.log(this.name);
	}
}
Parent.prototype.working = function(work){
	console.log('is' + 'work');
}
function Child(name,age){
	// 调用父类构造函数,继承父类实例上的属性和方法
	Parent.call(this);
}

// 调用父类构造函数生成父类实例,作为子类的原型,继承父类原型上的属性和方法
Child.prototype = new Parent();
// 将子类原型上的构造器指回子类
Child.prototype.constructor = Child;

4 寄生组合继承

  1. 为了减少调用父类的构造函数的次数(减小开销),我们不再通过new Parent()来让父构造函数生成实例,可以直接用 Object.create(Parent.prototype) 来继承父类的原型。
  2. 几乎是完美的
function Parent(name,age) {
	this.name = name;
	this.age = age;
	showName = function() {
		console.log(this.name);
	}
}
Parent.prototype.working = function(work) {
	console.log('is' + work);
}

function Child(name, age){
	// 调用父类构造函数,继承父类实例上的属性和方法
	Parent.call(this);
	this.name = name;
	this.age = age;
}

// 不再使用new Parent来生产父类实例
Child.prototype = Object.create(Parent.prototype);
// 将子类原型上的构造器指回子类
Child.prototype.constructor = Child;

5 extends继承

ES6新增class和extends继承

  1. 如果子类中有构造器,则在this之前使用super。
  2. 因为(1)子类没有自己的this对象,而是继承父类的this(2)调用super()继承父类中的this
class Father{
    constructor(name){
        this.name=name
    }
    getName(){
        return this.name
    }
}

class Son extends Father{
    constructor(name,age,sex){
        // 这里如果子类中存在构造函数,就必须在使用 this 之前先调用 super()
        // 相当于借用父类的 constructor 跟构造函数式继承中的 call 继承方法类似
        super(name)
        this.age=age
        this.sex=sex
    }
}

const son= new Son('joney',18,'女')
console.log(son);

7、箭头函数和普通函数的区别

  1. 箭头函数定义比较简单,使用()=>{},和普通函数的定义上有不同
    箭头函数在只有一个参数时,不需要加小括号,只有一句返回语句时省略函数体和return
  2. 箭头函数没有自己的this,在声明的时候捕获上下文中的this来使用,并且以后不能更改this指向,普通函数的this指向函数的调用者
  3. 箭头函数的this一旦确定后,不能通过call apply bind来修改this指向
  4. 箭头函数不能作为构造函数new实例对象,因为它没有自己的this不能调用call,也没有prototype
  5. 箭头函数没有arguments数组,如果使用不定项参数时用rest

8、函数的this指向

  1. 全局作用域下,this指向window
  2. 普通函数的this指向函数的调用对象
  3. 构造函数的this指向新创建的实例对象
  4. 箭头函数在声明时捕获上下文中的this供自己使用,this指向它的父级作用域,此后不能作更改
  5. call apply bind的this指向传入的第一个参数对象

9、深拷贝与浅拷贝

10、节流与防抖

  1. 防抖和节流都是用来控制函数在一段时间内的执行次数,减小事件触发频率,避免资源的浪费。
  2. 应用场景:resize scroll mousedown mousemove keyup keydown事件中使用防抖节流来减少触发的频率
  3. 防抖:在触发事件后,等待n秒,执行一次函数,如果等待的n秒期间,事件再次被触发,就需要重新计算时间。在连续触发事件时,只执行最后一次。
  4. 节流:连续触发事件,但在n秒内只执行一次,稀释函数的执行频率。一段时间内只执行一次。
  5. 应用:防抖(搜索框在输入完成后发送请求、窗口大小调整完成后执行一次resize计算大小)
    节流(滚动加载监听scroll事件、射击类游戏)

11、ES6新特性之set

  1. 是es6新增的集合类型,通过new Set()创建实例,也可以传入值进行初始化
  2. 如果传入重复的值,set会自动删掉重复元素,所以可以用set对数组去重。通过new Set(arr)将数组转为set并自动去重,再通过Array.from()将set转化为数组
  3. 通过s.size获取set中元素个数
  4. 通过add(1)增加 delete(3)删除set中的元素,通过clear()清空set中的元素
  5. 通过has()判断set中是否含有某个元素,返回布尔值
  6. 通过keys()获取set中的键名,values()获取set中的键值。在set中键名=键值
  7. 通过entries()返回键值对

12、clientHeight offsetHeight scrollHeight

  1. clientHeight:内容的高度+上下padding
  2. offsetHeight:内容的高度+上下padding+border
  3. scrollHeight:滚动部分的高度
  4. scrollTop:元素距离页面顶部的高度

13、JS性能优化

  1. 闭包中被引用的对象手动赋值null
  2. 垃圾回收
  3. 防抖节流
  4. 事件委托(事件代理)
    1、原理:事件冒泡,事件发生有三个阶段,事件捕获 目标和冒泡
    2、事件捕获:从window到目标对象,从上层到底层
    目标阶段:事件发生
    事件冒泡:从目标对象向上传导到window,是事件委托的原理
    3、事件委托:把原本要绑定到子元素身上的事件委托给父元素,让父元素监听
    4、减少事件注册,提高性能。比如让ul代理所有的li
  5. CDN
  6. script标签中的defer async

1.引入库

计算机基础知识

1、经典排序算法

(1)冒泡排序

1、平均时间复杂度为O(n^2),最好情况下为O(n)
2、原理:使用双层for循环,比较相邻的两个元素,如果后面一个元素比前面元素大,则交换两个元素位置,比较一趟后,最大的元素会出现在末尾
3、代码演示:
i = 0; i < arr.length; i++
j = 0; j < arr.length - 1 - i; j++
if(arr[j] > arr[j+1])

(2)选择排序

1、平均时间复杂度、最好情况下、最坏情况下为O(n^2)
2、原理:从未排序的数组中,选择一个最小的元素,把她放在起始位置。再从剩下未排序的数组中,继续选择最小的元素,把它放在已经排序元素的下一个。以此类推,直到排序完毕。
3、n个元素,需要 n-1 趟,完成排序
3、代码演示
i = 0; i < arr.length - 1; i++
minIndex = i;
j = i; j < arr.length; j++
if(arr[j] < arr[minIndex]) {
minIndex = j;
}

(3)插入排序

1、平均时间复杂度为O(n^2),最好情况下为O(n)
2、原理:默认第一个元素是已经排序好的,第二个元素作为新元素,如果新元素小于已经排序好的元素,则从后往前扫描已经排序好的序列,就要把已经排序好的元素反复向后移动,直到找到新元素应该插入的位置,然后把新元素插入进去。
3、代码演示:
i = 1; i < arr.length; i++
if(arr[i] < arr[i - 1]) {
let tmp = arr[i];
let p = i - 1;
while(p >=0 && arr[p] > tmp) {
arr[p+1] = arr[p];
p–;
}
arr[p+1] = tmp;
}

(4)快速排序

1、算法的平均时间复杂度为O(nlogn)
2、原理:先找一个基准,一般为Math.floor(arr.length / 2),把小于基准元素的放到left数组,把大于基准元素的放到right数组中。对left right数组采用递归的方式,然后使用concat连接left 基准值 和 right
3、代码演示:

function QuickSort(arr){
	let povitIndex = Math.floor(arr.length / 2);
	let povit = arr[povitIndex];
	let left = [ ], right = [ ];
	for(let i = 0; i < arr.length; i++) {
		if(i != povitIndex) {
			if(arr[i] <= povit) {
				left.push(arr[i]);
			}else{
				right.push(arr[i]);
			}
	    }	
   }
	return 	QuickSort(left).concat(povit,QuickSort(right));
}

2、B树

3、数组遍历的方式

  1. for循环遍历数组
  2. for of循环遍历数组,如果数组中的元素是对象的话,可以将对象的每个属性解构出来。for(const {name, age} of arr)。对象不能使用for of
  3. for in循环遍历数组或对象,得到的是数组的索引或者对象的属性名key
  4. forEach遍历数组,回调函数可以有三个参数,第一个是数组中每个元素item,第二个是数组下标index,第三个是数组array,在内部可以通过index的形式修改原数组中的元素,没有返回值。
  5. map,和forEach用法相似,但是map有返回值,返回一个新的数组,不会改变原来的数组。
  6. filter,对数组中所有的元素进行判断,将满足条件的元素放在一个新数组中,返回。不会改变原来的数组
  7. find,查找到符合要求的第一个元素,返回这个元素,后面的就不再遍历了。如果找不到,则返回undefined
  8. findIndex,查找符合条件的第一个元素下标,返回这个下标,后面的元素就不再遍历。如果找不到,则返回 -1
  9. every,返回的是布尔值,当数组中的每个元素都满足回调函数中的条件时,返回true,否则返回false。当有一个元素不满足时返回false且后面的元素不再进行检验。不对空数组检查,不改变原数组
  10. some,返回的是布尔值,当数组中有一个元素满足条件,就返回true且剩余的元素不再进行检验,否则返回false。
  11. reduce,对数组中的每个元素执行一次reduce函数,将执行的结果与当前元素进行计算
arr.reduce(function(pre,cur,index,arr) {

},init)

pre:必须,累计器的返回值,或上一次执行reduce的返回值。如果指定了初始值Init,则pre是初始值;如果没指定,pre是数组中第一个元素值
cur:必须,当前正在处理的元素
index:正在处理的元素下标
arr:数组本身
init:迭代的初始值
可以对数组求和求积,求元素出现次数,去重

4、数组去重的方式

  1. indexOf() === -1去重,遍历需要去重的数组,当新数组中查找不到该元素时,就把该元素push到新数组中。
  2. 双层for循环+splice去重,遍历数组,当后一个元素和前一个元素相同时,则调用splice(j,1)
function unique(arr) {
	for(let i = 0; i < arr.length; i++) {
		for(let j = i + 1; j < arr.length; j++) {
			if(arr[i] ===arr[j]) {
				arr.splice(j,1);
			}
		}
	}
	return arr;
}
  1. Map()去重,遍历需要去重的数组,将数组元素作为Key值存放在map中。利用Map中key值不能重复的特点,当map中已经有了key值时,就不要放到新数组;当map中没有key值时,push到新数组中。
function unique(arr){
	let array = [];
	for(let i = 0; i < arr.length; i++) {
		if(array.indexOf(arr[i]) === -1) {
			array.push(arr[i]);
		}
	}
	return array;
}
  1. ES6的Set()去重,通过new Set(arr)将数组转为set,再通过Array.from(s)将set转为数组。array = […new Set(arr)]
function unique(arr){
	return Array.from(new Set(arr));
	// return [...new Set(arr)];
}
  1. 先sort排序,再使用for循环去重
  2. 通过filter去重,当数组中元素出现的第一个索引为当前索引时,就保留
function unique(arr) {
	return arr.filter((item,index,arr) {
		arr.indexOf(item,0) === index;
	}
}
  1. reduce去重:迭代功能实现数组的扩展,判断当前元素cur是否已经添加到数组中,如果不存在就push到pre中
arr.reduce(function(pre,cur,index,arr){
	if(pre.indexOf(cur) === -1) {
		pre.push(cur);
	}
	return pre;
},[])

5、数组中常见的方法

  1. push pop unshift shift splice sort
  2. concat合并数组 join变成字符串 slice截取
  3. indexOf includes find foreach reduce

6、OSI七层模型

1、应用 表示 会话 传输 网络 数据链路 物理层
2、TCP属于传输层

7、三次握手

建立一个TCP连接时,需要客户端和服务端一共发送三个包。来确认双方的发送和接收能力正常,方便后续的数据可靠传输

  1. 第一次握手:客户端向服务器发送一个SYN包,其中同步标志位SYN=1,发送一个初始序列号seq = x,客户端在发送等待状态

  2. 第二次握手:服务端接收了客户端发过来的包,并发送一个自己的SYN包作为应答,确认号是初始序列号+1,并发送一个自己的序列号y。其中同步标志位SYN=1,确认标志位ACK=1,确认序号ack = x+1,并发送自己的序列号seq = y

  3. 第三次握手:客户端收到了来自服务端的应答包,发送一个自己的包告诉服务端自己接收成功。其中确认标志位ACK=1,确认序号ack = y+1,序列号是seq = x+1

  4. 为什么非要三次不能两次?
    第一次握手:客户端发送包服务端收到,此时服务端可以得知:客户端的发送能力和服务端的接受能力正常
    第二次握手:服务端发送包 客户端收到。此时客户端可以得知:客户端的发送接受能力正常,服务端的发送接收能力正常。但是服务端不能得知客户端是否成功接收
    第三次握手:客户端发送包 服务端收到。此时服务端可以得知:服务端的发送接收能力正常,客户端的发送接收能力正常

  5. 携带数据
    第一次握手时携带数据让服务器更加容易受到攻击,第二次握手不可以携带,第三次握手可以携带
    第一次握手:客户端发送网络包,服务端收到了。
    这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
    第二次握手:服务端发包,客户端收到了。
    这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
    第三次握手:客户端发包,服务端收到了。
    这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常

8、四次挥手

释放一个TCP连接需要客户端和服务端发送四个包。客户端和服务端都可以发起释放连接请求。

  1. 客户端发送一个FIN包,FIN = 1,seq = u
  2. 服务端收到客户端的FIN,发送一个确认应答包,ACK = 1,ack = u +1,seq = v
  3. 服务端也想关闭连接时,发送一个FIN包,FIN = 1,ACK = 1,ack = u+1,seq = w
  4. 客户端收到服务端的FIN+ACK后,发送一个ACK包应答,ACK = 1,ack = w+1

9、状态码

(1)2:成功 200
(2)3:重定向
301永久重定向:请求的资源永久移到别的位置。一般用在跨域中,如访问http://www.baidu.com会返回301并进入https://www.baidu.com
302临时重定向:请求的资源临时从别的URL访问。如未登录时访问主页会重定向到登录页面
(3)4:客户端错误 403跨域 404资源请求不存在
(4)5:服务端错误

10、sessionStorage localStorage cookie

都是用来存储数据的,有生命周期和作用域两点不同

10.1localStorage

  1. 生命周期:永久的,浏览器关闭后,数据仍然存在,除非手动删除数据,否则数据不会丢失
  2. API:用setItem(key,value)来存储键值对 getItem(key)取值,removeItem(key)删除,clear()清空
  3. 存储空间比较大 有5M

10.2 sessionStorage

  1. 生命周期:在浏览器会话期间有效,当浏览器关闭时数据被销毁
  2. API和存储空间与localStorage相同

10.3 cookie

  1. 生命周期:在设置的过期时间之前,一直有效
  2. 存储空间比较小,4K,存储个数一般不超过20个

10.4使用场景

vue是单页面应用,基本操作是在一个页面内进行路由跳转,多数情况下使用sessionStorage。
1、sessionStorage可以保证在页面打开时,sessionStorage中数据是空的
2、如果使用localStorage,每次打开页面,localStorage都存储上一次页面打开时的数据

11、http https

  1. http:超文本传输协议,用于web浏览器和服务器之间传递信息。信息是以明文形式存在,不对数据进行加密,不适合传输卡号密码等。
  2. https:在http基础上增加SSL/TSL,依靠证书来确认服务器身份真实,并对通信数据进行加密处理。
  3. 区别
    (1)http无连接无状态,不太安全,传输信息是明文传输,不对数据进行加密处理,默认在80端口
    (2)https是加密传输协议,具有不可否认性,默认在403端口

12、tcp udp

  1. 连接:tcp面向连接,需要三次握手建立连接四次挥手释放连接,udp无连接
  2. 可靠性:tcp是可靠传输,传输过程中出现丢包时会重传,udp是不可靠传输但会尽最大努力交付
  3. 工作效率:udp实时性高,不需要建立连接也没有重传机制
  4. 是否支持多对多:tcp点对点,udp支持一对一 和 一对多
  5. 首部大小:tcp20字节,udp8字节

13、get post

get post是HTTP请求的两种方式

  1. get请求一般用于从服务器获取数据,post一般用于发送数据到后台
  2. get请求参数携带在地址栏url中,以?分割URL和传输数据,参数之间以&相连。安全性低,参数长度有限制,一般是不超过2048字符;post请求的参数携带在请求体中,不显示在地址栏,安全性较高,长度无限制
  3. get请求有缓存机制,保存在浏览器历史记录中;post请求无缓存,不保存在历史记录中
  4. get请求产生一个tcp包,浏览器把header和data一起发送出去,服务器响应200并返回数据;post请求产生两个tcp包,浏览器先发送header,服务器响应100continue,再发送data,服务器响应200并返回数据

14、从输入url到获取页面经历什么

  1. DNS预解析:从url中获得域名,通过DNS将域名解析成对应的IP地址
    (1)查找浏览器缓存:如果有目标IP,则返回
    (2)查找本地缓存:如果host中有目标IP,则返回
    (3)查找路由器缓存
    (4)

  2. 建立TCP连接:在DNS获取到目标服务器的IP地址后,通过三次握手建立连接
    (1)浏览器向目标服务器发送请求报文SYN=1
    (2)服务器接收请求报文后,发送一个应答报文ACK=1
    (3)浏览器收到服务器发来的报文后,发送一个报文作为应答

  3. 浏览器发送HTTP请求:TCP连接建立完成后,浏览器向服务器发送一个get请求

  4. 服务器处理相关的请求并返回结果:有些服务器会进行重定向,状态码为301,返回的响应数据中有Location,可以得到重定向之后的地址,浏览器根据这个地址重新发送http请求。服务器处理完毕后返回结果

  5. 关闭TCP连接:通过四次挥手关闭连接
    (1)浏览器向服务器发送释放连接请求,FIN = 1,浏览器不再发送数据
    (2)服务器接收后,发送一个应答报文,ACK = 1,服务端把没发完的数据继续发送
    (3) 服务器向客户端发送释放连接请求,FIN = 1
    (4)浏览器接收服务端发的请求,给出确认,ACK = 1,连接释放

  6. html解析与渲染页面:将html解析成DOM树,CSS树,渲染到页面上

Vue

1、双向绑定原理

  1. vue通过数据劫持结合发布订阅者模式,核心是通过Object.defineProperty()方法重新定义了set get函数来实现数据劫持,在数据变化时发布消息给订阅者,触发相应的监听回调。让数据和视图同步变化。
  2. Object.defineProperty()有三个参数,obj要定义属性的对象,prop是定义或修改的属性,des是具体的改变方法。一般是set和get方法,get函数在获取属性值时调用,set函数在修改属性值时调用。
  3. 消息订阅和发布:(1)在vue初始化时,所有的数据和属性被监听器Observe监听,当数据或属性变化时,Observe发布消息给订阅者watcher(2)每一个订阅者watcher都绑定一个更新函数,当收到监听器的消息时,执行更新函数,更新视图(3)每个数据都绑定一个消息订阅器Dep,Dep中存放用到这个数据的订阅者watcher。当Observe监听到数据变化时,就通知Dep,再通知watcher触发更新函数(4)有个解析器Compile,用来解析每个节点的相关指令
    总结:消息订阅和发布:vue初始化时,所有的数据和属性被监听器Observe监听,当数据或属性变化时,发布消息给订阅器Dep,Dep中存放用到这个数据的所有订阅者Watcher,会通知Watcher触发更新函数,实现数据变化达到视图更新。

2、MVVM

  1. vue采用数据劫持结合发布订阅模式来进行双向绑定的,通过Object.defineProperty劫持属性和数据的setter getter,数据变动时发布消息给消息收集器Dep,再由Dep去通知相应的订阅者Watcher,去触发对应的更新函数。
  2. MVVM是双向绑定的入口,整合了Observer监听器,Compile模板解析器和Watcher订阅者。通过Observe监听model数据的变化,通过Compile解析模板指令,通过Watcher建立桥梁,达到数据变化实现视图更新,视图更新实现数据变化的双向绑定

3、nextTick()

  1. 在下一次DOM更新结束后,延迟执行回调函数。在修改数据后调用nextTick,可以获取更新后的DOM。在nextTick函数中,可以基于更新后的DOM进行操作。
  2. 使用场景:(1)created生命周期钩子中,这个时候真实DOM还没有生成,如果对真实DOM进行操作会报错,将DOM操作放在nextTick中(2)如果想基于更新后的DOM元素进行操作,需要把对新DOM的js代码放在nextTick的回调函数中。

4、生命周期函数

vue实例从创建到销毁的整个过程,包括开始创建、初始化数据、编译模板、挂载DOM、渲染、更新、渲染、卸载等一系列过程。在这个过程中有八个生命周期函数会自动触发。

  1. beforeCreate:创建之前,此时vue的挂载对象$el和data还没初始化,值为undefined
  2. created:创建完成,此时data已经存在,可以调用methods中的方法对data中的数据进行初始化。但$el还不存在
  3. beforeMount:挂载之前,此时vue实例的挂载对象$el和data都已经存在,挂载为虚拟的DOM节点,模板已经编译完成,但没有渲染到页面上。
  4. mounted:挂载完成,此时虚拟DOM节点已经渲染为真实DOM,渲染到页面上了。
  5. beforeUpdate:在数据更新之前调用,此时data中的数据还没有和最新的数据保持一致。
  6. updated:数据更新完成。
  7. beforeDestroy:在实例销毁之前调用,进行清除定时器,解除事件绑定操作
  8. destroyed:实例销毁,此时vue解除事件监听和dom绑定,但是dom结构仍然存在。

5、computed watch method

  1. computed:
    (1)计算属性,和data中的数据使用方法相同,写法类似于一个函数
    (2)必须有一个return返回值
    (3)computed有缓存机制
    (4)依赖data中的数据计算出来的,如果依赖的数据没有发生变化,就会使用缓存中的值
    (5)不支持异步处理
  2. watch:对数据或属性进行监听,当监听的数据属性发生变化时,立即执行handler函数,handler接收两个参数,newV oldV。
    (1)可以用deep:true深度监听对象中属性的变化。如果对某个对象进行普通监听,当对象的某个属性改变时,由于对象的引用地址不会改变,所以无法监听到,可以通过deep:true深度监听到对象中属性的变化
    (2)可以用immediate:true进行立即执行。当进行页面时,就立即监听数据或属性
    (3)watch没有缓存机制,当数据变化时,立即调用handler函数,watch支持异步操作。
  3. method:在模板中调用时,使用插值语法。在渲染模板时,会执行函数
  4. computed适合 一个属性受多个属性影响,比如求和
  5. watch适合属性变化时就执行回调函数的数据响应

6、vue优化方式

6.1代码层面

  1. v-if v-show分场景使用

  2. computed watch分场景使用

  3. v-for添加key值

  4. 长列表性能优化
    当列表只是展示数据时,不需要对列表进行劫持和监听。使用Object.freeze()冻结对象,这样对象就不会再改变了。

  5. 图片懒加载
    只有当图片进入可视区域再进行加载,提高加载性能和用户体验。
    使用vue-lazyload插件进行懒加载,先npm安装插件,在main.js中import导入插件并使用Vue.use(),将图片img的src属性改成v-lazy

  6. 路由懒加载
    vue单页面应用,路由组件很多,可能出现首屏加载过慢,出现白屏问题。可以将不同的路由分隔成不同的代码块,当路由被访问时,才加载对应的组件。
    不再直接import导入路由组件,使用异步加载的写法,const Foo = () => import("…/ …/ ")

  7. 事件销毁
    在vue的beforeDestroyed中,对指令和事件监听解除绑定,但是addEventListener不会自动解除绑定,需要手动removeEventListener

  8. 第三方插件的按需引入,使用babel-plugin插件

6.2webpack层面

6.3web技术层面优化

  1. 开启gzip压缩:减小文件体积,使传输速度更快。通过服务端,使用express做gzip压缩
    (1)安装compression,npm i compression --save
    (2)创建一个compression, var compression = require(‘compression’)
    (3)app = express()
    (4)在其他中间件之前使用compression app.use(compression());
  2. CDN加载:浏览器下载css js文件都需要连接服务器,但服务器带宽有限制。可以通过不同域名加载文件,可以使并发下载文件数量增多。

7、vue-router路由导航

vue是单页面应用,需要设置不同的路由地址来展示不同的路由组件。通过vue-router配置路由和组件的映射关系。

7.1安装配置

  1. 通过npm 安装vueRouter
  2. 创建一个router文件夹,新建Index.js文件,将vue 和vuerouter导入,并使用
  3. new一个VueRouter对象,对象里面放一个数组routes用来配置路由和组件之间的映射关系
  4. 将vuerouter对象export暴露出去

7.2使用

  1. 创建路由组件
  2. 在index文件中,import导入路由组件
  3. 在VueRouter对象的routes数组中配置映射关系,path表示路径,component表示对应的路由组件
  4. 在app.vue中,通过router-link和router-view来展示路由组件。router-link是vue内置的,会渲染成a标签,router-view会根据路径动态展示不同的组件
    (1)router-link:使用to指定跳转的路径,使用tag指定这个路径渲染成什么标签,默认是a标签
    (2)router-view:可以根据当前的路由地址,动态渲染不同的路由组件。
  5. 如果使用路由嵌套,需要增加一个children属性,在children中配置path和component,这里Path不需要加/

7.3路由重定向、路由模式、懒加载、动态路由

  1. 路由的重定向:输入url后默认进到首页或者登录页,需要新增一个路由配置,path:‘/’, redirect: ‘/Home’
  2. 路由模式:一共有2种,hash和histroy,默认是hash。

hash模式:路由默认的模式,地址栏中有#,#后面的路径不是真实的路径,几乎能兼容所有的浏览器和服务器。使用hash模拟完整的url,所以url改变时,页面不会重新加载
原理:使用onhashchange事件,监听Hash,当hash值变化时,执行hashchange事件中的js代码跳转到对应的页面。

history模式:在new VueRouter时,配置mode为histroy。url中的路径是服务端根目录下的真实路径,如果根目录下没有对应的文件,就会报错404。就需要在nginx代理中配置每一个route路由,缺少某个路由的配置就会返回404。刷新时可能存在404问题。

Histroy对象保存了当前窗口访问的历史记录。
属性:histroy.length 获取当前窗口访问路径的个数,histroy.state 获取histroy对象的当前状态。
方法:可以通过go() back() forward()实现跳转,后退,前进,go的参数为正值表示前进,为负值表示后退。
pushState()方法可以向Histroy历史记录中添加一个访问记录,一般有三个参数,object可以展示到新的页面,如果不需要展示,写为null。title是标题,一般为空。url是新的地址,与原来的地址在同一个域。
replaceState()方法用于修改当前的记录,用法和pushState一样

popState事件:在histroy有变化时,比如调用了go() back() forward()方法时,popState事件会被触发,触发后可以执行对应的回调函数。

  1. 懒加载:在index.js文件中,不直接导入路由组件,采用异步加载的形式。这样当进入不同的路径时才加载对应的路由组件,避免刚进入页面时,加载过慢,首屏出现白屏的问题。

  2. 动态路由:有的页面路径是不确定的,比如根据用户id进入不同的页面。(路由传参params方式)
    (1)需要在配置文件path时使用 path:'/user/:userId’冒号形式写上动态路由
    (2)在app.vue中,router-link需要使用v-bind动态拼接user和userId v-bind:to = " ‘/user/’ + userId "
    (3)如果想要在别的页面获取用户id,可以使用this.$route.params.uid

  3. this.$router拿到创建的VueRouter对象,可以调用push() replace()方法,这个对象里面包含了routes很多个路由

  4. this.$route拿到当前活跃的路由,可以点出来params参数

7.4路由导航守卫

主要是用来进行跳转验证和拦截的,分为三类,全局导航守卫,路由独享守卫和组件内部守卫

  1. 全局导航守卫:beforeEach afterEach
    (1)全局前置守卫有三个参数,to from next,分别表示要去的路由地址和现在的路由地址,next表示放行,
    (2)afterEach只有to from两个参数
  2. 路由独享守卫:beforeEnter,在配置路由和组件间的映射关系path component时使用,也有to from next三个参数,和beforeEach相同
  3. 组件内部守卫:beforeRouterEnter beforeRouterLeave beforeRouterUpdate,和data mounted是平级的。beforeRouterEnter在组件渲染时调用,还不能获取this实例,beforeRouterUpdate在路由改变且组件被复用时调用,beforeRouterLeave在导航离开路由对应的组件时调用,一般用在用户修改了信息但还没保存,可以通过next(false)
    阻止用户离开界面。

8、虚拟DOM及优缺点

  1. 虚拟DOM是一个js对象,用来描述真实DOM结构。
  2. 优点:虚拟DOM可以跟踪当前dom的状态。它会根据当前的dom元素生产一个可以描述它结构的虚拟dom。当dom数据改变时会重新生成一个新的虚拟DOM。对新旧虚拟DOM通过diff算法进行比较,得出一个最优的更新方法。将计算出来的不同点存储在patch对象中,通过patch中记录的不同点对dom进行局部更新,提升渲染的效率和用户体验。

9、diff算法

  1. diff算法是用来比较虚拟DOM节点,将两个虚拟DOM的不同点存放在patch对象中,根据patch中记录的不同对dom进行局部更新。

9.1diff算法如何比较

  1. 同层级比较,不会跨层级比较;循环从两边向中间比较;采用深度优先的比较策略
  2. 如果两个节点类型不同,会把旧的虚拟DOM中的节点删掉,并添加一个新的节点和子节点
  3. 如果两个节点类型相同,更新旧节点中的属性
  4. 如果两个节点是同类节点,就是他们的节点类型和属性相同,只是里面的文本内容不同,就采用就地复用的策略,直接更新旧节点中的文本内容。

10、v-for key

10.1 v-for更新数据列表绑定key

  1. 在使用v-for更新已经渲染的元素列表时,会采用就地复用的策略:根据key值判断某个元素是否需要修改,如果需要,就重新渲染,否则就复用之前的元素。使用key可以提升渲染的效率
  2. 使用唯一的id作为key值,不使用index。如果使用index,在列表末尾添加数据时和使用id是没区别的,都只有最后一条数据需要重新渲染。
  3. 但是如果在列表中间添加一条数据,使用index时,会将这条添加的数据以后的每个数据都需要重新渲染,降低效率。

10.2 diff算法中使用Key

在同层的一组节点,使用key作为每个虚拟节点的唯一标识,通过对比新旧虚拟节点的key值,来判断节点是否需要改变,更高效地更新虚拟DOM

11、vue组件通信方式

11.1父子通信

  1. props:子组件通过props接收父组件传过来的数据,父组件通过v-bind往子组件传值。props可以接收任何一种数据类型,只能父组件向子组件传数据,形成一种单向的下行绑定
  2. $ emit:子组件通过$emit绑定一个自定义事件,事件触发时向父组件传递数据,在父组件中通过v-on监听事件,并接收传过来的数据
  3. ref/refs:当子组件身上有一个ref属性时,ref就指向了子组件实例。可以通过this.$refs.xxx获取子组件实例,获取它的data或调用子组件的方法。
  4. provide/inject注入依赖:适合父子、祖孙组件通信。provide用来提供数据,写法和data一样,inject用来接收数据。在父级组件中,通过provide向子孙组件提供一个数据,在子孙组件中通过inject注入数据
  5. parent/children:通过$ parent访问父组件实例,可以获取父组件身上的数据,也可以调用方法。通过$children可以获取一个数组,数组中存放的是所有的子组件实例,且是无序的

11.2跨代通信

  1. $ attrs $ listeners实现跨代通信:$ attrs可以继承父组件中除了props style class的所有属性,$ listeners是一个对象,包含这个组件身上所有的监听器

11.3任意组件间通信

  1. eventBus事件总线:注册一个空的vue作为事件总线。通过$ emit触发事件并把数据发送出去,通过$on监听事件,对接收的数据作出相应的回调函数。相当于把数据存储在事件总线中,其他的组件通过事件总线来获取数据。
  2. vuex

12、vuex

vuex适应于任何组件通信,即使是两个无关联的组件也可以使用vuex共用一组数据。它相当于一个公共的仓库,保存着所有组件都能共用的数据。

12.1普通使用

创建一个store文件夹,新建一个index.js文件,导入vue 和 vuex,并Vue.use(vuex)。通过new Vuex.store新建一个store,并export暴露出去,在main.js中导入store并全局注册。
vuex有以下几个属性

  1. state:里面是一些自定义的变量,保存数据,相当于data。在app中可以通过this.$store.state获取数据。
  2. mutations:存储的是方法,用来改变state中的数据,mutations中的方法有两个参数,第一个是state,第二个是传过来的参数,对state中的数据进行同步修改。在app.vue中通过this.$store.commit触发mutations中的方法。commit中有两个参数,第一个是commit中的方法,第二个参数是传过来的值。
  3. actions:存储的也是方法,暴露给用户使用。方法中有两个参数,第一个是context上下文,第二个是传过来的参数。actions中的方法是通过commit提交mutations中的方法进行异步修改。在app.vue中通过this.$store.dispatch触发actions中的方法,dispatch中有两个参数,第一个参数是actions中的方法,第二个参数是传过去的参数。

12.2模块化使用

可以新建state mutations actions文件,里面分别存储所有的数据 所有的方法 并暴露出去,在index.js中导入这些模块,并在store中使用。

13、data写成函数式

vue组件是可以被复用的,当创建一个vuecomponent实例时,data函数就会生产一份新的data对象,这个对象就是vue实例的私有数据,每次复用一个组件时,都会生成一份新的私有数据,不同的实例数据之间不会有影响。

14、v-model

v-model可以在input textarea上创建元素的双向数据绑定,它可以监听用户的输入事件来更新数据。用户在登录注册时提交的用户名 密码 等使用v-model进行双向绑定。

  1. 原理:本质是语法糖,通过v-bind绑定value属性,通过v-on监听input事件,将输入的最新的值赋值给绑定的属性身上
  2. v-model是双向数据绑定,但是是单向数据流,比如props就是单向数据流,将父组件的值传给子组件。

15、keep-alive

可以保存组件的状态,在tab栏切换的时候,把不活跃的组件缓存起来,但不销毁,这样当tab切换回来时,不需要重复渲染DOM,提高渲染的效率。

  1. props:include exclude max
  2. 生命周期函数:actived deactived
  3. keep-alive有一个最大缓存数量,采用的是最久未使用法LRU。当缓存一个组件时,就把组件放到最上面,当到了最大缓存数量时,从最下面的组件开始删除。

16、vue3与vue2 的对比

  1. 源码上采用typescript编写
  2. 新增了组合API,将实现同一种功能的代码封装在一个函数中,最后在setup中调用
  3. 新增了三个响应式函数 reactive toRefs ref
    (1)reactive()将引用类型的数据,转变成响应式数据,页面随着数据变化会重新渲染
    (2)toRef()将响应式对象的每个属性也变成响应式对象,它的参数是一个响应式对象,将每个属性解构出来,变成一个响应式对象,这个对象有个value属性存放值。
    (3)ref()将基本数据的类型转为响应式对象,这个对象也有value属性,用来存放值。
  4. 生命周期函数的变化:
    (1)beforeCreate created被setup替代
    (2)beforeMount mounted beforeUpdate updated 在vue3中变成OnbeforeMount onMounted onBeforeUpdate onUpdated
    (3)destroy变成了unmount,所以beforeDestroy 变成onbeforeUnmount destroyed变成onUnmounted
  5. vue3的响应式系统从Object.defineProperty变成proxy,它可以监听到数组索引 数组长度的变化,也可以监听到对象新增属性

17、v-if v-show

v-if v-show都是用来控制元素的显示与隐藏。

  1. v-show是通过修改元素的display属性来控制元素的显示与隐藏,当display为none时,元素就隐藏。更适合频繁改变元素显示状态时使用。比如点击按钮显示或隐藏某个区域
  2. v-if是通过增加或删除虚拟的DOM节点来控制元素的显示与隐藏,所以如果频繁操作dom会影响性能。它适合元素状态只会显示或隐藏,后续不再改变时使用。比如使用v-if v-else动态地显示一级或二级标签。

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值