面试

HTML

  1. 如何理解 HTML 语义化
  • HTML语义化就是使用正确的标签,段落就写 p 标签,标题就写 h1 标签,文章就写 article 标签,视频就写video 标签,等等,这样便于开发者进行阅读和维护
  1. meta viewport 是做什么用的,怎么写?
  • meta viewport是专门为移动设备下的显示所设计的东西
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
  • name:为viewport,表示供移动设备使用
  • content:定义了viewport的属性
  • width:表示移动设备下显示的宽度为设备宽度(device-width)
  • initial-scale:表示设备与视口的缩放比率
  • maximum-scale=1和minimum-scale:分别表示缩放的最大最小值, 要注意的是, maximum必须大于或等于minimum
  • user-scalable:表示用户缩放能力, no表示不允许用户缩放网页

不用viewport控制用户不能缩放:用js监听屏幕宽度 window.onresize

  1. 你用过哪些 HTML5 标签?

display的block、inline和inline-block的区别

(1)block
    会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性

(2)inline在一行内
    元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不可以设置垂直方向的padding和margin

(3)inline-block
    将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内

常见的行内元素和块级元素

块级元素:

div、p、h1~h6、ul、li、ol、dd、dt、dl、table、hr、blockquote、address、pre、menu

HTML5中新增的:header、footer、aside、section
常见的行内元素:

span、img、input、a、label、button、select、textarea、sup、sub、abbr、s、i、em、u、strong、small
  • 内容相关

    • header
    • main
    • footer
    • article
  • 功能相关

    • canvas
      • canvas 如何进行绘制
const canvas = document.getElementById('canvas'); // 首先获取到 canvas
const ctx = canvas.getContext('2d'); // 然后获取到 canvas 的 2d 上下文
ctx.fillStyle = 'green'; // 然后设置笔刷的颜色
ctx.fillRect(10, 10, 150, 100); // 然后设置笔刷的范围
  • video
    • 用 video的时候会加什么属性
<video src="videofile.ogg" autoplay poster="posterimage.jpg"></video>
// src 为视频地址,autoplay为自动播放,poster为封面
<video src="foo.ogg">
  <track kind="subtitles" src="foo.en.vtt" srclang="en" label="English">
  <track kind="subtitles" src="foo.sv.vtt" srclang="sv" label="Svenska">
</video> // 还可以用track加字幕
  • audio
  1. H5 是什么?
  • HTML5 最新的 HTML 标准
  • 是 HTML 标签中的 标题标签,代表五级标签

CSS

  1. 两种盒模型分别说一下。
  • CSS 盒模型分两种,一种是 content-box 内容盒,一种是 border-box 边框盒

区别是什么?

content-box 的宽度只包含content, border-box 的宽度包含到 border,包括 content宽度 + padding宽度 + border宽度

  • 你一般用哪一个?

我一般用 border-box,因为我觉得 border-box 更灵活些

  1. 如何垂直居中?

https://juejin.im/post/6882272759901061127/

  • 子元素绝对定位,父元素相对定位 + transform: translate(-50%, -50%);
  • flex布局:
    display:flex;
    justify-content:center;
    align-items: center;
  1. flex 怎么用,常用属性有哪些?
    常用属性:
排列方式:横向还是纵向
flex-direction:row; // 从左向右
flex-direction:column; // 从右向左
flex-direction:row-reverse; // // 从上到下
flex-direction:column-reverse; // 从下到上

是否换行:
flex-wrap: nowrap; // 不换行(默认)

水平排列方式:
justify-content: flex-start; // 居左
justify-content: flex-end; // 居右
justify-content: center;// 居中
justify-content: space-between; // 两端对齐
justify-content: space-around; // 拉伸分布

垂直排列:
align-items: flex-start; // 开始
align-items: flex-end; // 底部
align-items: center; // 居中

flex-grow:0;(默认值)// 定义子元素放大比例
  1. BFC 是什么?(不理解)
  1. CSS 选择器优先级
    !important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认

伪元素,选择元素的特定位置,比应用样式

举例:

  • 越具体优先级越高
  • 写在后面的覆盖前面的
  • important! 最高,但是尽量少用
  1. 清除浮动说一下
.clearfix::after{
content: '';
display: block/table;
clear: both;
}

.clearfix 加到容器上,里面子元素的浮动就被清除了。

  1. 层叠上下文

所有的盒模型元素都处于三维坐标系中。 除了我们常用的横坐标和纵坐标, 盒模型元素还可以沿着“z 轴”层叠摆放,这里就需要用到 z-index了,z-index数字越大, 元素越接近观察者。

媒体查询: 通过查询当前属于哪种设备, 让网页能够在不同的设备下正常的预览
@media
我用到过 min-width和max-width

  1. 浏览器渲染原理

  2. 解析HTML→构建HTML树(DOM)

  3. 解析CSS→构建CSS树(CSSDOM)

  4. 将两棵树合并成一颗渲染树(render tree)

  5. Layout布局

根据render tree就可以进入Layout布局
Layout流程输出是一个盒模型,Layout计算每个对象的精确位置和大小。

5.Paint绘制

布局好了后,就可以将render tree里的每个对象转换成屏幕的实际像素,paint就是将各个节点绘制到屏幕上。

6.Composite合成

将已经paint的部分根据层叠关系把页面展示出来。

  1. PC端和移动端的区别
  • PC考虑的是浏览器的兼容性,而移动端开发考虑的更多的是手机兼容性
  • 在部分事件的处理上,移动端多出来的事件是触屏事件,而缺少的是hover事件
  1. window的onload事件和DOMcontentloaded谁先谁后?
    DOMcontentloaded先构建html树的时候就开始执行,onload是在页面加载完成后才开始出现

  2. line-height 如果设置了 15rem 15em 15px 1.5分别代表什么效果?
    rem和em是自适应大小,区别在于rem是相对于根字体,em是相对于父元素而言,没有单位的1.5表示1.5倍行高,如果当前字体10px 1.5就是说行高15px 。15rem 15em 15px 1.5分别相对于 根字体 父辈字体 固定字体 当前字体大小而言。

  3. transition 和 animation

随时间改变元素的属性值

  • animation配合@keyframe触发。transition 是通过hover或者js事件触发
  • animation 可以结合 keyframe 设置每一帧,但是 transition只有两帧
  • animation 可以设置很多的属性,比如循环次数,动画结束的状态等等,transition 只能触发一次

原生 JS

  1. ES 6 语法知道哪些,分别怎么用?
    let/const/箭头函数/解构赋值/Promise

解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

语法:

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20

详细:
https://es6.ruanyifeng.com/
https://fangyinghang.com/es-6-tutorials/

  1. Promise、Promise.all、Promise.race 分别怎么用?
    Promise的缺点
  • promise一旦新建就会立即执行,无法中途取消
  • 当处于pending状态时,无法得知当前处于哪一个状态,是刚刚开始还是刚刚结束
  • 如果不设置回调函数,promise内部抛出的错误,不会反应到外部
    Promise的优点
  • 更好地进行错误捕获
  • 代码更易读

Promise

Promise 是异步编程的一种解决方案,有三种状态:

待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
已兑现(fulfilled): 意味着操作成功完成。
已拒绝(rejected): 意味着操作失败。

可以通过函数来监听Promise状态的变化
成功执行 then() 函数的回调
失败执行 catch() 函数的回调

Promise的具体用法如下(背代码):

 function fn(){
     return new Promise((resolve, reject)=>{
         成功时调用 resolve(数据)
         失败时调用 reject(错误)
     })
 }
 fn().then(success1, fail1).then(success2, fail2)

Promise.all

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

Promise.all([promise1, promise2]).then(success1, fail1)

promise.race

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

Promise.race([promise1, promise2]).then(success1, fail1)

promise1和promise2只要有一个成功就会调用success1;
promise1和promise2只要有一个失败就会调用fail1;
总之,谁第一个成功或失败,就认为是race的成功或失败。

  1. 手写函数防抖和函数节流
    节约性能
    防抖是控制次数,节流是控制频率
 // 防抖,指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。比如:坐电梯时,如果在电梯内持续有人按电梯的楼层号,那么电梯是不会运行的,当没人按楼层号时,电梯会在一小段时间间隔后才会运行,以此达到防抖的效果。
 function debounce(fn, delay){
     let timerId = null
     return function(){
         const context = this
         if(timerId){window.clearTimeout(timerId)}
         timerId = setTimeout(()=>{
             fn.apply(context, arguments)
             timerId = null
         },delay)
     }
 }
 const debounced = debounce(()=>console.log('hi'))
 debounced()
 debounced()
 // 节流(一段时间执行一次之后,就不执行第二次)CD
 function throttle(fn, delay){
     let canUse = true
     return function(){
         if(canUse){
             fn.apply(this, arguments)
             canUse = false
             setTimeout(()=>canUse = true, delay)
         }
     }
 }

 const throttled = throttle(()=>console.log('hi'))
 throttled()
 throttled()
  1. 手写AJAX

可以进行表单验证

AJAX 就是用JS向服务端发起一个请求,并获取服务器返回的内容,它一共分为四个步骤

  • 第一步,创建XMLHttpRequest对象

  • 第二步,连接服务器

  • 第三步,向服务器发送请求send

  • 第四步,接受服务器响应的数据

var request = new XMLHttpRequest();
request.open('GET', '/xxxx',false) // 请求方式,路径,true代表异步,false代表同步
request.onreadystatechange = function() {
  if (request.readyState === 4) {
    console.log('请求完成')
    if (request.response.status >= 200 &
      console.log('请求成功')
    } else {}
  }
}
// request.onload = ()=>{console.log('请求成功')} // 简化
request.send()

readyState状态码说明:
0=>初始化 1=>载入 2=>载入完成 3=>解析 4=>完成

  1. 这段代码里的 this 是什么?

this永远指向的是调用它的对象,也就是看谁调用执行的它

  • fn() // this => window/global 普通函数中的 this 都引用 window 对象
  • new fn() // this => 新的对象 构造函数中的 this 指向的是它实例化的对象
  • obj.fn() // this => obj 作为对象属性值的函数,this 指向的就是这个对象
  • fn.call(xx) // this => xx
  • fn.apply(xx) // this => xx
  • fn.bind(xx) // this => xx 函数调用 apply(), call() 方法后,this 引用为 call apply 方法传进去的第一个参数
  • fn = () =>{} // this => 外面的 this
  1. 闭包

什么是「闭包」。

闭包是一种隐藏局部变量的技术

比如说:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包

举个栗子:

var a = 1
function f1(){
    console.log(a)
}
// 1

用途:使用闭包主要是为了设计私有的方法和变量
缺点:函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
解决方法:在退出函数之前,将不使用的局部变量全部删除

<script>
    function f1() {
      var a = 1;
      return {
        function() {
          return a
        }
      }
    }
    var b = f1()
  </script>
  1. 什么是 JSONP,什么是 CORS,什么是跨域?

htpp proxy代理跨域

跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果

如果两个url的协议域名端口号完全一致,那么这两个url就是同源的。

CORS

如何理解CORS?
如果wang.com和ergou.com这两个网站都是我的,我想让这两个网站互相访问,只需要wang.com在响应头里写ergou.com可以访问即可。这就是CORS。

具体语法:
Access-Control-Allow-Origin:

JSONP

原理是利用了script标签的src属性不受浏览器的同源策略限制,来进行数据请求的。

我们在跨域的时候由于某些原因当前浏览器不支持CORS,我们必须使用另一种方式来跨域,前端请求一个js文件,这个js文件会执行一个回调,回调里面就有我们的数据。

回调的名字是什么?

回调的名字可以随机生成的,我们把这个名字当成callback的参数传给后台,后台会把这个函数返回给我们并执行

JSONP的优点是什么?

  • 兼容IE
  • 可以跨域

JSONP的缺点是什么?

  • 因为是script标签,所以读不到AJAX那么精确,拿不到状态码,拿不到header
  • 不支持post,只支持get
  1. async/await 怎么用,如何捕获异常?

async 是“异步”的简写, async 用于申明一个异步的 function

await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成

await只能放在async函数里

  1. 如何实现深拷贝?
    浅拷贝
    修改新变量的值会影响原有变量的值
    默认情况下引用类型都是浅拷贝

展开运算符...

深拷贝
修改新变量的值不会影响原有变量的值
默认情况下基本数据类型都是深拷贝

  • 递归

function deepClone(obj) {
  let objClone = Array.isArray(obj) ? [] : {}
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        // 判断obj子元素是否为对象,如果是,递归复制
        if (obj[key] && typeof obj[key] === 'object') {
          objClone[key] = deepClone(obj[key])
        } else {
          objClone[key] = obj[key]
        }
      }
    }
  }
  return objClone

  • 通过 JSON 对象
function deepClone (obj) {
  let _obj = JSON.stringify(obj)
  let objClone = JSON.parse(_obj)
  return objClone
}

  • 通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);
  • Object.assign()拷贝
    当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
  1. 如何用正则实现 trim()?
  • trim() 方法用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。
  • trim() 方法不会改变原始字符串。
  • trim() 方法不适用于 null, undefined, Number 类型。
var str = trim("   R   ")
function trim(string) {
  return string.replace(/^\s+|\s+$/gm,'');
}
console.log(str) // "R"
  1. 不用 class 如何实现继承?用 class 又如何实现?
    不用 class
// Animal 类
function Animal(){
this.a = 1
}
Animal.prototype.move = function(){}   // Animal 有个属性 a , 有个原型方法为 move

// Dog 类
function Dog(){
Animal.apply(this, arguments) // 首先调用 Animal
this.d = 2
}

 // 实现原型的继承,Dog类 继承 Animal类
let f = function(){
f.prototype = Animal.prototype
Dog.prototype = new f() // Dog 的原型继承 Animal 的原型
Dog.prototype.constructor = Dog
Dog.wangwang = function(){}
}

用class

class Dog extends Animal {
   constructor() {
     super()
   }
}
  1. 如何实现数组去重?
  • 使用set
  • 使用map
function unique (array) {
  return Array.from(new Set(array))
}
var array = [1,5,2,3,4,2,3,1,3,4];
console.log(unique(array)); // [1, 5, 2, 3, 4]
<script>
    let arr = [1, 5, 2, 3, 4, 2, 3, 1, 3, 4];
    function unique(arr) {
      let map = new Map()
      let newArr = []
      for (let i = 0; i < arr.length; i++) {
        if (!map.has(arr[i])) {
          map.set(arr[i])
          newArr.push(arr[i])
        }
      }
      return newArr
    }

    console.log(unique(arr)); // [1, 5, 2, 3, 4]
  </script>
  1. == 相关题目(反着答)

这个我不太清楚, == 规则太复杂了,我平时写代码都用三个等于号,代码更清晰简洁

  1. 手写一个 Promise(送命题,必须会)放弃
  1. JS 中使用 typeof 能得到哪些类型?
  • typeof 123 // number

  • typeof 'abc' // string

  • typeof true // boolean

  • typeof Symbol() // symbol

  • typeof undefined // undefined

  • typeof null // object

  • typeof [] // object

  • typeof {} // object

  • typeof console.log // function

  1. 介绍 js 的基本数据类型

四基两空一对象

number:数字
string:字符串
bool:布尔值
symbol:符号
undefined:未定义
null :空
object:对象

五个falsy值:0, NaN, null, undefined, ''(中间没有空格)

  1. JS 中有哪些内置函数/对象?
    Object 是 JavaScript 中所有对象的父对象

数据封装类对象:
Object
Array
Boolean
Number
String

其他对象:
Function
Arguments
Math
Date
RegExp
Error

  1. JS 变量按照存储方式区分为哪些类型,并描述其特点
    值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中
    // 值类型
    var a = 10
    var b = a
    a = 11
    console.log(b)// 10

// 引用类型
var a = {age:100}
var b = a
b.age = 200
console.log(a.age) // 200

  1. var、 let、const的区别
  • var存在变量提升,let、const不存在
  • var可以重复声明,let、const不能
  • var、let 的变量值可以修改,const不能
  • var 和 let 声明时可以不用设置初始值,const需要
  • var 没有块级作用域,let、const有
    19.箭头函数和普通函数
  • 普通函数的this 指向调用它的那个对象
  • 箭头函数不能作为构造函数,不能使用new,没有this

20.立即执行函数是什么?

要成为立即执行函数,需要满足两个条件:

声明一个匿名函数
立马调用这个匿名函数
比如,下面就是一个非常典型的立即执行函数:

(function(){console.log('这是一个立即执行函数')}())

//首先声明一个匿名函数(function(){console.log('这是一个立即执行函数')})
//然后再匿名函数的后面接一对括号(),立马调用这个函数

立即执行函数有什么作用?

立即执行函数的作用只有一个,那就是创建独立的作用域。 让外部无法访问作用域内部的变量,从而避免变量污染。

  1. 作用域?

指函数在哪些范围内可以用,而在其他部分不可以,要用就得重新定义。

说说你对作用域链的理解

每一个函数都有一个作用域, 如果一个函数内部又嵌套着另外一个函数,
嵌套的函数也会有一个作用域,这样,嵌套函数就能访问到外部函数中的变量,
以及全局作用域中的变量,此时就形成了一条作用域链

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到 window 对象即被终止,作用域链向下访问变量是不被允许的。

  1. 原型与原型链

减少内存开销,实现属性的继承

var obj = {};
var arr = [];
function fn1 () {}

所有的引用类型(数组、对象、函数),都有一个 proto(隐式原型)属性,属性值是一个普通对象

console.log(obj.__proto__);

所有的函数,都有一个 prototype (显式原型)属性,属性值也是一个普通对象

console.log(obj.prototype);

所有的引用类型的proto属性值都指向构造函数的prototype属性值。

console.log(obj.__proto__ === Object.prototype); // true

当试图获取对象属性时,如果对象本身没有这个属性,那就会去他的proto(prototype)中去寻找。

function Dog(name){ 
   this.name = name; 
} 
Dog.prototype.callName = function (){ 
   console.log(this.name,"wang wang"); 
}
let dog1 = new Dog("ahuang"); 
dog1.printName = function (){ 
   console.log(this.name);
}
dog1.callName();  // ahuang wang wang
dog1.printName(); // ahuang

原型链

我找一个属性,首先会在f.proto中去找,因为属性值为一个对象,那么就会去f.proto.proto去找,同理如果还没找到,就会一直向上去查找,直到结果为null为止。这个串起来的链即为原型链。

image.png
  1. 异步和单线程

进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。

线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。

并发执行:当多个线程同时运行的时候,这样的执行模式成为并发执行

我们可以将同步看成是单线的执行,即要么执行成功,要么执行失败,反正就是要返回一个结果,在没有得到这个结果之前什么都不干,就傻傻的等着。

单线程:就是在同一时间只能做一件事情。

单线程意味这所有的任务都需要排队,执行完一个才能继续执行下一个,但是如果前一个执行很长,后一个任务就需要一直等待。这个时候我们就需要用到异步

常用的异步

setTimeout,setInterval,ajax

为什么js引擎是单线程?

js的主要用途是与用户互动,以及操作DOM,这决定它只能是单线程。例:一个线程要添加DOM节点,一个线程要删减DOM节点,容易造成分歧。

  1. 数组有哪些方法?
    push()方法:尾部添加;
    pop()方法:尾部删除;
    unshift():头部添加;
    shift():头部删除。
  2. javascript中创建对象的三种方式
  • 利用字面量创建对象
 var obj = {
                name: '123',
                gender: '男',
                sayHi: function() { //方法
                    alert('hello!')
                }
            }
            // 2.调用对象
            // (1)
               console.log(obj.name);
            // (2)
                console.log(obj['name']);
            // (3)调用对象的方法
              obj.sayHi();
  • 利用new object创建对象
var obj = new Object(); //创建一个空对象
        obj.name = '123';
        obj.age = '23';
        obj.height = '177';
        obj.sayHi = function() {
                alert('hello');
            }
        // 2.调用对象
        // (1)
        console.log(obj.name);
        // (2)
        console.log(obj['name']);
        // (3)调用对象的方法
        obj.sayHi();
  • 利用函数创建对象
 function Star(name, age, gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.sing = function(sang) {
                console.log(sang)
            }
        }
        // new Star('123', 23, '男');  //只new不赋值的话,以下的不会执行,算是错误的
        //1.构造函数名字首字母大写
        // 2.构造函数不需要return
        var ldh = new Star('123', 23, '男');
        var zxy = new Star('345', 29, '男');
        ldh.sing('啦啦啦');
        // console.log(typeof(ldh));
        console.log(ldh.name);
        zxy.sing('你的名字');
  1. new一个对象的时候发生了什么?
function Person(name, age) {
  this.name = name;
  this.age = age;
}
let p = new Person("William", 24);

new一个对象的四个过程:

  • 创建一个空对象
let obj = {};
  • 让构造函数中的this指向新对象,并执行构造函数的函数体
let result = Person.call(obj);
  • 设置新对象的proto属性指向构造函数的原型对象
obj.__proto__ = Person.prototype;
  • 判断构造函数的返回值类型,如果是值类型,则返回新对象。如果是引用类型,就返回这个引用类型的对象
if (typeof(result) == "object") 
    p = result;
else 
    p = obj;
  1. js为什么需要放到body后?

浏览器的渲染引擎和js解析引擎会冲突。

BODY中编写的都是HTML标签,JS很多时候需要操作这些元素,首先我们要保证元素加载成功,才可以在JS中获取

  1. js 操作数组的api

https://www.cnblogs.com/10JQKA/archive/2019/04/04/10650340.html

join(), sort(), slice(), splice(), concat(), reverse(), push()+pop(), shift()+unshift(), forEach(), map(), some(), every(), filter(),
  1. 前端常见的性能优化方式?

1、减少http请求,合理设置 HTTP缓存

2、使用浏览器缓存

3、CSS Sprites,合并 CSS图片,减少请求数

4、CSS放在页面最上部,javascript放在页面最下面

DOM

  1. 事件委托

DOM 事件模型
DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播,这种传播分为三个阶段。

  • 捕获阶段:事件从window对象自上而下向目标节点传播
  • 目标阶段:目标节点处理事件
  • 冒泡阶段:事件从目标节点自下而上向window对象传播
    事件委托
    事件委托,由于冒泡阶段事件会从子节点向上传播到父节点,因此可以监听父节点来处理多个子节点的事件。
<style>
  ul{
    border: 1px solid red;
    padding: 10px;
  }
  li{
    border: 1px solid red;
    padding: 10px;
  }
  span{
    border: 1px solid black;
    padding: 10px;
  }
</style>
<body>
  <ul class="parent">container
    <li class="child">box
      <li class="target">target</li>
    </li>
  </ul>
</body>

</html>

错误版(但是可能能过)
const ul = document.querySelector('ul')
ul.addEventListener('click', function(e){
     if(e.target.tagName.toLowerCase() === 'li'){
    console.log('hello')
     }
 })
bug 在于,如果用户点击的是 li 里面的 span,就没法触发 fn,这显然不对。
高级版
 function delegate(element, eventType, selector, fn) {
     element.addEventListener(eventType, e => {
       let el = e.target
       while (!el.matches(selector)) {
         if (element === el) {
           el = null
           break
         }
         el = el.parentNode
       }
       el && fn.call(el, e, el)
     })
     return element
   }
思路是点击 span 后,递归遍历 span 的祖先元素看其中有没有 ul 里面的 li。
  1. 用 mouse 事件写一个可拖曳的 div
    http://js.jirengu.com/fevayuruci/1/edit?html,css,js,output

HTTP

对器客户端和 服务器端之间数据传输的格式规范,格式简称为“超文本传输协议”

一个请求由什么组成?

请求头,请求体,请求正文,状态码,响应头,响应正文。

请求头和响应头有哪些?

content-type, user-agent,cache-control,host,origin,refer等等

  1. HTTP 状态码知道哪些?分别什么意思?

https://http.cat/

  • 1 开头:信息状态码

  • 2 开头: 成功状态码

  • 3 开头: 重定向状态码,进一步操作

  • 4 开头: 客户端错误状态码

  • 5 开头: 服务端错误状态码

  • 100 继续

  • 101 切换协议

  • 200 成功

  • 201 已创建

  • 202 已接受,未处理

  • 204 无内容

  • 300 多种选择

  • 301 永久移动

  • 302 临时移动

  • 303 查看其他位置

  • 304 未修改

  • 400 错误请求

  • 401 未授权

  • 403 禁止

  • 404 未找到

  • 405 方法禁用

  • 414 请求 url 过长

  • 500 服务器错误

  • 502 错误网关

  1. HTTP 缓存有哪几种?
    三种
    ①- ETag: 值一般是MD5
    ②- xExpire: 值一般是 日期 // 在某个时间点过期
    ③- Cache-Control: 最常见的是 max-age=600 // 多少秒内过期

②③区别:②有bug:本地时间是可以设置的,假如今天是2020/10/1,把本地时间设置成2019/10/1,直接就过期了,③是一个相对时间,不存在这个问题

①③区别:③是从浏览器本地缓存,是无请求的,而①还是会发送请求,状态码一般为304

http的缓存机制可以分为两种类型:

强缓存:浏览器判断本地缓存未过期,就直接使用,无需发起http请求
协商缓存: 浏览器判断本地缓存过期,发送http请求,服务器返回304告诉浏览器文件未改变,浏览器继续使用本地缓存

浏览器发送请求时判断缓存顺序:
是否有缓存?——无:发送请求;有:判断缓存
验证Cache-Control中的max-age时间限定、验证Expires到期日?——未过期:使用缓存(200 form-cache);过期:发送缓存信息至服务器验证
验证E-tag和Last-Modified信息?——无更新:304,使用缓存;有更新:200,返回新文件并更新缓存

  1. GET 和 POST 的区别
    get、post、put、patch、delete

错误:

  • POST 安全, GET 不安全
  • GET URL 有长度限制, POST 没有
  • GET 参数是放在 url, POST 是放在消息体里面的
  • GET 只需要一个报文, POST 需要两个以上
  • GET 幂等,POST 不幂等
    正确:
    GET 是获取数据, POST 是提交数据

Cookie VS Session

  • Cookie 是服务器发给浏览器的一段字符串,浏览器每次访问服务器的时候都会把字符串带上, Cookie 是在浏览器上

  • Session 是会话,表示浏览器与服务器一段时间内的会话,Session 是在服务器上
    Cookie VS LocalStorage

  • Session一般是基于Cookie来实现的,就是把Session ID 放到Cookie里面

  • Cookie 限制比较小,一般是 4k 左右,LocalStorage 一般有5M

  • Cookie 一般用来存用户信息,LocalStorage 一般用于存不重要数据

  • Cookie 会被发送到服务器上,LocalStorage不发送到服务器上
    LocalStorage VS SessionStorage

  • LocalStorage 一般不会过期,SessionStorage 一般会在 Session 结束的时候过期

  1. HTTP1.x和HTTP2的区别
  • HTTP2支持多路复用
  • HTTP2支持服务器推送
  1. 从输入 url 到页面加载显示完成发生了什么
  • 查找域名和对应 IP 地址
  • 建立连接 (TCP 的三次握手)
  • 构建网页
  • 断开连接
  1. 三次握手四次挥手?不记得

框架 Vue

  1. watch 和 computed 和 methods 区别是什么?
  • watch是监听属性,computed是计算属性
  • watch不支持缓存,不论监听的数据是否重复都会被监听到,computed支持缓存机制,在监听数据没有改变时不会重新计算
  • methods是方法,只要重新渲染就会执行,如需要每次重新计算,用方法
  1. Vue 有哪些生命周期钩子函数?分别有什么用?

VUE生命周期是VUE实例化或者组件创建到消亡的过程
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑

  • beforeCreat:创建前的状态
  • created:创建完毕状态
  • beforeMount:挂载前状态
  • mounted:挂载结束状态,渲染到真正的DOM
  • beforeUpdate:可以拿到Vue实例化改变前的状态
  • updated:拿到变动完成的状态
  • beforeDestroy:消亡前的状态
  • destroyed:实例化或组件被摧毁消亡

DOM 渲染哪个周期中就已经完成?

一般在mounted周期内请求数据,因为这个周期开始时,当前组件已经被挂载到真实的元素上了

第一次页面加载会触发哪几个钩子?

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

  1. Vue 如何实现组件间通信?
父子组件:使用 v-on 通过事件通信
爷孙组件:使用两次 v-on 通过爷爷爸爸通信,爸爸儿子通信实现爷孙通信
任意组件:使用 eventBus = new Vue() 来通信,eventBus.$on 和 eventBus.$emit 是主要API
任意组件:使用 Vuex 通信
  1. Vue 数据响应式/双向绑定原理?

简单来说,数据响应式是指页面视图会随着数据的变化而变化

数据响应式原理:

  • 把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,使用 Object.defineProperty 把这些属性全部转为 getter/setter
  • 对于已经创建的实例,Vue 不能检测到对象属性的添加或删除,解决方法是手动调用 Vue.set 或者 this.$set
  1. Vue.set 是做什么用的?
    对于已经创建的实例,Vue 不允许动态添加根级别的响应式,解决方法是手动调用 Vue.set 或者 this.$set
  2. Vuex 你怎么用的?
    Vuex 是一个专为 Vue.js 应用程序开发的状态管理工具。
    它包括State/Getter/Mutation/Action/Module

Mutation/Action的区别

  • mutation 有一个固有参数 state,接收的是 Vuex 中的 state 对象
  • action 也有一个固有参数 context,但是 context 是 state 的父级,包含 state、getters
  1. VueRouter 你怎么用的?
    Vue Router 是 Vue.js 官方的路由管理器。
    说出核心概念的名字和作用:History 模式/导航守卫/路由懒加载

常用 API:router-link/router-view/this.router.push/this.router.replace/this.$route.params

this.router.push(path): 相当于点击路由链接(可以返回到当前路由界面) this.router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
this.router.back(): 请求(返回)上一个记录路由 this.router.go(-1): 请求(返回)上一个记录路由
this.$router.go(1): 请求下一个记录路由

  1. 路由守卫是什么?

导航守卫就是路由跳转过程中的一些钩子函数。

  • router.beforeEach 全局前置守卫
  • router.beforeResolve 全局解析守卫
  • router.afterEach 全局后置钩子
  • beforeRouteEnter
    beforeRouteUpdate (2.2 新增)
    beforeRouteLeave路由独享的守卫
  1. VueRouter怎么做懒加载?

把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件

  1. router 和 route 的区别

$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。

$router对象是全局路由的实例,是router构造方法的实例。

  1. v-if和v-show
    相同点: 两者都是在判断DOM节点是否要显示。

    不同点:

a.实现方式: v-if是根据后面数据的真假值判断直接从Dom树上删除或重建元素节点。 v-show只是在修改元素的css样式,也就是display的属性值,元素始终在Dom树上。

b.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件; v-show只是简单的基于css切换;

c.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素始终被保留;

d.性能消耗:v-if有更高的切换消耗,不适合做频繁的切换; v-show有更高的初始渲染消耗,适合做频繁的额切换;

  1. vue.js 的两个核心是什么?
  • 数据驱动:在vue中,数据的改变会驱动视图的自动更新
  • 组件化:组件化开发,将常用的代码封装成组件之后,就能高度的复用,提高代码的可重用性

12.说出至少 4 种 vue 当中的指令和它的用法

v-if(判断是否隐藏)

v-for(把数据遍历出来)

v-bind(绑定属性)

v-model(实现双向绑定)
  1. 什么是组件以及如何使用组件

组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件
将大界面拆分成小界面就是组件化

组件化的好处是可以简化Vue实例的代码,可以提高代码复用性

  1. 单页面应用和多页面应用有哪些优缺点?

概念:只有一个html页面,所有跳转方式都是通过组件切换完成的。
优点:页面之间跳转流畅、组件化开发、组件可复用、开发便捷、易维护。
缺点:首屏加载较慢,加载整个项目中使用的css、js

概念:整个项目有多个html,所有跳转方式都是页面之间相互跳转的。
优点:首屏加载较快,只加载本页所使用的的css、js
缺点:页面跳转较慢,工作量比较大

框架 React

  1. 受控组件 V.S. 非受控组件
<FInput value={x} onChange={fn}/> 受控组件
 <FInput defaultValue={x} ref={input}/> 非受控组件

区别受控组件的状态由开发者维护,非受控组件的状态由组件自身维护(不受开发者控制)

  1. React 有哪些生命周期函数?分别有什么用?(Ajax 请求放在哪个阶段?)
  • 组件将要挂载时触发的函数:componentWillMount
  • 组件挂载完成时触发的函数:componentDidMount
  • 是否要更新数据时触发的函数:shouldComponentUpdate
  • 将要更新数据时触发的函数:componentWillUpdate
  • 数据更新完成时触发的函数:componentDidUpdate
  • 组件将要销毁时触发的函数:componentWillUnmount
  • 父组件中改变了props传值时触发的函数:componentWillReceiveProps

在componentDidMount钩子里请求数据,因为这个周期开始时,当前组件已经被挂载到真实的元素上了

  1. React 如何实现组件间通信?
父子靠 props 传函数
爷孙可以穿两次 props
任意组件用 Redux(也可以自己写一个 eventBus)

  1. shouldComponentUpdate 有什么用?
    用于在没有必要更新 UI 的时候返回 false,以提高渲染性能
  2. 虚拟 DOM 是什么?
    虚拟 DOM 就是用来模拟 DOM 的一个对象,这个对象拥有一些重要属性,并且更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的。
  3. 什么是高阶组件?

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
举例:React-Redux 里 [connect 就是一个高阶组件],比如 connect(mapState)(MyComponent) 接受组件 MyComponent,返回一个具有状态的新 MyComponent 组件。

  1. React diff 的原理是什么?

  2. Redux 是什么?redux - 是怎么实现的, 实现过程

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。重点是『状态管理』。
说出核心概念的名字和作用:Action/Reducer/Store/单向数据流
说出常用 API:store.dispatch(action)/store.getState()

  1. connect 的原理是什么?

react-redux 库提供的一个 API,connect 的作用是让你把组件和store连接起来,产生一个新的组件(connect 是高阶组件)

10.vue和react的主要区别

  • vue是响应式的数据双向绑定系统,而react是单向数据流,没有双向绑定。

  • vue的语法较为简单,适用于小型项目创建,而react更适用于Web端和原生App的开发,侧重于大型应用。

  1. useEffect()怎么使用?

  2. setState()函数是同步的还是异步的?

TypeScript

  1. never 类型是什么?

不应该出现的类型

  1. TypeScript 比起 JavaScript 有什么优点?
  • 提供了类型约束,因此更可控、更容易重构、更适合大型项目、更容易维护

Webpack

webpack 是什么,做了什么?

是一个模块化管理工具兼打包工具
它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。

  1. 有哪些常见 loader 和 plugin,你用过哪些?

file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件

babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码


define-plugin:定义环境变量
mini-css-extract-plugin:抽取css代码,变成一个文件
html-webpack-plugin:用来生成html文件

  1. 英语题:loader 和 plugin 的区别是什么?
  • loader是"加载器",plugin是插件
  • 加载器是用来load一个文件的,比如说babel-loader是把高级的变成IE支持的js,css-loader和style-loader是用来加载CSS然后变为页面中的标签
  • 插件是用来扩展webpack功能的,比如 html-webpack-plugin,它是用来生成HTML文件的,还有一个mini-css-extract-plugin,它是用来抽取css代码,变成一个文件的
  1. 如何按需加载代码?
  • Vue UI组件库的按需加载,为了快速开发前端项目,经常会引入现成的UI组件库,但是只需要几个组件就行了,造成不必要的开销,现在很多组件库已经提供了现成的解决方案,Element UI里的[babel-plugin-component],只需要在参数中进行设置,即可实现组件按需加载了
  • 单页应用的按需加载,现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个问题——首次加载的代码量会越来越多,影响用户的体验。可以用懒加载
  1. 如何提高构建速度?
  • 压缩代码。删除多余的代码、注释、简化代码的写法等等方式。
  • 删除多余的代码。将代码中永远不会走到的片段删除掉。
    5.与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
  • webpack适用于大型复杂的前端站点构建
  • parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果
    由于parcel在打包过程中给出的调试信息十分有限,所以一旦打包出错难以调试,所以不建议复杂的项目使用parcel

安全

  1. 什么是 XSS?如何预防?

跨站脚本攻击(Cross Site Scripting)
对特殊字符进行转译

  1. 什么是 CSRF?如何预防?

跨站请求伪造 (Cross-site request forgery)
使用 post 接口
增加验证,例如密码、短信验证码、指纹等

开放题目

  1. 你遇到最难的问题是怎样的?
    在做记账项目的时候,需要引入SVG,但是我按照官网上提供的方法写完代码后,怎么样都无法在页面显示,这个问题困扰了我一下午,于是在网上搜了好久,最后终于在一个答案中发现要加svg-sprite-loader。
  2. 你在团队的突出贡献是什么?

我没有团队,一个人开发的

我在我的前端团队组织了定期的前端分享,帮助大家了解最新的前端技术

  1. 最近在关注什么新技术
  2. 有没有看什么源码,看了后有什么记忆深刻的地方,有什么收获

变量命名很烂,平时会避免这样命名

  1. 谈谈你的缺点?

node.js不太了解,不过最近正在学。

  1. 有什么想问的吗?
    公司主要用什么框架

刁钻题目

[1,2,3].map(parseInt) // [1, NaN,NaN]
var a = {name: "a"}
a.x = a = {}
a.x 是多少? // undefined
  1. (a ==1 && a==2 && a==3) 可能为 true 吗?
  • 利用 == 会调用 valueOf() 的特性
 var a = {
  value: 1,
  valueOf(){
   return this.value++
  }
 }
 a ==1 && a==2 && a==3 // true
  • 利用 a 会读取 window.a 的特性
 var value = 1; 
 Object.defineProperty(window, 'a', {
     get(){
         return value++;
     }
 })
 a ==1 && a== 2 && a==3 // true
 // 或者 
 a ===1 && a=== 2 && a===3 // true

超纲题(放弃)

  1. JS 垃圾回收机制
  2. Eventloop 说一下

算法和数据结构

1.手写选择排序和冒泡排序,快速排序