> 文章列表 > 面试题整理

面试题整理

面试题整理

1、new关键字干了什么?

let a = new Object() = let a = Object() = let a = {} 都会创建一个新对象

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

function Person(name) { // 构造函数Person()this.name = name;// this.prototype = Object
}
const a = new Person('ycl');
  1. 创建一个空的JavaScript 对象,即{}调用构造函数Object()

    • const a = {};
  2. 设置该空对象的原型__proto__,为构造函数的原型对象prototype 实现原型继承

    • a.__proto__ = Person.prototype = Object; // true
    • 实例化对象的原型__proto__ 就是其构造函数的原型对象prototype
  3. this指向空对象并执行函数体;

    • a.name = 'ycl';
    • a.constructor = f Person(name)
  4. 判断构造函数的返回值,以决定最终返回结果 – 返回新对象

    • 返回基础数据类型,则忽略返回值

      function Person(name) {this.name = name;return 666;
      }
      const a = new Person('ycl');
      // {name:'ycl'}
      
    • 返回引用数据类型(return的返回),则new操作符无效,返回的是return内容

      function Person(name) {this.name = name;return { // Object,Array,Function,Data...age: 18 };
      }
      const a = new Person('ycl');
      // {age:18}
      

2、闭包是什么?

  1. 闭包是什么

    • 函数和函数内部能访问到的变量的总和。
  2. 如何生成闭包

    • 函数内嵌套函数,函数执行完毕以后,内部函数会被引用,这样内部函数可以访问外部函数中定义的变量。
  3. 闭包的特性

    • 如果生成闭包,外部函数执行完毕,其中的局部变量可能被内部函数使用,所以不能销毁,因此内部函数能一直访问到这些局部变量,直到引用解除。
  4. 缺点:

    • 内存溢出(内存泄漏)
      • 使用闭包但是未及时销毁,导致闭包中的私有变量一直存在于内存中,导致js的内存泄漏。应该及时销毁不用的闭包变量,从而避免内存泄漏。
  5. 优点:

    • 避免全局污染

      • 隐藏变量,避免放在全局有被篡改的风险。
    • 延长生命周期

      function outer() {var a = 1;function inner() {console.log(a);}return inner;
      }var b = outer();
      

3、原型链是什么?

JavaScript中, class 是关键字,但也只是语法糖。

JavaScript 仍然是基于原型的。几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。

  • 每个实例对象(object)都有一个私有属性(称之为 proto)指向它的构造函数的原型对象(prototype

  • 该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null

  • 理解 p 所在的原型链

    1. p 实例对象 (对象)Person {name: 'ycl'}
      • p.__proto__ 实例对象的原型 类似(指针){constructor: ƒ Person(name)}
    2. Person.prototype 实例对象的构造函数的原型对象 (对象){constructor: ƒ Person(name)}
      • Person.prototype.__proto__ 原型对象的原型 类似(指针) {...__proto__: null...}
    3. Object.prototype 对象的原型对象 (对象) {...__proto__: null...}
      • Object.prototype.__proto__ 对象的原型对象的原型 null
    4. null.prototype null的原型对象 // 报错 null没有原型,查找原型链结束
  • PS:

    • __ proto__是一个访问器或索引,用其找到构造函数的prototype
    • prototype是一个构造器,里面包含了构造函数里的各种属性,方法
  • 例子:

    function Person(name) {this.name = name
    }
    var p = new Person('ycl');
    console.log(p.__proto__) // Person.protptype (Object)-- 实例对象的原型 就是 实例对象构造函数的原型对象
    console.log(p.__proto__.__proto__) // Object.prototype
    console.log(p.__proto__.__proto__.__proto__) // null -- Object原型对象没有原型了(找到头了)
    console.log(p.__proto__.__proto__.__proto__.__proto__) // err报错 -- null是基础数据类型,没有原型
    console.log(p.constructor) // Person -- 实例化对象的构造函数
    console.log(p.prototype) // undefined -- 实例没有prototype属性
    console.log(Person.constructor) // Function 一个空函数 
    console.log(Person.prototype) // 打印出Person.prototype这个对象里所有的方法和属性
    console.log(Person.prototype.constructor) // Person
    console.log(Person.prototype.__proto__) // Object.prototype
    console.log(Person.__proto__) // Function.prototype
    console.log(Function.prototype.__proto__) // Object.prototype
    console.log(Function.__proto__) // Function.prototype
    console.log(Object.__proto__) // Function.prototype
    console.log(Object.prototype.__proto__) // null
    

4、call、apply、bind的区别是什么?

改变this指向的。(还有箭头函数)

如果函数处于非严格模式下,则this指定为 nullundefined 时会指向全局对象window

  • 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)

    1. 直接写多个参数
    2. 立即执行函数
  • 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])

    1. 多个参数写成数组
    2. 立即执行函数
  • var newFn = 函数名.bind(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)

    1. 直接写多个参数

      • newFn(要给函数传递的参数n)如果参数多余,则不生效(可以在原函数和新函数两个位置传参,优先考虑的是binf内部的参数)
      • 多次使用bind改变this指向,同时传入参数,则函数形参依次叠加
    2. 不会立即执行函数,而是返回一个已经改变了 this 指向的函数

5、js数据类型

  • 值数据类型(基本数据类型):存放在栈(stack)内存中的简单数据段,变量直接存储数据

    1. Number 隐式的编码为浮点类型
    2. String
    3. Boolean
    4. Undefined
    5. null
    6. Symbol (ES6新增)唯一并且不可变的原始值并且可以用来作为对象属性的键
    7. BigInt 可以表示任意大小的整数,存储和操作巨大的整数,甚至超过 Number 的安全整数限制
  • 引用数据类型(复杂数据类型):存放在堆(heap)内存中的对象,栈内存中的变量存放的是堆内存中具体内容的引用地址

    • Object(统称)

      • ObjectArrayfunctionDateRegExp

6、js数据类型判断

  • typeof() 查看字面量或者变量的数据类型

    • number、string、boolean、Symbol、undefined及function
    • 注意:对于null及数组、对象,typeof均检测出为object,不能进一步判断它们的类型。
  • .constructor 判断构造函数

    • 注意:undefined和null没有contructor属性

      console.log(false.constructor === Boolean);// true
      
  • instanceof判断一个对象的构造函数是否等于给定的值(一般用于判断自定义构造函数实例。)

    ({}) instanceof Object // true
    [] instanceof Array // true
    new Date() instanceof Date // true
    /123/g instanceof RegExp // true
    
  • Object.prototype.toString.call()

    • 可以用来区分数组、null等引用类型
    • 自定义对象的判断只能得到"[object Object]"的结果。
    Object.prototype.toString.call(1);  '[object Number]'
    Object.prototype.toString.call('1'); '[object String]'
    
  • isArray()

  • isNaA()

7、eventLoop中宏任务和微任务?

事件循环eventLoop是js引擎执行js代码的机制,用来实现js的异步特性。

步骤:

  1. 执行一个宏任务。
  2. 执行微任务,直到微任务队列为空。
  3. 循环1、2。
  • 宏任务:

    • script整体代码setTimeoutsetIntervalrequestAnimationFrameI/O
  • 微任务:

    • Promise.thenPromise.catchnextTick

8、防抖和节流?

  • 防抖(输入框):

    • 短时间内用户多次触发同一个事件,只需要执行最后一次
    • 用户不停触发,可能永远不会收到反馈
    • 用于无法预知的用户主动行为
    • 触发后,启动定时器,若再触发则重置计时器,直到定时器结束,执行请求
  • 节流(验证码):

    • 用户同时段多次触发事件、只会执行第一次事件
    • 用户不停触发,会收到反馈
    • 非用户主动行为或者可预知的用户主动行为
    • 触发后,启动定时器,定时器结束前不会被再次触发

9、深浅拷贝有哪些方法?

深拷贝:

  1. 新对象的属性与源对象的属性不共享相同的引用(指向相同的底层值)的副本。
  2. 当更改源或副本时,一定不会导致其他对象也发生更改。

浅拷贝:

  1. 新对象的属性与源对象的属性共享相同的引用(指向相同的底层值)的副本。
  2. 当更改源或副本时,可能导致其他对象也发生更改。

拷贝的划分都是针对引用类型来讨论的

  • 基础数据类型拷贝:栈中变量存储的是值本省,拷贝会开辟新的内存空间,所以一定是深拷贝

  • 引用数据类型拷贝:栈中变量存储的是堆内存中真正数据内容的引用,所以有深浅拷贝之分

  • 深拷贝:

    • JSON.parse(JSON.stringify(能被序列化的JS对象)) – 先将对象转为JSON字符串,再转回(全新的)JS对象 – 注意有bug

    • 封装递归函数cloneDeep()

      • 思路:若属性为值类型,直接返回;若属性为引用类型,递归遍历。
      function deepClone (obj) {// 如果值 值类型 或 null ,直接返回if (typeof obj !== 'object' || obj === null) {return obj;}let copy = {};// 如果对象是数组if (obj.constructor === Array) {copy = [];}// 遍历对象的每个属性for (let k in obj) {// 如果 key 是对象的自有属性if (obj.hasOwnProperty(k)) { copy[k] = deepClone(obj[k]); // 递归调用 deepClone}}return copy;
      }
      
  • 浅拷贝

    • for循环

    • Object.assign() 将所有可枚举的自有属性从一个或多个源对象复制到目标对象,返回修改后的对象。拷贝的是(可枚举)属性值。假如源值是一个对象的引用,它仅仅会复制其引用值

    • Array.prototype.concat()合并两个或多个数组, concat方法会返回一个新数组

10、跨域是什么?解决方案是什么?

  • 跨域是什么

    • 考虑到网站数据安全,服务器不允许浏览器端ajax跨域获取数据(同源策略)
    • 所谓跨域,就是指协议+域名+端口任意一个不同即为跨域
  • 解决跨域的方案

    • JSONP

      • 浏览器对<script>标签的引入没有跨域限制(JSONP原理)
      • 通过其src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
      • 这种方式只能用于 get 请求。
      var script = document.createElement('script');
      script.type = 'text/javascript';// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
      script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
      document.head.appendChild(script);// 回调执行函数
      function handleCallback(res) {alert(JSON.stringify(res));
      }
      
      handleCallback({"success": true, "user": "admin"}) // 服务端返回
      
    • CORS(跨域资源共享)

      • 允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
      • 需要浏览器和服务器同时支持(当前所有浏览器都支持该功能,因此只需要在服务器端给响应添加头信息)
      • 跨域请求分类
        • 简单请求
          • 对于简单请求,浏览器直接发出一个CORS请求,并在请求头中加入一个 Origin 段来描述本次请求来自哪个源(协议 + 域名 + 端口)
        • 非简单请求
          • 浏览器会在正式请求之前发出一个OPTION请求来询问服务器是否支持该次请求,这个OPTION请求被称为‘预检请求’。
          • 在服务端回应允许后,浏览器才会发出真正的非简单请求,和简单请求一致。
    • nginx代理

      • 实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段

11、@import 和 link的区别?

外部引入CSS有2种方式:@import、link

  1. 从属关系区别

    • link是html标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。(加载任意文件,如图标)
    • @import是 CSS 提供的语法规则,只有导入样式表的作用(在css文件中使用)。(只能加载样式)
  2. 加载顺序区别

    • link标签引入的 CSS 在页面加载时被同时加载(异步加载)
    • @import引入的 CSS 在页面加载完毕后被加载(同步加载)
  3. 权重区别

    • link方式的样式的权重高于@import
  4. DOM可控性

    • link标签 支持使用javascript改变样式

    • @import不支持

12、fixed、relative、absolute的区别?

三者共同点,都是相对于某个基点的定位,不同之处仅仅在于基点不同

  • fixed 窗口定位

    1. 定位基点是视口(viewport,浏览器窗口),即定位基点是浏览器窗口置
    2. 搭配topbottomleftright这四个属性一起使用
    3. 元素的位置不随页面滚动而变化,好像固定在网页上一样。
  • relative 相对定位

    1. 定位基点是元素的默认位置,即当前元素为static定位时的位置
    2. 搭配topbottomleftright这四个属性一起使用,用来指定偏移的方向和距离。
  • absolute 绝对定位

    1. 定位基点是元素的上级元素(一般是父元素)
    2. 限制条件:定位基点不能是static定位,否则定位基点就会变成整个网页的根元素html
    3. 搭配topbottomleftright这四个属性一起使用,用来指定偏移的方向和距离。
    4. 脱离文档流,元素所占空间为零,周边元素不受影响。

13、localStorage、sessionStorage、cookie的区别?

一、存储时效不同

  • cookie 如果不设置过期时间 关闭页面或者浏览器就没有
  • sessionStorage 会话缓存,有效期是仅保持在当前页面 关闭当前会话页面或者浏览器后消失
  • localStorage 在不手动删除的情况下,永久存储

二、存储的大小不同

  • cookie 一般存储 5kb左右 一般存50条
  • localStorage、sessionStorage 一般在5M左右

三、与服务端通信

​ 1.cookie可以和服务端进行通信 一般请求头 存储关键信息

​ 2.localStorage、sessionStorage 只能前端存储

四、读写的便捷度

​ 1.localStorage、sessionStorage 操作更简单

五、支持的浏览器

​ 1.cookie 出现比较早 支持所有的浏览器

​ 2.localStorage、sessionStorage 不支持低版本的ie IE8版本之下的都不支持

14、动画样式?

  • animation 指定一组或多组动画(执行动画)

  • transition 为一个元素在不同状态之间切换的时候定义不同的过渡效果(过渡动画)

  • transform 旋转,缩放,倾斜或平移给定元素(位移)

  • @keyframe 通过在动画序列中定义关键帧的样式来控制 CSS 动画序列中的中间步骤(自定义动画)

15、数组去重有哪些方式

  • set

    const res = Array.from(new Set(arr)) 
    // Array.from() :对一个类似数组或可迭代对象创建一个新的浅拷贝的数组实例。
    
  • weakset

    // WeakSet 结构与 Set 类似,也是不重复的值的集合,只有三个方法,没有属性
    // WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
    // WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
    // WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。
    
  • 数组循环方法

    let len = arr.length
    for (let i = 0; i < len; i++) {for (let j = i + 1; j < len; j++) {if (arr[i] === arr[j]) {arr.splice(j, 1)len-- // 减少循环次数提高性能j-- // 保证j的值自加后不变}}
    }
    
  • filter、indexOf

    // filter不会改变原有数组的值,产生一个新的数组
    arr = arr.filter((item, index) => { return arr.indexOf(item) === index
    })
    
  • includes

    // includes判断字符串或者数组里是否包含这一项,如果包含 返回true 反之 返回false
    const newArr = []
    arr.forEach(item => {if (!newArr.includes(item)) {newArr.push(item)}
    })
    
  • Map

    const map = new Map()
    const newArr = []
    arr.forEach(item => {if (!map.has(item)) { // has()用于判断map是否包为item的属性值map.set(item, true) // 使用set()将item设置到map中,并设置其属性值为truenewArr.push(item)}
    })
    

16、页面的重排、重绘有什么区别?回流机制是什么?

​ 盒子变化会重排、任意样式会引起重绘、回流就是重排重绘

重绘不一定导致重排,重排一定导致重绘

  • 重排(重构/回流/reflow)
    • 盒子变化会重排
    • 如果JavaScript修改了DOM元素的几何属性(位置、尺寸)将会重新计算style,并且需要更新布局树,然后重绘
  • 重绘
    • 修改任意样式会引起重绘
    • 只修改DOM的非几何属性(元素的背景颜色),则只会重绘不会重排
  • 回流机制
    • 回流就是重排重绘
    • 当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。
    • 每个页面至少需要一次回流,就是在页面第一次加载的时候。
    • 重绘和回流的存在导致真实DOM性能不佳,所以Vue、react和angular等框架增加了虚拟DOM技术,就是为了减少DOM的重绘和回流从而减少浏览器性能消耗=。

17、Promise的理解?

  • 提出Promise的原因

    • 解决异步请求时回调地狱问题
  • 三种状态的转换(只可能有两种情况)

    1. 初始状态 pending(进行中)
    2. 操作成功,调用 resolve 函数,状态变为 fulfilled(已成功)
    3. 操作失败,调用 reject 函数,状态变为 rejected(已失败)
  • then、catch和finally

    1. 接收成功时的结果 .then(回调函数)

    2. 接受失败时的结果.catch(回调函数)

    3. 无论成功与否都会调用.finally(回调函数)

  • Promise.all()

    • 只有全部Promise参数的状态都变成fulfilled(全部成功),状态才会变成fulfilled,此时全部Promise参数的返回值组成一个数组,传递给回调函数。
  • Promise.race()

    • 只要Promise参数之中有一个实例率先改变状态,其状态就跟着改变。第一个成功的Promise实例的返回值,就传递给当前的返回值。

18、var、const 和 let 的主要区别是什么?

  • 声明

    • var允许重复声明
    • letconst 不允许重复声明变量
  • 赋值

    • letvar声明的时候可以不赋值,const 声明的时候必须赋值
    • letvar声明的变量的值可以改变,const 声明的变量的值不可以改变
  • 预解析

    • letconst 声明的变量不会在预解析的时候解析(也就是没有变量提升)
  • 作用范围

    • var在函数内部声明,作用域为函数范围;在函数外部声明,作用域为全局范围
    • letconst 声明的变量会被所有代码块限制作用范围(块范围)

19、什么是事件委托(事件代理)?它有什么好处?

​ 减少事件数量、预测未来元素、避免内存外泄

  • 什么是事件委托(事件代理)
    • 原理:DOM元素的事件冒泡
    • 一种JavaScript中常用绑定事件的常用技巧。把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。
  • 事件委托有什么好处
    1. 减少事件数量
    2. 避免内存外泄
      • 如列表中,在ul上绑定会比在li绑定上少很多事件,少花费更多内存
    3. 预测未来元素
      • 新增子对象时无需再次对其绑定(动态绑定事件)
      • 如列表中,如果绑定事件在列表项li上,则对列表项的增删都将导致元素需要新绑定或解绑事件

20、JavaScript对象的几种创建方式

  1. Object构造函数式
const obj = new Object();
  1. 对象字面量
const obj = {};
  1. 工厂模式
function createPerson(name){var a =new Object(); // 创建一个新的对象a.name = name; // 向对象中添加属性return a;			
}
var obj = createPerson("羊羊");
  1. 构造函数
function Test() {} // Test被称为“类”或者“构造函数”。Test是t的构造函数。
const obj = new Test();
  1. 动态原型模式
  • 将所有信息封装在了构造函数中,而通过构造函数中初始化原型(仅第一个对象实例化时初始化原型),这个可以通过判断该方法是否有效而选择是否需要初始化原型。
function Person(name){ this.name = name; //属性    if (typeof this.sayName != "function"){              Person.prototype.sayName = function(){alert(this.name);        };             }
} var friend = new Person("羊羊"); 
friend.sayName(); 

21、虚拟Dom是什么?

虚拟节点Vnode的本质就是用树型结构的JS普通对象来描述真实dom结构的信息。

防抖机制、合并渲染

  • 如何创建虚拟Dom?

    1. render() – 创建组件虚拟 DOM 树
      • vue底层提供的一个用于js执行页面渲染的方法
    2. h() – 创建虚拟 DOM 节点 (vnode)
      • 创建一个普通JavaScript对象,它描述了真实的dom结构和属性
      • 称之为虚拟节点VNode
  • 决定如何渲染?

    • diff算法 – 用来对比新旧虚拟Dom的方法
  • 虚拟Dom的好处?

    • 成本低——运用防抖机制进行合并渲染

      • 页面的更新先反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制
      • 数据变动先在vnode中修改,再diff,最后对dom tree进行一次集中修改,减少游览器的重绘及回流

22、v-if和v-for的优先级

同时使用 v-ifv-for不推荐的,因为这样二者的优先级不明显

  • Vue2,在一个元素上同时使用 v-ifv-for 时,优先级v-for >v-if

    • 在每次渲染时候都要遍历列表并判断是否需要渲染,这个遍历操作会造成性能损耗。
  • Vue3,优先级v-if >v-for

    • 这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:

      <li v-for="it in list" v-if="!it.isDelete">{{ it.name }}</li>
      
    • 可以外面套一层<template>v-for移上去

23、路由传参有哪些方式?

​ query、查询参数、params、动态路由、meta

  • query 查询参数

    this.$router.push({path: '/detail',query: {id: id}})
    
  • params

    this.$router.push({name: 'Detail',params: {id: id}})
    
  • 动态路由

    { path: '/:articleName', component: Article }
    
  • meta

    { path: '/home', component: Home, meta: { reqquireLogin: true } }
    

24、vue-router有哪几种路由模式?实现的原理是什么?

在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。

routerview组件 – 路由渲染

  • Hash 模式 - -用createWebHashHistory创建
    • 在内部传递的实际 URL 之前使用了一个哈希字符
    • 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号,有一点点丑。这是最安全的模式,因为他兼容所有的浏览器和服务器
    • 原理:改变hash可以监听到hashchange事件
  • History(HTML5 模式) – 用 createWebHistory() 创建
    • URL看起来很正常
    • 需要添加一个简单的回退路由
    • 原理:ServiceWorker – 充当Web应用程序(服务器)与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作)

25、vue组件传值方法?

  • 父组件传参给子组件

    • 在父组件模板中的子组件标签上设置绑定属性v-bind进行数据传递(属性下发),子组件在props中接收属性
  • 父组件调用子组件方法

    • <my-table ref=“mynode” :list=“list” @parentevt=“parentCb”>
    • this.$refs.mynode.changeList()
  • 子组件修改父组件参数

    • 方法一

      • 子组件模板的标签中,自定义事件@event="$emit(父组件的自定义事件,参数...)"发送给父组件
      • 父组件模板中的子组件内,监听自定义事件@父组件的自定义事件="处理器"触发处理器来进行相关操作
    • 方法二

      • 子组件模板的标签中,自定义事件@event="$parent.处理器(参数)"直接将数据传给父组件的处理器进行相关处理
  • vuex全局数据共享

  • provide和inject来实现全局状态管理

    • provide来全局注入
    • 使用inject来调用对应的状态

26、v-if和v-show的区别?

  • v-if 条件渲染
  • 显示和隐藏是通过创建新节点或销毁节点实现的
  • 适用于少量切换的节点
  • 相当于三目运算返回
  • v-show 伪条件渲染
    • 只编译一次,显示和隐藏是通过控制css样式display实现的
    • 适用于频繁切换的节点

27、vuex有哪几种属性?

  • state 存放状态。

    • 定义和初始化数据的属性
  • gettersstate的计算属性,对数据进行过滤后暴露

  • mutations赋值数据更新,同步操作

    • Vuex中不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation
  • actions提交mutayion,异步操作。

    • 处理后的数据只能提交给mutations修改
  • modules 将store模块化

    • 每个模块都有自己的stategettersmutationsactions,甚至是嵌套子模块
    • namespaced必须开启,所有 getteractionmutation 都会自动根据模块注册的路径调整命名

28、vuex的特性?

  • 全局数据共享

  • 数据流向是单向的(state是唯一数据源、单一状态数)

    • 闭包
  • 可以严格控制数据流,还可以实现数据的可预测化

    • 发布-订阅者模式

29、data为什么是一个函数?

vue中,如果data不是一个工厂函数,或者函数中不是返回一个对象字面量,那么实例化多个组件(组件复用)的时候,不同组件间会共享同一个引用数据data,data的改变会影响到每个实例,这时不符合预期的。

30、vue样式隔离原理?

  • 在组件的style标签中加了scoped属性,则会在所有选择器上添加对应的属性选择器来只对自身组件产生影响,以此来实现样式隔离

  • 对每个组件中的DOM元素添加格式为:data-v-[hash:8]的属性

    <p data-v-37b1dc3d>Hello World!</p>
    
  • 然后该组件的所有选择器也会添加上对应的[data-v-[hash:8]]属性选择器来只对自身组件产生影响。以此来实现样式隔离。

    p[data-v-37b1dc3d]{color:red;
    }
    

31、插槽是什么?(v2和v3)

在某些场景中,需要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段

插槽内容与出口

  • 插槽内容
    • 存在于父组件中,插槽内容可以是任意合法的模板内容,不局限于文本,可以传入多个元素,甚至是组件
  • 插槽出口(插槽占位符) <slot>
    • 存在于子组件中的,标示了父组件提供的插槽内容将在哪里被渲染。

渲染作用域

Vue 模板中的表达式只能访问其定义时所处的作用域。

父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。

  1. 插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。
  2. 插槽内容无法访问子组件的数据。

默认内容

  • 在父组件没有提供插槽内容的情况下,可以为插槽指定默认内容 <slot>默认内容...</slot>

具名插槽

当一个组件中包含多个插槽出口时,需要用到具名插槽

  1. 什么是具名插槽?
    • name 的插槽被称为具名插槽。<slot name=“header”></slot>
    • 没有提供 name<slot> 出口会隐式地命名为default<slot></slot>
  2. 属性name
    • 属性name 给插槽分配唯一的 ID,以确定每一处要渲染的内容。
  3. 具名插槽传值
    • 使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令
    • <template v-slot:header>插槽内容...</template>,简写为<template #header>插槽内容...</template>
  4. 当组件同时接收默认插槽和具名插槽
    • 所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容。

动态插槽名

  • 动态指令参数在 v-slot 上也是有效的

    <base-layout><template v-slot:[dynamicSlotName]>...</template>
    </base-layout>
    

作用域插槽

  • 默认作用域插槽

    1. 当同时使用父组件域内和子组件域内的数据,可以向一个插槽的出口上传递 attributes:

      <slot :text="greetingMessage" :count="1"></slot>
      
    2. 槽接收proprs

      <MyComponent v-slot="slotProps">{{ slotProps.text }} {{ slotProps.count }}
      </MyComponent>
      
  • 具名作用域插槽

    1. 当同时使用父组件域内和子组件域内的数据,可以向一个插槽的出口上传递 attributes:

      <slot name="header" message="hello"></slot>
      
    2. 插槽 props 可以作为 v-slot 指令的值被访问到:v-slot:name="slotProps"

      <MyComponent><template #header="headerProps">{{ headerProps }}</template><template #default="defaultProps">{{ defaultProps }}</template><template #footer="footerProps">{{ footerProps }}</template>
      </MyComponent>
      
    • 最终 headerProps 的结果是 { message: 'hello' }

32、keep-alive组件有什么作用?

  • 可以使用keep-alive这个组件和动态组件配合实现保留组件状态,避免重新渲染(内存不释放组件,切换组件输入框内容不消失)

    <keep-alive><component :page-name="pageName" :is="pageName"></component>
    </keep-alive>
    
  • 针对keep-alive这个组件提供了两个生命周期钩子函数

    • activated:进入页面
    • deactivated:离开页面

33、vue获取dom节点?

  1. 原生JS获取DOM节点

    • document.querySelector(选择器)

    • document.getElementById(id选择器)

    • document.getElementsByClassName(class选择器)

  2. ref属性、$refs 获取元素或组件实例的对象(响应式)

    • 特殊属性ref 用于注册模板引用。

      <p ref="p">hello</p>
      
  • 组件实例$refs 一个包含 DOM 元素和组件实例的对象,用于访问模板引用

         // 选项式<script>export default {mounted() {this.$refs.input.focus()}}</script>```
  • 因为每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的DOM元素或组件的引用。

    • 所以在默认情况下, 组件的 r e f s 指向一个空对象。可以先在组件上加上 ‘ r e f = " 名字 " ‘ ,然后通过 ‘ t h i s . refs 指向一个空对象 。可以先在组件上加上`ref="名字"` ,然后通过`this. refs指向一个空对象。可以先在组件上加上ref="名字"‘,然后通过this.refs.名字`获取相应元素并进行操作。
  1. ref钩子函数 创建任何类型的ref(响应式)

    • eg

      // 组合式
      <script>export default {setup() {const input = ref(null)// ...return {input}}}
      </script>
      
      // 组合式(setup语法糖)
      <script setup>import { ref, onMounted } from 'vue'// 声明一个 ref 来存放该元素的引用// 必须和模板里的 ref 同名const input = ref(null)onMounted(() => {input.value.focus()})
      </script>
      
  2. 组件实例 $parent

    • 子组件获取父组件实例 this.$parent.属性

34、v-model指令实现的原理?

v-model是一个数据双向绑定的指令——语法糖

  1. 在input事件上使用v-model,等价于用value传值

    • v-bind 绑定一个value属性

    • v-on 指令给当前元素绑定input事件

    <input v-model="searchText" />
    
    <input:value="searchText"@input="searchText = $event.target.value"
    />
    
  2. 在组件上使用v-model

    • 将内部原生 <input> 元素的 value 属性绑定到 modelValue 属性上

    • 当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件

      1. 在父组件内给子组件标签添加 v-model ,其实就是给子组件绑定了 value 属性

      2. 子组件内使用 prop 创建 创建 value 属性可以拿到父组件传递下来的值,名字必须是 value

      3. 子组件内部更改 value 的时候,必须通过 $emit 派发一个 input 事件,并携最新的值

      4. v-model 会自动监听 input 事件,把接收到的最新的值同步赋值到 v-model 绑定的变量上

    <CustomInput v-model="searchText" />
    
    <CustomInput:modelValue="searchText"@update:modelValue="newValue => searchText = newValue"
    />
    

35、双向绑定原理?

setter、getter、观察模式、发布订阅模式

  • vue2是通过 数据劫持defineProperty 结合 发布订阅模式 的方式来实现双向绑定的
  • vue3是通过 Proxy数据代理对象(ES6) 的方式来实现双向绑定的
  • Vue中响应式数据变化是观察者模式
  • vue中的事件总线就是使用的发布订阅模式
  • 发布订阅模式相比观察者模式多了个事件中心,订阅者和发布者不是直接关联的
  • MVVM框架的的核心就是双向绑定, 其原理是通过数据劫持+发布订阅模式相结合的方式来是实现的,简单来说就是数据层发生变化的时候,可同布更新视图层,当视图层发生变化的时候,同步更新数据层

36、为什么vue中赋值是异步?

防抖机制、提高渲染性能

Vue可以响应数据变化,数据变化后会自动更新视图,如果每次修改都触发视图更新,会导致多次重复和不必要的渲染操作,例如一个组件使用了两个data的属性,更新两个属性如果触发两次渲染的话,会影响性能。因此Vue采取异步更新。

37、路由模式和实现的原理?

在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。

routerview组件 – 路由渲染

  • Hash 模式 - -用createWebHashHistory创建
    • 在内部传递的实际 URL 之前使用了一个哈希字符
    • 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号,有一点点丑。这是最安全的模式,因为他兼容所有的浏览器和服务器
    • 原理:改变hash可以监听到hashchange事件
  • History(HTML5 模式) – 用 createWebHistory() 创建
    • URL看起来很正常
    • 需要添加一个简单的回退路由
    • 原理:ServiceWorker – 充当Web应用程序(服务器)与浏览器之间的代理服务器(可以拦截全站的请求,并作出相应的动作->由开发者指定的动作)

38、组件注册方法?异步组件定义(路由组件懒加载)?动态组件?

组件注册方法

  • 全局注册(component方法)

    const app = Vue.createApp(options)
    app.component('my-panel', MyPanel)
    app.mount('#root')
    
  • 局部注册(components属性)

    Vue.createApp({components: { 'my-panel': MyPanel}
    }).mount('#root')
    

异步组件定义(路由组件懒加载)

  • import()

    • const List= () => import("@/components/List");
  • defineAsyncComponent() – 定义一个异步组件,它在运行时是懒加载的。

    import { defineAsyncComponent } from 'vue'const XXX = defineAsyncComponent(() => {// 返回Promise...// 导入组件...
    })
    

动态组件

  • <component :is="pageName"></component>,通过:is属性控制模板的样式,传给:is的值可能为:
    • 被注册的组件名
    • 导入的组件对象
  • PS:当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过<KeepAlive>组件强制被切换掉的组件仍然保持“存活”的状态。

41、key的作用?

key是循环渲染中,作为虚拟dom对比的标志,所以可以提高diff算法性能

42、组件封装过程?

  1. 明确需求
  2. 接收参数props
  3. 自定义事件
  4. 传递数据
  5. 组件slot扩展

43、生命周期有哪些?有什么作用?

生命周期就是在组件的不同时期实现不同业务

  1. 创建阶段
    • beforeCreate()

      • 几乎不用,没有什么具体业务执行,所以vue3取消了这个生命周期
    • created()

      • 表示vue组件实例对象构造完成,数据已经绑定到vm层

      • PS:Vue中,没有具体元素,只有虚拟Dom

        • 如果要获取元素,不能使用选择器直接获取,需要使用到绑定属性
        • 关联属性(ref):关联真实Dom和虚拟Dom的关系对象
        <h3 ref="node">hello world</h3>
        // Vue实例
        // this.$refs.node
        
      • 数据已经完成了初始化,但是节点没有完成实例挂载,所以不会触发

      • 如果created中存在异步赋值,那么会导致二次渲染,原因:所有生命周期都是同步代码,所以异步执行不会得到等待

      • 综上:created非异步赋值不会导致二次渲染,而mounted一定会导致二次渲染

  2. 挂载阶段

    • beforeMount()

      • 无用的生命周期
    • mounted()

      • 已完成挂载
      • <button @click="this.price+=2"></button>注意:这里不能写this,因为这里绑定的代码会重新编译
  3. 修改阶段

    • beforeUpdate()
      • 指页面更新,非数据更新,但是数据更新会触发页面更新
      • 数据更新会触发更新生命周期吗?————不对,只有当数据绑定到dom节点上(数据被页面使用了),它的更新才会触发页面更新
    • updated()
  4. 销毁阶段(v2 destroy) / 卸载阶段(v3 unmount)

    • beforeDestory()
    • destroyed()
    • unmount()
    • beforeUnmount()

44、created和mounted的区别?更新生命周期触发要求?

  • created和mounted的区别
    • created非异步赋值不会导致二次渲染,而mounted一定会导致二次渲染
  • 更新生命周期触发要求
    • 由于数据和dom绑定,数据变化后,需要更新其 DOM 树。

45、extends和minxis的区别?

组件类继承、单一继承、属性合并、多组件合并

mixins可以接收一个混入对象的数组(组件类继承),可以混入多个mixin来多组件合并,进行属性合并

extends接收的是对象或函数(单一继承),只能继承一个

46、事件总线?

全局组件通信 : 信两个任意的组件,不管是否有关联( 父子、爷孙, 子子)的组件,都可以直接进行交流通信

  • EventBus - vue2
    • $root
      • 访问根父组件
    • $on
      • 绑定自定义事件监听
    • $emit
      • 分发自定义事件
  • mitt - vue3
    • globalProperties
      • 配置全局事件总线
    • getCurrentInstance
      • 支持访问内部组件实例
      • 获取到ctx代替this

47、项目优化?

性能优化

  • 按需加载
    1. 图片按需加载,只下载可视区附近的图片
    2. 组件懒加载,路由懒加载,其实路由懒加载本质也是组件懒加载。
    3. 其他资源懒加载,避免由于模块引用关系不当,导致首屏页面加载了首屏用不到的CSS、字体图标、图片等资源。
  • 精灵图
    • 把多张小图合成一张大图,通过css中的background-position属性,显示精灵图中某一个小图标。
  • 字体(使用iconfont图标字体代替图片)
    1. 图标缩放不失真,颜色可更改
    2. 字体图标相对图片图标体积更小
    3. 减少请求次数,一个文件可包含所有的图标
    4. 减少大量使用图片,从而节省代码量,降低维护成本
  • 减少请求
    1. 合并请求,由于每次请求时候,实际传输的内容只占整个请求过程的较少一部分时间,因此合并内容让多个请求变成一个,可以节约请求中建立连接、排队等待等耗时。
    2. 雪碧图,图片合成,避免每个图片都要发一次请求。
    3. 内联较小的js css、图片(转成base64)等资源,避免再发一次请求获取资源。
  • 分页降低传输数量
    • 请求列表传参pagesize
  • 其他
    • 移除控制台输出
    • 不在css文件内使用@import引入,会造成额外的i请求
    • 异步加载js(asyncdefer放到body底部动态创建script标签…)

48、如何实现文件按需引入?

<script> 引入文件为同步加载,可能导致主线程被阻塞

(不管怎样,这个文件都会在页面初始化时加载,想要不使用文件,文件就不加载?)
使用第三方库 requirejs 或 seajs 都为按需加载
原理同 ()=>import (path)
一般老项目jquery

  • 如何异步加载JavaScript文件?

    • <script src="..." defer> 使js延迟加载,页面加载完了(onload之后)再加载文件
    • <script src="..." async> 声明为异步加载
    • 放到body底部
    • 动态创建script标签
  • 如何实现按需加载?

    • requirejs

      • AMD模板加载
      • 同步加载
    • seajs

      • CMD模板加载
        • 按需加载
    • import()

49、箭头函数和普通函数有哪些区别?

  • 箭头函数只能简写函数表达式,不能简写声明式函数

  • 箭头函数内部没有 this,箭头函数的 this 是上下文的 this

    • 可以用来改变this指向
    • 箭头函数继承来的this指向永远不会改变
  • 箭头函数内部没有 arguments 这个参数集合

  • 函数体只有一行代码的时候,可以不写 {} ,并且会自动 return

50、变量提升如何理解?var 和 function提升有什么区别?

  1. 变量提升的理解

    • 定义/赋值变量时,var会存在变量提升;而let和const不会提升
    • var变量提升是提升变量定义,不提升变量赋值
  2. var 和 function提升有什么区别

    • 变量提升var

      • 使用var定义变量,声明的变量会提升到作用域顶部,但是赋值操作并不会提升;
      function test1(){console.log(a)var a = 10
      }
      // 等同于
      function test1(){var a;console.log(a); // undefineda = 10;
      }
      
    • 函数提升function

      • 使用function声明函数,整个声明语句都会得到提升。所以声明提升提升的是对函数或变量的声明,而不是赋值!
      function test2(){console.log(a)function a(){}
      }
      // 等同于
      function test2(){function a(){}console.log(a) // f a(){}
      }
      
    • 注意:var xx = fn()只有变量定义的提升,函数未运行则不会提升

      function test3(){console.log(a)var a = function(){}
      }
      // 等同于
      function tests(){var a;console.log(a); // undefineda = function(){}
      }
      

51、js继承有哪些?

  1. 原型继承子类.prototype = new 父类构造函数()

    根据js原型链特性,在访问对象属性时候,如果对象私有属性中没有该属性,会去对象的构造函数的prototype中查找。可以将子类构造函数的prototype赋值为父类的实例,这样在子类对象中查找属性找不到时候,就可以在父类实例中找到,从而让子类可以使用父类的属性。

    • 特点
      • 可以继承(实际上是子类的原型包含了)父类的私有属性和原型属性
    • 缺点
      • 无法向父类构造函数传参
      • 继承的属性都是原型属性,不能继承私有属性
  2. 构造函数继承父类.call(this, 参数);

    为了解决原型继承不能传参和不能继承私有属性的缺点,可以使用借用构造函数继承。

    在子类构造函数中使用call/apply调用父类构造函数,将父类构造函数指向子类实例。

    • 特点
      • 在子类中可以给父类传参
      • 可以继承父类的私有属性
    • 缺点
      • 只能继承父类的私有属性,不能继承父类的原型属性。
  3. 组合继承 -- 同时使用 原型继承 和 构造函数继承

    让子类即继承了父类的原型属性也继承了父类的私有属性,需要注意的是,父类的property属性既存在于子类的私有属性中,也存在于子类的原型属性中,这导致了不必要的重复。

    • 特点
      • 子类可以继承父类原型属性和私有属性
      • 子类可以给父类传参
    • 缺点
      • 对于父类的私有属性,子类继承时候同时存在于私有属性和原型属性中,造成了冗余
  4. extends class 子类 extends 父类{}

    • 创建一个普通类或者内建对象的子类

52、js延迟加载的方法?

流程:遇到script标签,停止解析HTML,等待外链CSS加载并解析完成、内联CSS解析完成后,再执行JavaScript。执行完JavaScript再开始解析HTML。

js延迟加载:js下载和执行时候不会停止解析HTML

  • defer

    • JavaScript会等DOMContentLoaded事件触发后再开始执行(onload加载完成后)
  • async 声明为异步加载

    • JavaScript会等下载完再执行
  • 动态创建dom(script标签)

    • JavaScript会等下载完再执行
  • jQuery的getScript()

  • setTimeout

  • js外部引入的文件放到页面底部,来让js最后引入

53、哪些操作容易内存泄露?

​ 全局变量、闭包、dom删除或清空、事件未清除、元素引用

全局变量

使用闭包但

  • 全局变量

    • 全局变量不会像函数内部的局部变量一样被回收
  • 闭包

    • 闭包可以使变量常驻内存,但未及时销毁就会造成内存泄漏
  • dom删除或清空

    <div id="root"><ul id="ul"><li></li><li id="li"></li><li></li></ul>
    </div>
    <script>let root = document.querySelector('#root')let ul = document.querySelector('#ul')let li = document.querySelector('#li')root.removeChild(ul) // 由于ul变量存在,整个ul及其子元素都不能GC(垃圾回收)ul = null // 虽置空了ul变量,但由于li变量引用ul的子节点,所以ul元素依然不能被GCli = null // 已无变量引用,此时可以GC
    </script>
    
  • 事件未清除

    • 如事件监听器、
    • 计时器 setTimeInterval()setTimeOut()
      • 清除定时器clearInterval()clearTimeOut()
    • 下一帧执行事件requestAnimationFrame()
      • 清除事件cancelAnimationFrame()
  • 元素引用

    • 对象的强引用:将一个引用对象通过变量或常量保存时,那么这个变量或常量就是强引用,这个对象就不会被回收

    • Map、Set强引用

      let obj = {id: 1} // 引用对象
      let user = {info: obj}
      let set = new Set([obj])
      let map = new Map([[obj, 'hahaha']])// 重写obj
      obj = null //以下强引用,并不会因为垃圾回收掉
      console.log(user.info) // {id: 1}
      console.log(set)
      console.log(map)map.delete(obj);		
      obj = null;	//此时才能去除map对key所引用对象的强引用let weakSet = new WeakSet([obj])
      let weakMap = new WeakMap([[obj, 'hahaha']])// 重写obj引用
      obj = null
      // {id: 1} 将在下一次 GC 中从内存中删除
      

54、js垃圾回收机制?

GC(垃圾回收机制):查找垃圾释放空间、回收空间

  • 标记清除

    • 核心思想
      1. 标记:逐步标记内存的可达性(找到活动对象)
      2. 清除:清除"不可达"的内存,并且将原来的标记给清除(清除不可达对象,并且清除标记,便于下次工作)
    • 优点:
      • 解决对象循环引用的不能回收问题。
    • 缺点:
      • 容易产生碎片化空间,浪费空间、不能立即回收垃圾对象。(外部碎片:内存中的某些空闲分区由于太小而难以利用)
  • 引用计数

    • 核心思想

      1. 内部通过引用计数器,来维护当前对象的引用数,从而判断该对象的引用数是否为0,来决定它是否是一个垃圾对象。
      2. 如果引用数值为0,GC就开始工作,将其所在的内存空间进行回收释放和再使用。
    • 优点:

      • 发现垃圾立即回收(因为根据当前的引用数值是否为0判断他是否是一个垃圾,如果是垃圾就回收内存空间,释放内存)
      • 最大限度的减少程序暂停(应用程序在执行的过程中必定会对内存进行消耗,而执行平台内存空间有上限,所以内存会有占满,引用计数算法时刻监控着那些引用数值为0的对象,最大程度避免这种情况)
    • 缺点:

      • 无法回收循环引用的对象
      • 时间开销大(引用计数需要去维护一个数值的变化,时刻监控当前引用数值是否修改,修改需要时间)

55、eventLoop是什么?

js 为单线程,从上至下依次执行;事件轮询是用来实现异步的

  • 宏任务
    • setTimeoutsetInterval、、
  • 微任务
    • Promiseprocess.nextTickrequestAnimationFrame

56、常见数组方法?

Array.prototype.XX()

  1. 切割/拼接(可能会修改原数组)

    • slice(begin,end) 切片

      • 返回一个新数组,为原数组的浅拷贝副本,不会修改原数组。
    • splice(start,deleteCount,item...) 拼接

      • 返回被修改(删除)的的内容,同时会修改原数组。
    • join(separator) 拼接

      • 返回拼接后的字符串,不会修改原数组。
    • concat(array2...) 合并

      • 返回新数组,不会修改原数组。
  2. 增删元素(均会修改原数组)

    • unshift(elment0,...) 头部添加

      • 返回数组的新长度
    • shift() 头部删除

      • 返回删除的元素的值
    • pop() 尾部删除

      • 返回删除的元素的值
    • push() 尾部添加

      • 返回数组的新长度
  3. 遍历(均不会修改原数组)

    • some(callbackFn) 是否存在

      • 返回布尔类型,是否存在元素能通过cb测试函数
    • every(callbackFn) 是否所有

      • 返回布尔类型,是否所有元素都能通过cb测试函数
    • filter(callbackFn) 过滤

      • 返回能通过cb测试的原数组的一部分浅拷贝
    • map(callbackFn) 映射

      • 返回一个每次元素遍历后返回的组成的新数组
    • forEach(callbackFn) 遍历

      • 无返回值
    • reduce(reducer(previousValue,currentValue,currentIndex,array),initialValue) 累积

      • 返回reducer回调函数遍历数组后的结果

57、输入一个URL到页面过程中发生了什?

  1. 浏览器中输入URL
  2. 查找页面缓存
    • 如果浏览器有本地的静态资源缓存,并且未过期,则直接从缓存中读取,而不会发送网络请求。
  3. DNS域名解析
    • 将输入的url对应的域名解析成IP
    • DNS解析过程根据 本机的hosts文件->本地DNS缓存->本地域名服务器的优先级解析域名,在域名解析过程还可能涉及和顶级域名服务器、根域名服务器、根域名服务器的交互。
  4. 建立TCP连接
    • 默认端口号为80
  5. 发起HTTP请求
  6. 服务器响应请求并返回结果
  7. 关闭TCP连接
  8. 浏览器渲染
    • 游览器解释返回的文件(如index.html),并将web页显示给用户

58、浏览器渲染的基本原理?

  1. 构建DOM树
    • 解析 HTML,构建DOM树
  2. 构建CSS规则树
    • 解析CSS(计算style),生成CSSOM树
  3. 构建render树
    • 合并dom树和css规则树,生成render渲染树
  4. 计算布局layout元素位置
  5. 执行绘制
    • 浏览器根据命令绘制,并显示在显示器上

59、http 和 https 的区别?

  • http
    • 明文方式发送内容,不会数据加密,因此不安全
    • 标准端口80
  • https
    • 传输过程会进行加密解密,因此更安全
    • 标准端口443

60、304是什么?

添加请求参数、改变请求地址

客户端发送 GET 请求且请求资源成功,但请求的资源(自上次访问以来或者根据请求的条件)未被修改,则

客户端使用的是本地游览器缓存,而不从服务器下载。

游览器缓存分为强制缓存和协商缓存,强制缓存不需要向服务器发送请求,协商缓存则需要发送请求,通过304 code判断是否需要使用缓存

61、git常用命令?

  • git clone [url] 克隆一个远程仓库
  • git pull 从远程仓库拉取代码到工作空间
  • git add [file-name1] [file-name2] ... 从工作区添加指定文件到暂存区
  • git commit -m [massage] 将暂存区所有文件添加到本地仓库
  • git push 将文件添加到远程仓库
  • git log 显示所有commit日志
  • git branch 查看当前分支
  • git checkout -b [file-name] 创建并切换分支
  • git status [file-name] 查看指定文件状态

62、居中方式?

  • 水平居中
    • (块级元素中的)行内元素(inline或inline-block)
      1. 设置父元素文字居中text-align: center;
    • 块级元素且不脱离文档流(position: absolute;
      1. 设置宽度 width: 100px;
      2. 设置外边距 margin: 0 auto;
  • 垂直居中
    • 行内元素

      • 设置元素高度等于行高 line-height: 100px;height: 100px;
    • 块级元素

      • 设置父元素为弹性盒子 display: flex;

      • 已知高度

        • CSS3新属性 top: calc(50% - width/2);、``
      • 未知高度

        • margin-top: 50%;translate: -50%;transform: translateX(2em);

63、rem、em、px、vh、%分别什么意思?

​ 根字体、父元素字体、绝对像素、视窗高度、父元素百分比

  • px

    • 像素,绝对长度单位
  • em

    • 相对父元素font-size的长度单位(相对自己未设置值时的长度)
    • em的值并不是固定的
    • em会继承父级元素的字体大小。
  • rem

    • 相对根元素html的长度单位
  • rpx

    • 微信小程序独有的、解决屏幕自适应的尺寸单位
    • 不论屏幕大小,将其屏幕宽度都认定为750rpx
  • vh、vw

    • 相对浏览器窗口的长度单位
    • 将浏览器窗口宽高各分为100份,100vh为屏幕高度,100vw为屏幕宽度
  • %

    • %也是将屏幕分为100份,默认情况下只可以给盒子设置宽度,设置高度是无效的
    • 百分比是继承于父级元素的。想要用%给盒子设置高度,就需要给父元素设置一个固定的高度,才能生效
    • 对于position: absolute; 的元素是相对于已定位的父元素
    • 对于position: fixed; 的元素是相对于ViewPort(可视窗口)

64、隐藏元素方法?

  • dispaly:none; 设置元素不可见(元素不会占用任何空间)(删除dom)
  • visibility:hidden; 设置元素不可见(但是依旧占据页面空间,会影响布局)
  • opacity:0; 设置元素透明度
  • width:0; height:0宽高为0
  • clip-path:polygon(0px 0px,0px 0px,0px 0px,0px 0px);
    • 使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。可以指定一些特定形状。
  • left:-9999pxtransform:translateX(-9999px); 将元素移出窗口

65、清除浮动方法?

浮动的元素会造成父元素高度塌陷,因此需要清除浮动。

  1. 在浮动元素后增加一个挡板元素,设置clear: both;

    • 设置clear的元素不受前面浮动元素影响,位置会放在浮动元素后面,因此可以把父元素撑开。

      <div class="father"> // 父元素高度塌陷,需要清除浮动<div class="son1">内容1</div> // 浮动<div class="son2">内容2</div> // 浮动<div class="baffle">挡板元素</div> // 挡板,样式设置clear: both;
      </div>
      
  2. 父元素设置after伪元素,设置clear: both;

    .father::after{content: "";height: 0;display: block;clear: both;zoom: 1;
    }
    
  3. 父元素设置overflow: hidden。

    • overflow: hidden让父元素形成一个BFC(块级格式化上下文),所以可以清除浮动。

66、SEO是什么?如何优化?

搜索引擎优化 (SEO,Search Engine Optimization)

利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名

  • 语义化html标签

    • 网络架构层次清晰 <header><footer><nav><section><aside>
  • 添加meta

    • description 网站相关描述

      <meta name="keywords" content="技术交流 技术博客交流"></meta>
      
    • keywords 关键字(谷歌已不使用其作为网站排名因素)

      <meta name="description" content="一个有爱的技术交流社区 csdn 欢迎您的到来 "></meta>
      
  • title 页面标题

  • 少用iframe

    • 代码复杂,搜索引擎爬虫不能很好地处理iframe中的内容
  • 图片加上alt

    • 搜索引擎能更快识别图片内容

元素居中方法

  1. 绝对定位 top:calc(50% - width/2)
  2. 块级元素 margin:auto
  3. 行内元素 line-height、text-align
  4. flex
  5. transform

npm

  • 直接下载,若失败则会删除下载的依赖(可能会误删之前的依赖导致出错)

cnpm

  • 国内镜像,先检查依赖是否能全部下载下来,能则下载

yarn

pnpm

前端框架有哪些

vue、react、angular

前端有那些构建工具

构建工具:ES6\\ES7游览器不认识就用构造工具将其编译成游览器认识的

实现代码压缩:空格、换行、注释等

  • grunt
  • glup
  • webpack
    • 摇树机制:只引进包里需要用到的方法、变量,其他的不引进
    • 基于项目编译,首次很慢,后面快
  • rollup
    • 基于模块化编译,首次很快,后面慢

前端脚手架

  • ng-cli
  • vue-cli
  • create-react-app
  • vite(目前只有vite基于rollup)
  • next
  • nust
  • umi

前端开箱即用的框架

通过命令直接构建一个应用,包含路由、状态管理器、拦截等,也会有一些页面(登录页面、首页、看板、列表、表单等)

  • next
  • nust
  • umi
  • element-admin
  • antd-pro

算法

  • 排序算法
  • 链表
  • 二叉树

架构

  • 后端架构
    • reatful – 使用不同方式(请求方式不同:POST/GET/DELETE/PUT/PATCH等)对同一个资源(同一个url地址,/user)进行不同操作(/user+post 表示修改用户信息,/user+get 表示获取用户信息,/user+delete 表示删除用户信息,/user+put 表示新增用户)
  • 前端架构
    • flux
      • 前端全局进行数据管理的一个架构(状态管理器)

6、转译 可把字符串作为url组件进行编码

  • encodeURIComponent()把字符串作为 URL 组件的一部分(如path/query/fragment等)进行编码
  • decodeURI()/decodeURIComponent()解码URL中被转义的字符

自适应和响应式区别

自适应包含响应式

响应式:根据 变化样式

为了适应所有设备的观看效果

自适应:不同平台加载不同样式

根据不同的用户去匹配,需要做多版本,