面试--基础

文章目录


一、HTML

1. HTML是怎么加载的

  • 下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的。
  • 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),下载过程会启用单独连接进行下载。
  • 样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染(CSS覆盖)。
  • JS、CSS中如有重定义,后定义函数将覆盖前定义函数。
  • css放顶部,js放在底部,避免使用内联样式导致从新渲染。

2. 如何理解HTML语义化

  • 让人更容易读懂,增加代码可读性。
  • 让搜索引擎更容易读懂(SEO)。
  • 屏幕阅读器可以更好识别。(Accessibility)

3. 默认情况下,哪些HTML标签是块级元素,哪些是内联元素?

  • display: block/table; div, h1, table, ul, ol, li, p 独占一行
  • display: inline/inline-block; span, img, input, button

4. Javascript事件流模型(事件委托和事件冒泡)。

  • 事件委托:自己想所触发的事件,让他的父元素代替执行!阻止默认事件,设置true或者(1)return false;(2) ev.preventDefault();
    addEventListener('click', (event)=>{
    	//判断event.target执行
    	var element = e.target;
        if (element.className == 'btn') {
          console.log(element.id);
        }
    }, true)// 阻止默认事件,设置true或者(1)return false;(2) ev.preventDefault();
    
  • 事件冒泡:当前元素接收事件时,会把接收的事件传给自己的父级,一直到window。子元素和父元素的同类型事件会被依次触发。ie:阻止冒泡ev.cancelBubble = true;非IE ev.stopPropagation();

二、CSS

1. 左边固定,右边自适应。

  • 给左边div设置float:left,给右边div设置margin-left
  • 左边div绝对定位,右边div设置margin-left
  • 双float + calc, 两个都float,右边calc(100% -200px)
  • flex, 父盒子flex,子盒子左边flex: 0 0 200px; 右边: flex: 1.

2. 垂直居中

// 1. 子绝父相,子left: 50%, top: 50%, ml: -width, mt: -height.
.box3{
   border: 2px solid yellow;
    position: relative;
}
.img3{
    width: 224px;
    height: 224px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -112px;
    margin-left: -112px;
}
// 2. 子绝父相,子top,right,bottom,left都0 外加margin:auto
.box4{
   border: 2px solid green;
    position: relative;
}
.img4{
    width: 224px;
    height: 224px;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin:auto;
}
// 3. 子绝父相,
.box5{
    border: 2px solid cyan;
    position: relative;
}
.img5{
    width: 224px;
    height: 224px;
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -moz-transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    -o-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}
// 4. 父盒子,flex,justifyCoteent, alignItems 都center
.box6{
    display: flex;
    justify-content: center;
    align-items: center;
}
.img6{
    width: 224px;
    height: 224px;
}

3. 什么是BFC

  • Block format context(块级格式化上下文): 一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素
  • 形成BFC的条件
    • float不是none
    • position是absolute或者fixed
    • overflow不是visible
    • display是flex inline-block
  • 清除浮动: 当子元素浮动时,形成BFC,导致父元素高度无法被撑开,解决办法,给父元素也形成BFC,但是为了不给父元素以外的其他元素再次造成BFC的影响,一般采用overflow:hidden或者display: flow-root,也就是创建一个无副作用的BFC

4. 盒模型

  • 盒模型offsetWidth计算:(内容宽度+边框+内边距)
  • margin-top和margin-bottom会发生重叠
  • margin四个方向设置负值,什么效果?
    • margin-top负值: 元素向上移动.
    • margin-left负值: 元素向左移动.
    • margin-right负值: 右侧元素左移,自身不受影响.
    • margin-bototm负值: 下边元素上移,自身不受影响.
  • calc计算: 100% - value

5. 重绘和回流

  • 重绘: color,字体大小从新设置的时候。
  • 回流:dom节点丢失, 盒模型的改变, img 不设置默认宽高。

三、JS

1. 常用数据类型,及区别。

  • 值类型:String、Number、Boolean、undefined、Symbol。
    基本类型

  • 引用类型:Object、Array、Function、null(特殊引用类型,指向空地址)。
    引用类型

  • 区别:变量声明时,会存储在栈里,值类型存储值,引用类型则存储地址(堆地址)。

2. 类型判断typeof和instanceof,typeof返回什么。

  • typeof判断值类型和引用类型Object
  • typeof 返回:string,number,boolean,symbol,object(typeof null === ’object), function。
  • instanceof判断变量属于哪个Class、构造函数或者判断是否属于Array、Date、RegExp、Object

3. 列举强制类型转换和隐式类型转换。

  • 强制:parseInt parseeFloat toString等
  • 隐式:if、逻辑运算、==、+ 拼接字符串

4. ===== 的不同?。

  • ==: 只比较值,表示等同,会发生隐式转换。
  • ===: 既比较值还比较类型,表示恒等。

4. 什么是浅拷贝和深拷贝?

  • 浅拷贝:将原对象或原数组的引用直接赋给新对象或新数组,新的只是原来的一个引用,新的发生变化,原来的也会发生变化。
  • 深拷贝:是指新建一个对象,将原对象的所有属性的‘值’拷贝过来(不是引用),新对象的值发生改变的时候,原对象的值不发生改变。

5. 常用深拷贝的方法。

  • JSON.parse(JSON.stringify(obj):缺点是不能处理函数和正则。

  • 使用递归实现(简易版本有缺陷)
    简单深拷贝

  • Object.assign() 一层的时候深拷贝,二层是浅拷贝

  • lodash库的 lodash.cloneDeep()

6. 手写深度比较,模拟 lodash isEqual。

// 判断是否是对象或数组
function isObject(obj) {
    return typeof obj === 'object' && obj !== null
}
// 全相等(深度)
function isEqual(obj1, obj2) {
    if (!isObject(obj1) || !isObject(obj2)) {
        // 值类型(注意,参与 equal 的一般不会是函数)
        return obj1 === obj2
    }
    if (obj1 === obj2) {
        return true
    }
    // 两个都是对象或数组,而且不相等
    // 1. 先取出 obj1 和 obj2 的 keys ,比较个数
    const obj1Keys = Object.keys(obj1)
    const obj2Keys = Object.keys(obj2)
    if (obj1Keys.length !== obj2Keys.length) {
        return false
    }
    // 2. 以 obj1 为基准,和 obj2 一次递归比较
    for (let key in obj1) {
        // 比较当前 key 的 val —— 递归!!!
        const res = isEqual(obj1[key], obj2[key])
        if (!res) {
            return false
        }
    }
    // 3. 全相等
    return true
}

7. 常用数组的增加删除。

  • push()尾部添加,pop()尾部删除
  • unshift()头部添加,shift()头部删除

8. split() 和 join() 的区别。

  • split()字符串拆分成数组,join()将数组转换成字符串
'1-2-3'.split('-') // [1, 2, 3]
[1, 2, 3].join('-') // '1-2-3'

9. slice()切片 和 splice()剪接 的区别。

  • slice
    • 返回一个新的浅拷贝的数组
    • 是纯函数
  • splice arr.splice(1, 2, ‘a’, ‘b’, ‘c’)
    • 返回 arr 从下标1开始的2个元素
    • 不是纯函数,arr 从下标1开始的2个元素被替换成abc了。

10. 数组的pop push unshift shift 分别做什么。

  • push()
    • 功能:从数组后面追加一个元素
    • 返回值:返回 length
    • 会对原数组造成影响
  • pop(),
    • 功能:从数组后面刨除一个元素
    • 返回值:刨除的那个元素
    • 会对原数组造成影响
  • unshift()
    • 功能:从数组前面插入一个元素
    • 返回值:返回 length
    • 会对原数组造成影响
  • shift()
    • 功能:从数组前面刨除一个元素
    • 返回值:刨除的那个元素
    • 会对原数组造成影响

11. 什么是纯函数

  • 不改变原数组(没有副作用)
  • 返回一个数组

12. 数组纯函数api

cosnt arr = [1, 2, 3, 4]
// concat
const arr1 = arr.concat([5, 6, 7 ])
// map
const arr2 = arr.map(num => num * 2)
// slice
const arr3 = arr.slice()
const arr4 = arr.slice(1, 3) // 从数组下标1切到下标4,不包含4
// filter
const arr4 = arr.filter(num => num > 3)

13. 数组非纯函数api

// push pop unshift shift
// forEach 返回的不是数组 没有返回值
// some every 返回的不是数组
// reduce 返回的不是数组

14. 数组ES6新增函数

15. 常用遍历及区别

map(), some(), every(), filter(), reduce()

16. var和let const 的区别

  • var 是 ES 语法,let const 是ES6语法。
  • var有变量提升。
  • var 和 let 是变量,可修改;const 是常量,使用时必须初始化(即必须赋值),不可修改。
  • let const 有块级作用域(可以定义内部变量),var 没有。
  • 同一个变量只能使用一种方式声明,不然会报错。
  • 块级作用域:任何一对花括号 {} 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

17. call 和 apply 的区别

// 都是改变this指向
fn.call(this, p1, p2, p3); // 参数一个一个传
fn.apply(this, arguments); // 参数传数组或类数组

function add(c, d){ 
    return this.a + this.b + c + d; 
} 
var o = {a:1, b:3}; 
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 

18. 数组和类数组的区别

  • 类数组
    • 拥有length属性,其属性(索引)为非负整数
    • 不具有数组所具有的方法
    • 常见的类数组有 arguments对象和 DOM方法的返回结果。比如 document.getElementsByTagName()。
    • arguments(实参)对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数
  • 类数组转换数组
    • args = Array.prototype.slice.call(arguments);

19. ES6 set

  • Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
console.log([...mySet]) // [1, 5]

20. 函数声明和函数表达式的区别

  • 函数声明式,也就是具名函数,变量名会提升
  • 函数表达式,也就是匿名函数。
// 函数声明式
function funDeclaration(type){
    return type==="Declaration";
}
// 函数表达式
var funExpression = function(type){
    return type==="Expression";
}

21. new Object() 和 Object.create() 的区别

  • new Object(): {} 和 new Object() 除了本身创建的对象,都继承了 Object 原型链上(Object.prototype)的属性或者方法,eg:toString();当创建的对象相同时,可以说 {} 等价于 new Object() 。
  • Object.create(): 是将创建的对象继承到原型链上,而本身没有继承 Object.prototype 的属性和方法。

22. 普通函数和箭头函数的区别

  • 写法不一样
  • 普通函数存在变量提升的现象
  • 箭头函数不能作为构造函数使用
    • 箭头函数没有new.target
    • new.target是用来检测函数是否被当做构造函数使用,他会返回一个指向构造函数的引用
  • 两者this指向不同
    • 普通函数:谁调用该函数就指向谁
    • 箭头函数:箭头函数的this指向的是声明时候的上下文环境对象的this,如果没有上下文环境对象,那么就指向最外层对象window。
  • arguments
    • 箭头函数不绑定arguments,取而代之用rest参数…解决
    • 箭头函数的arguments指向它的父级函数所在作用域的arguments

23. 高阶函数

  • 一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。

24. 正则

1. 贪婪模式

  • *:尽可能多的匹配,从字符串后面开始匹配,如果匹配则返回,不匹配则去掉最后一个继续匹配。

2. 惰性匹配

  • ?: 表示匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。

2. 常用的正则匹配

25. 手写字符串 trim 方法,保证浏览器兼容性

26. 手写 flatern 考虑多层级

27. 如何获取多个数字中的最大值

// 1. Math.max
Math.max(10,20,30,40)  // 40
Math.min(10,20,30,40)  // 10
// 2. sort 排序法
var arr = [12,56,25,5,82,51,22];

arr.sort(function (a, b) {
  return b-a;
}); // [5,12,22,25,51,56]
var max = arr[0];  // 5
var min = arr[arr.length - 1];  // 56

28. 数组去重方法

// indexOf
var arr=[2,8,5,0,5,2,6,7,2];
function unique1(arr){
  var hash=[];
  for (var i = 0; i < arr.length; i++) {
     if(hash.indexOf(arr[i])==-1){
      hash.push(arr[i]);
     }
  }
  return hash;
}
// new Set() 加 扩展运算符
function unique2(arr){
  var x = new Set(arr);
 return [...x];
}
// new Set 加 Array.from
function unique3(arr){
  var x = new Set(arr);
 return Array.from(x);
}

29. 如何用JS实现继承

  • 借助原型链实现继承
  • 借助构造函数继承
  • 通过call和apply改变this指向实现继承

四、JS-三座大山

1.原型、原型链和构造函数(大山之一)

  • 原型:每个class都有显示原型prototype,每个实例都有隐式原型__proto__,实例的__proto__指向对应的class的prototype,对象以其原型为模板、从原型继承方法和属性。
  • 原型链:就是__proto__和prototype的依赖关系,当声明一个实例,我们查找一个实例的属性时,实例里没有会去实例的隐式原型原型里面找,在没有去实例的显示原型里面,再没有去显示原型的隐式原型里面去找,一直找到Object的隐式原型null,最后返回一个undefined。
    在这里插入图片描述

2.闭包和作用域(大山之二)

2.1 闭包是什么?有什么特性?应用?有什么负面影响?

  • 含义
    • 通俗的讲就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。
    • 作用域应用的特殊情况
  • 特性
    • 封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;
    • 一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在系统中,闭包中的数据依然存在,从而实现对数据的持久使用(内存常驻)。
    • 自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方
  • 应用
    • 函数作为参数被传入(应用场景)
    • 函数作为返回值被返回 (应用场景 )
    • 封装,设计私有的方法和变量。
  • 优点
    • 避免全局变量的命名冲突 。
    • 缓存值,比如闭包内部return ++的值,循环的值。
    • 外部可以函数内部变量。
    • 实现封装,防止变量跑到外层作用域中,发生命名冲突。
  • 影响缺点
    • 变量会常驻内存,得不到释放。有可能会内存泄漏。
// JS中的垃圾回收机制
function test(){
      var a = 1;
      alert(a)
}
test(); // 执行完这个函数,函数里面的a就不存在了.

function  aaa() {
       var a = 1;
       a++;
       alert(a)
 }
aaa(); // 2
aaa(); // 2
aaa(); // 2
上面的函数不管执行几次,弹出的都是2,如果我们想弹出2/3/4 这样的结果呢?就需要用到闭包
// 闭包
function aaa() {
        var a = 1;
        return function(){
            a++;
            alert(a)
        }
    }

var bbb = aaa();
bbb(); // 2
bbb(); // 3
bbb(); // 4

// 函数表达式的写法
var aaa = (function () {
    var a = 1;
    return function () {
        a++;
        alert(a)
    }
})()

aaa() // 2
aaa() // 3
aaa() // 4

2.2 作用域

  • 指一个变量的作用范围

3.异步(大山之三)

3.1 同步和异步的区别是什么(js单线程,只能同时做一件事)

  • 同步:会阻塞代码执行,遇见未完成的代码执行,会一直等待。
  • 异步:不会阻塞代码执行(通过callBack实现)。

3.2 前端使用的异步场景有哪些

  • ajax: Asynchronous Javascript And XML,异步JavaScript和XML无需加载整个页面,对网页局部进行更新,使网页实现异步更新的技术。
  • 网络请求,比如图片加载(onload就是一个callBack)。异步图片加载
  • 定时任务,比如如setTimeout。

3.3 异步实现的方式

  • callback 使用回调函数实现(普通的和promise)
    • 普通的缺点:请求接口复杂时会陷入callbback hell(回调地狱)
      回调地狱
  • Promise(pending/reslove/reject)promise调用
    promise 请求接口

3.4 手写Promise加载一张图片

promise加载图片

4. 异步进阶

4.1 描述event loop(事件循环/事件轮询)的机制。

  • event loop:就是异步回调实现的原理
  • js执行
    • js从前到后,一行一行执行。
    • 如果某一行执行报错,则停止下面代码的执行。
    • 先把同步代码执行完,再执行异步。
  • event loop 过程:
    • 过程1
      • 同步代码一行一行放在Call Stack(调用栈)执行。
      • 遇到异步,会先"记录"下,等待时机(定时、网络请求等)。
      • 如果Call Stack为空(即同步代码执行完)Event Loop 开始工作。
      • 轮询查找Callback Queue, 如果有则移动到Call Stack 执行
      • 然后继续轮询查找
    • 过程2 DOM事件和Event loop
      • 事件触发时,先触发事件的函数,再执行事件函数里的callback。
      • 事件函数里的callback代码块继续执行event loop。

4.2 什么是宏任务和微任务,区别是什么。

  • 宏任务(触发迟)
    • setTimeout, setInterval,Ajax,DOM 事件
  • 微任务(触发早)
    • Promise, async,await
  • DOM (微任务执行完渲染DOM,再执行宏任务)
  • 区别
    • 微任务早宏任务迟是因为微任务在DOM渲染前触发,而宏任务是在DOM渲染后触发。
    • 微任务在DOM渲染之前触发,宏任务在DOM渲染之后触发。

4.3 Promise ?有哪三种状态?如何变化?

  • promise。
    • promise 是什么? 作用?
      • 是异步编程的一种解决方案,链式调用,但也是基于回调函数(并不是promise就是异步)
      • 主要用于异步计算
      • 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
      • 可以在对象之间传递和操作promise,帮助我们处理队列
    • promise 解决的问题
      • 解决回调地狱的问题。
      • promise可以支持多个并发的请求,获取并发请求中的数据
    • 三种状态(pending resolved rejected)
      • pending:不会触发then和catch,从pending -> resolved 或 从pending -> rejected.
      • resolved(fulfilled):会触发后续的then回调函数。
      • rejected:会触发后续的catch回调函数。
      • 状态不可逆

4.4 async/await语法,及顺序。

  • async/await ?
    • 同步语法,彻底消灭异步回调, 同步语法编写异步代码。
    • await必须依赖于async, await后面可以追加promise也可以追加async函数,或者具体值。
  • async/await和Promise的关系
    • 和Promise并不互斥,两者相辅相成
    • 执行async函数,返回的是Promise
    • await相当于Promise的then
    • 如果是失败的情况,await不会执行,需要用catch 捕获
    • try…catch可捕获异常,代替了Promise的catch
  • 执行顺序await执行顺序

4.5 for-of

  • 常用来异步的遍历

五、JS-Web-API

1. DOM

1.1 DOM 是哪种数据结构( Document Object Model)

  • 树 DOM树
  • 本质:DOM 的本质就是一个树,浏览器内存里面已经初始化好的树的结构。

1.2 DOM 操作常用的API

1.2.1 DOM 节点操作API
  • 获取DOM节点
    • id获取
    • className获取
    • tagName获取
  • 获取DOM节点的 property
    • 节点的 style,className, nodeName, nodeType, innerHTML 等等
  • 获取DOM节点的 attribute
    • p.getAttribute(param1)
    • p.settAttribute(param1, param2)
  • attribute 和 property 的区别
    • attribute: 修改html属性,会改变html解构
    • property:修改对象属性,不会体现到html解构中
    • 两者都可能引起DOM从新渲染
1.2.2 DOM 结构操作API
  • 新增/插入节点
     // 获取
     const div1 = document.getElementById('div1');
     // 新增
     const p1 = document.createElement('p');
     // 插入
     div1.appendChild(p1);
     // 移动已有节点
     const p2 = document.getElementById('p2');
     div1.appendChild(p2);
    
  • 获取子元素列表,获取父元素
     // 获取父元素
     const p1 = document.createElement('p');
     console.log(p1.parentNode);
     // 获取子元素列表
     const div1 = document.getElementById('div1');
     // 包含标签和标签内的文本,所以应该判断nodeType为1就可以获取标签
     console.log(div1.childNodes); 
    
  • 删除子元素
     const div1 = document.getElementById('div1');
     div1.removeChild(div1.childNodes[0]);
    
1.2.3 如何减少DOM操作?

1.3 DOM 性能,一次性插入多个 DOM 节点, 考虑性能

  • DOM 操作非常 消耗性能,避免频繁的DOM操作
  • 对DOM查询做缓存
    // 不缓存 DOM 查询结果
    for (let i = 0; document.getElementsByTagName('p').length; i++) {
       // 每次循环都会计算length,频繁进行 DOM 查询
    }
    // 缓存 DOM 查询结果
    const pList = document.getElementsByTagName('p');
    const length = pList.length;
    
    for( let i = 0; length; i++) {
       // 缓存 length, 只进行一次 DOM 查询
    }
    
  • 将频繁操作改为一次性操作
    // 频繁操作
    const list = document.getElementsByTagName('list');
    for (let i = 0; i < 10; i++) {
    	const li = document.createElement('li');
    	li.innertHTML = `List item ${i}`;
    	list.appendChild(li)
    }
    // 一次操作
    const list = document.getElementById('list')
    // 创建一个文档片段,此时还没有插入到 DOM 结构中
    const frag = document.createDocumentFragment()
    
    for (let i  = 0; i < 20; i++) {
        const li = document.createElement('li')
        li.innerHTML = `List item ${i}`
    
        // 先插入文档片段中
        frag.appendChild(li)
    }
    
    // 都完成之后,再统一插入到 DOM 结构中
    list.appendChild(frag)
    

2. BOM

2.1 将 url 参数解析为 JS 对象

  • 获取当前url参数值?ES6?

2.2 知识点

  • navigator 浏览器的信息
const ua = navigator.userAgent
const ishrome = ua.indexOf('Chrome');
  • screen 屏幕的信息
console.log(screen.width);
console.log(screen.height);
  • location 地址的信息
  • history 前进后退

3. 事件

3.1 document load 和 ready 的区别。

  • document load:资源全部加载完(包括DOM树,js,css,图片)后执行。
  • ready:jquery封装的方法,当DOM文档树加载完成后执行一个函数 (不包含图片,css等)。

3.2 事件代理(委托) 和冒泡

3.2.1 事件冒泡
  • 事件冒泡:基于DOM树形结构,事件会顺着触发元素往上冒泡,应用场景代理。当前元素接收事件时,会把接收的事件传给自己的父级,一直到window。子元素和父元素的同类型事件会被依次触发。ie:阻止冒泡ev.cancelBubble = true;非IE ev.stopPropagation();
3.2.2 事件委托/代理
  • 事件委托:让自己想所触发的事件,让他的父元素代替执行,用e.target获取触发元素阻止默认事件,设置true或者(1)return false;(2) ev.preventDefault();
addEventListener('click', (event)=>{
	//判断event.target执行
	var element = e.target;
    if (element.className == 'btn') {
      console.log(element.id);
    }
}, true)// 阻止默认事件,设置true或者(1)return false;(2) ev.preventDefault();

4. Ajax

1. 什么是Ajax ?优点?缺点?

  • 定义ajax: Asynchronous Javascript And XML,异步JavaScript和XML,无需重新加载整个网页的情况下,能够更新部分网页的技术。
  • 优点:减轻服务器的负担,按需取数据,最大程度的减少冗余请求,局部刷新页面,带来更好的用户体验。
  • 缺点:AJAX干掉了Back和History功能,即对浏览器机制的破坏。
  • 为什么是异步的:async默认的设置值为true,这种情况为异步方式,就是说当ajax发送请求后,在等待server端返回的这个过程中,前台会继续 执行ajax块后面的脚本,直到server端返回正确的结果才会去执行success
  • 通过XMLHttpRequest API实现的,Jquery,浏览器Fetch,Axios,XMLHttpRequest(XHR)都可以实现。
// XMLHttpRequest
// get 请求
const xhr = new XMLHttpRequest();
// false 代表异步请求
xhr.open('GET', '/api', false);
xhr.onreadystatechange = function () {
	// 这里的函数式异步执行
	// 0: 请求未初始化,没有调用send方法。
	// 1: 服务器连接已建立,已调用send方法。
	// 2: 请求已接收,send方法执行完成。
	// 3: 请求处理中,正在响应解析内容。
	// 4: 请求已完成,且响应已就绪。
	if (xhr.readyState === 4) {
		if (xhr.status = == 200) {
			aleeert(xhr.reesponseText);
		}
	}
}
// send 发送向后台请求的参数,只能发送字符串
// xhr.send(JSON.stringify(Data));
xhr.send(null);

// Promise 封装
function ajax (url) {
	const p = new Promise((reesolve, reject) => {
		const xhr = new XMLHttpRequest();
		xhr.open('GET', url, true);
		xhr.onreadystatechange = function() {
			if (xhr.readyState === 4) {
				if(xhr.status === 200) {
					reesolve(
						JSON.pase(xhr.responseText)
					)
				} else if (xhr.status === 404) {
					reject(new Error('404 not found'))
				}
			}
		};
		xhr.send(null) // 必须写
	})
	return p;
}
const url = '/data/test.json';
ajax(url)
.then(res => console.log(res))
.catch(err => console.log(err))

1. 什么是JSON ?

  • JavaScript Object Notation,是一种轻量级的数据交互格式。
  • JSON.parse() 将字符串转换为 JavaScript 对象。
  • JSON.stringify()将对象串转换为json字符串对象。

1. 什么是跨域?

  • 什么是跨域:
    • 在不同源下,访问server。
    • 同源策略(仅限浏览器)
      • ajax请求时,浏览器要求当前网页和server必须同源(安全)
      • 同源:协议(http/https)、域名、端口、三者必须一致。
      • CSS JS 可无视同源策略
    • 搜索引擎和爬虫是通过服务端发送请求的,可以跨域请求,攻击。
    • 所有的跨域,都必须经过servere端允许和配合
    • 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号。
  • 实现方式
    • JSONP
      • <script>可绕过跨域限制,实现 JSONP
      • 服务端可以任意动态拼接数据返回,只要符合html格式要求
      • 同理于<script src="https://test.com/test.js"> js也可以动态拼接js代码返回数据
      • 所以,<script>就可以死获得跨域的数据,只要服务端愿意返回。
    • CORS(服务端支持)
      • 服务器端设置 http header

1. 什么是 jsonp ?

  • 定义:JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
  • 原理:动态插入scrip标签(scrip标签引入不受跨域限制,加载scrip后,调用里面的回调函数实现跨域,但是得和后台约定好内容和callback函数名)

1. get 和 post 区别

  • get 一般用于查询操作,post 一般用于用户提交操作
  • get 参数拼接在url 上, post 放在请求体内(数据体积更大)
  • post 易于防止 CSRF(跨站请求伪造) 攻击

5. 存储

  • cookie
    • 作用1:本身用于浏览器和server通讯,http请求会发送Cookie信息
    • 作用2:html5之前用来做本地存储,前后端都可以修改操作,document.cookie
    • 缺点:
      • 只有4kb
      • http 请求时会发送到服务端, 增加请求数据量
  • sessionStorage,localStorage
    • 共同点
      • 最大可存储5M(每个域名都可以存储5M)
      • API 简单易用 setItem getItem
      • 不会随着http发送到服务端
      • 存储的都是字符串形式,获取的也是字符串,会强制转换
    • 不同点
      • localStorage 数据会永久存储,除非代码或手动删除
      • sessionStorage 数据只存在于当前会话,浏览器关闭则清空
      • 一般用 localStorage 会更多一些
    • cookie localStorage sessionStorage的区别
      • 大小限制,存储期限,安全。

六、Http

1. http 常见的状态码有哪些

  • 状态码 Status code
  • 状态码分类
    • 1xx 服务器收到请求
    • 2xx - 表示成功处理请求,如200,204
    • 3xx - 需要重定向,浏览器直接跳转,如
      • 301(永久重定向,配合 location, 浏览器自动处理,用于更换域名)
      • 302(临时从定向,配合 locatiion,浏览器自动处理,访问A链接服务端返回locationB,然后跳转到B)
      • 304(资源未改变,请求缓存,用来做优化)
    • 4xx - 客户端请求错误
      • 404(资源未找到,请求地址有错误)
      • 403(没有权限访问)
    • 5xx - 服务端错误, 挂掉
      • 500 服务器错误
      • 504 网关超时
  • 关于协议和规范,就是一个约定,要求大家都跟着执行,不要违反规范,例如IE浏览器

2. http 常见的header 有哪些

2.1 Request Headers

  • Accept 浏览器可接收的数据格式
  • Accept-Encoding 浏览器可接收的压缩算法,如gzip
  • Accept-Language 浏览器可接收的语言,如 zh-CN
  • Connection:keep-alive 一次 TCP 连接重复使用
  • cookie
  • Host 请求的域名
  • User-Agent(简称UA)浏览器信息

2.2 Response Headers

  • Content-type 返回数据的格式,如如application/json
  • Content-length 返回数据的大小,多少字节
  • Content-type(post或者patch)发送数据格式,如application/json
  • Content-Encoding 返回数据的压缩算法,如gzip
  • Set-Cookie

2.3 缓存headers

  • Cache-Control Expires
  • Last-Modified If-Modified-Since
  • Etag If-None-Match

2.4 自定义header

  • 比如添加密钥判断是不是非法请求

3. http methods

3.1 get和post 的区别

  • 参考前面

3.2 传统的 methods

  • get 获取服务器的数据
  • post 向服务器提交数据
  • 就这两个简单的功能

3.3 现在的 methods

  • get 获取数据
  • post 新建数据 ,新建留言
  • patch(常用)/put 更新数据
  • delete 删除数据

3.4 Restful API 一种的新的 API 设计方法 url

3.4.1. 对比
  • 传统 API 设计:把每个url当做一个功能
  • Restful API 设计:把每个url当做一个唯一的资源
3.4.2. 如何把Restful API设计成一个资源
  • 尽量不用url参数
    • 传统api:/api/list?pageIndex=2
    • Restful API: /api/list/2
  • 用method表示操作类型
    • 传统
      • post请求:/api/create-blog
      • post请求:/api/update-blog?id=100
      • get请求:/api/get-blog?id=100
    • Restful API
      • post请求:/api/blog
      • patch请求:/api/blog/100
      • get请求:/api/blog/100

4. 描述一下 http 的缓存机制(见下http缓存图)

4.1 缓存介绍

  • 什么是缓存:把一些没有必要从新获取的东西不在从新获取,这就是缓存。
  • 为什么需要缓存:使用缓存视为了让页面加载更快。
  • 哪些资源可以被缓存:静态资源(js,css,img),html,API返回数据

4.2 http 缓存策略 (强制缓存 + 协商缓存)

协商缓存

4.2.1 强制缓存

Cache-Control

  • 浏览器初次请求的时候服务端在返回时,会把适合缓存的资源在Reponse Headers中加Cache-Control
  • 在Response Headers中
  • 控制强制缓存的逻辑
  • 例如 Cache-Control:max-age=31536000(单位是秒)缓存一年时间
  • 缓存过期就会再次请求服务器获取资源

Cache-Control的值

  • max-age 强制缓存的值 时间
  • no-cache 不用强制缓存,交给服务端处理,服务端怎么处理不管 比如html
  • no-store 不用强制缓存,也不让服务端做缓存,直接返回就行
  • private 只能允许最终用户作为缓存 比如电脑 手机
  • public 允许中间的路由、代理也可以做缓存

Expires

  • 比较老,被Cache-Control代替了
4.2.2 协商缓存(对比缓存)

协商缓存

  • 服务器端缓存策略(服务端可以告诉我资源没动,直接用本地的就行,服务端判断能不能用缓存内容)
  • 服务器判断客户端资源,是否和服务端资源一样
  • 一致返回 304, 否则返回200和最新的资源

资源标识

  • 协商缓存
  • 在 Response Headers中,有两种
  • Last-Modified 资源的最后修改时间
    Last-Modified
  • Etag 资源的唯一标识 (一个字符串,类似人类的指纹)
    Etag
4.2.3 Last-Modified 和 Etag
  • 两者存在时会优先使用 Etag
  • Last0-Modified 只能精确到秒级
  • 如果资源被重复生成,二呢绒不变,Etag更精确

4.3. 刷新操作方式,对缓存的影响

  • 正常操作:地址栏输入url, 跳转连接,前进后退等
    • 强制缓存有效,协商缓存有效
  • 手动刷新:F5, 点击刷新按钮,点击菜单刷新
    • 强制缓存失效,协商缓存有效
  • 强制刷新:ctrl + F5
    • 强制缓存失效,协商缓存失效

七、性能优化

前端性能如何优化?一般从哪几个方面考虑?

  • 原则:多使用内存,缓存,减少计算,减少网络请求
  • 方向:加载页面,页面渲染,页面操作的流畅度(防抖和节流)

html,CSS, JS

2.2 性能优化方案

  • 让加载更快
    • 减少资源体积:压缩代码(js, css, 图片)
    • 减少访问次数:合并代码,SSR服务端渲染,缓存(webpack就可以合并代码,雪碧图,分页缓存)
    • 使用更快的网络:CDN(针对不同的区域用户选择更近的服务端)
  • 让渲染更快1
    • CSS 放在 head,JS 放在 body 最下面
    • 尽早开始执行JS, 用DOMContentLoaded触发
    • 懒加载(图片懒加载,上滑加载更多,什么时候用什么时候加载)
  • 让渲染更快2
    • 对DOM查询进行变量缓存(避免重复多次查询DOM)
    • 频繁DOM操作,合并到一起插入DOM结构
    • 防抖,节流(渲染更加流畅)
  • 缓存
    • 机制:文件内容不变,则hash不变,则url不变,url和文件不变,则会自动触发
      http缓存机制返回304。
    • webpack打包文件添加hash值,新功能增加,hash改变,从新请求,老功能
      没有改变,hash不变,请求触发缓存。
  • SSR
    • 服务器端渲染:将网页和数据一起加载,一起渲染
    • 非SSR(前后端分离):先加载网页,再加载数据,再渲染数据

2.2 防抖debounce、节流throttle

  • 防抖:频繁输入和频繁操作的时候,最后才触发。
    • input输入keyup会频繁触发
    • 防抖:只在输入完指定时间(一般300)后触发 。
function debounce(fn, delay = 500) {
    // timer 是闭包中的
    let timer = null

    return function () {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
        	// this指 input1
        	// arguments 调用函数时传的参数 event等
            fn.apply(this, arguments)
            timer = null
        }, delay)
    }
}

input1.addEventListener('keyup', debounce(function (e) {
    console.log(e.target)
    console.log(input1.value)
}, 600))
  • 节流:频繁输入和频繁操作的时候,保持一个频率连续触发。
    • 拖拽一个元素时,要随时拿到该元素被拖拽的位置。
    • 直接用drag时间,则会频繁触发,很容易导致卡顿。
    • 节流:无论拖拽速度多快,都会每隔100ms触发一次。
// 节流
function throttle(fn, delay = 100) {
    let timer = null

    return function () {
        if (timer) {
            return
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments)
            timer = null
        }, delay)
    }
}

Http(优化具体参考文章前面的http缓存)

  • http 缓存策略 (强制缓存 + 协商缓存)

RAF requestAnimationFrame

  • setTimeout 要手动控制频率,而RAF浏览器会自动控制
  • 后台标签或隐藏(最小化或者切换标签)iframe中,RAF会暂停,而setTimeout依然执行

安全

1. 攻击方式

  • XSS 跨站请求攻击
    • 一个博客网站,其中嵌入<script>脚本
    • 脚本内容:获取cookie,发送到我的服务器(服务器配合跨域)
    • 发布博客,有人查看他,轻松收个访问者的cookie
  • XSRF 跨站请求攻击
    • 你正在购物看中某个商品,商品id是100
    • 付费接口是 xxx.com/pay?id=100,但没有任何验证
    • 我是攻击者,我看中了一个商品,id是200
    • 我向你发送一封电子邮件,钓鱼邮件
    • 但邮件正文隐藏着<img src=xxx.com/pay?id=200
    • 你一查看邮件,就帮我购买了id是200的商品。

2. 消除攻击

  • XSS 预防
    • 替换特殊字符,如 <变为&lt; >变为&gt;
    • 前端要替换,后端也要替换,双层保障。
  • XSRF 预防
    • 使用 post 接口
    • 增加验证,例如密码、短信验证码、指纹等。

八、开发环境

1. Git

1. 常用命令

# git clone xxx
# git init
# git branch 查看分支
# git checkout xxx / git checkout -b xxx 还原分支/创建分支
# git checkout . 撤销所有修改
# git add. 所有变化提交到暂存区
# git commit -m 'xxx' 提交到版本库
# git log 查看日志
# git show hash值(git log可以看到)
# git stash 先把修改的内容放到一边,用于临时切换分支
# git stash pop 把之前放到一边的内容在拿出来
# git fetch 获取最新的所有分支
# git merge develop 把develop合并到当前分支
# git pull orgin develop
# git push origin develop
# git diff / git diff 文件名

2. 调试工具

1. Elements

2. Console

3. debugger

4. Network

5. Application

3. 抓包(手机移动端)

1. windows 一般用 fiddler

2. Mac OS 一般用charles

3. 作用

  • 查看网络请求
  • 网址代理
  • https

4. webpack babel

1. 诞生的背景

  • ES6 模块化,浏览器暂不支持
  • ES6 语法, 浏览器并不完全支持
  • 压缩代码,整合代码,让网页加载更快

2. webpack(整合代码)

  • 配置dev环境打包 webpack.config.js
  • 配置生产环境打包 webpack.prod.jd
  • 打包 npm run build

3. babel(ES6转ES5)

  • npm install @babel/core @babel/preset-env babel-loader -D
  • .babelrc 里配置
{
	"presets": ["@babel/preset-env"]
}
  • 在webpack.config.js 里面的 module 里添加 rules

4. ES6 模块化规范

  • 模块化就是导出和导入的过程

5. linux 常用命令(连接测试机)

ssh work@192.169.12.21		登录
ls							查看pingpu
ls -a						查看所有包括隐藏的文件
ll							查看列表
mkdir test					创建文件夹
clear						清屏
rm -rf test					递归强制删除test文件夹
rm test.js					删除文件
cd test 					进入test
mv test.html test1.html		修改名字
mv test.js ../test.js		移动test.js到上层目录
cp a.js a1.js				把a.js拷贝成a1.js
vi a.js						新建a.js并用vim打开,点击i计入编辑模式,点esc退出编辑,
							:w 回车保存,:q 回车退出,:q! 强制退出
vim a.js					vim 打开a.js
cat package.js				查看文件内容
grep "babel" package.json	在package.json里查找关键字
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回答: 面试题中可能会涉及到Mybatis-Plus的相关问题。Mybatis-Plus是在Mybatis的基础上进行了扩展和增强的一个开源框架。它提供了很多便捷的功能,比如自动生成SQL语句、分页查询、逻辑删除等。在面试中可能会问到Mybatis-Plus的一些特性和用法。例如,面试官可能会问到Mybatis-Plus是否支持创建时间和更新时间的自动更新。答案是肯定的,Mybatis-Plus会自动帮我们更新创建时间和更新时间,但是每张表的字段名必须都得一致,即每张表的创建时间都叫create_time,更新时间叫update_time。[3]另外,面试官可能会问到为什么要使用Mybatis,使用Mybatis的好处是什么。使用Mybatis之后,我们只需要自己提供SQL语句,其他的工作,如建立连接、Statement、JDBC相关异常处理等都交给Mybatis去做了。这样可以减少我们的开发工作量,提高开发效率。同时,Mybatis还可以将技术细节封装在我们看不见的地方,让我们更专注于业务逻辑的实现。[1]此外,面试官可能会问到如何进行数值的校验。有两种方法可以进行数值的校验,一种是创建自定义注解,然后再写一个Mybatis拦截器,拦截查询相关方法,如果发现输入参数有自定义注解,并且参数为Null,则直接返回空;另一种方法是在Service层对参数做判断,如果参数为空,直接返回,不需要调用DAO层查询。[2]这些是面试中可能会涉及到的Mybatis-Plus的问题和答案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值