Skip to content
本页目录

JavaScript面试题

第1章 JS基础-变量类型和计算【不会变量,别说你会JS】

本章介绍变量的类型和计算的知识点和题目,包括值类型和引用类型区别,类型判断,深拷贝等。变量和类型是一个任何一门语言的基础,不了解的话,会被认为是 JS 语法不过关。 共 4 节 (43分钟)

1-1 JS 值类型和引用类型的区别 (13:02)

变量类型和计算
  • 题目
    • typeof能判断哪些类型
    • 何时使用===何时使用==
    • 值类型和引用类型的区别
    • 手写深拷贝
  • 知识点
    • 变量类型
      • 值类型vs引用类型
      • typeof运算符
      • 深拷贝
    • 变量计算
  • 解答

值类型

js
//值类型
let a =100
let b = a
a =200
console.log(b) //100
//引用类型
let a = {age:20}
let b = a
b.age = 21
console.log(a.age)	// 21
深层分析

值类型在内存中的存储方式

1652773637397

引用类型在内存中的存储方式

  • 引用类型都存储在堆中,变量存储的是引用类型的内存地址

1652775007814

常见的值类型
js
const a //undefined
const s = 'abc'
const n = 100
const b = true
const s = Symbol('s')
常见引用类型
js
const obj = {x:100}
const arr = ['a','b','c']

const n = null //特殊引用类型,指针指向空地址
//特殊引用类型,但不用于存储数据,所以没有"拷贝,复制函数"这一说法
function fn(){}

1-2 手写 JS 深拷贝 (16:13)

typeof运算符
  • 识别所有值类型
  • 识别函数
  • 判断是否是引用类型(不可再细分,再细分需要用原型链的intanceof方法)
js
//判断所有值类型
let a;   					typeof a //'undefined'
const str = 'abc';  		typeof str //'string'
const n = 100;    			typeof n //'number'
const b = true;   			typeof b //'boolean'
const s = Symbol('s');   	typeof s //'symbol'

//能判断函数
typeof console.log	//'function'
typeof function(){}	//'function'

//能识别引用类型(不能再继续识别)
typeof null 		//'object'
typeof ['a','b']	//'object'
typeof {x:100}		//'object'
深拷贝

深拷贝与浅拷贝的区别

  • 浅拷贝:只是拷贝一层,更深层次对象级别的只拷贝了地址
  • 深拷贝:层层拷贝,每一级别的数据都会拷贝
js
const obj = {
	age: 20,
    name: 'xxx',
    address: {
        city: 'beijing'
    },
    arr: ['a','b','c']
}
const obj2 = obj1

obj2.address.city = "shanghai"
console.log(obj1.address.city)  //"shanghai"

//深拷贝
/***
@param {Object} obj要拷贝的对象
*/
function deepClone(obj = {}){
    if(typeof obj !== 'object' || obj == null){
        // obj是null或者不是对象和数组,直接返回
        return obj
    }
    //初始化返回结果
    let result
    if(obj instanceof Array){	//判断数组
        result = []
    }else{
        result = {}
    }
    //处理结果
    for(let key in obj){
        if(obj.hasOwnProperty(key)){// 保证key不是原型的属性
            //递归调用
            result[key] = deepClone(obj[key])
        }
    }
    
    
    return  result
}

const obj3 = deepClone(obj1)	//深拷贝
obj3.address.city = "shanghai"
console.log(obj3.address.city)  //"shanghai"
console.log(obj1.address.city)  //"beijing"
思考深拷贝的堆栈图

1-3 变量计算 - 注意某些类型转换的坑 (09:48)

字符串拼接
js
const a = 100 + 10 // 110 加法
const b = 100 + '10' // '10010'
const c = true + '10' // 'true10'
const d = 100 + parseInt('10') // 110 加法
== 运算符
js
100 == '100' 		//true
0 == ''				//true
0 == false 			// true
false == '' 		//true
false == '' 		// true
null = undefined 	//true

// 什么情况下用==
// 除了 == null之外,其他一律用 === ,例如
const obj = {x:100}
if(obj.a == null ){}
//相当于: 
//if(obj.a === null || obj.a === undefined){}
if语句和逻辑运算

truly变量: !!a===true的变量

falsely变量:!!a===false的变量

js
//以下是falsely变量 除此之外都是truely变量
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false

if语句判断的不是true 和 false 实际上判断的是truly变量和falsely变量

js
//truly变量,以下if语句会执行
const a = true
if(a){
    // ...
}
const b = 100
if(b){
    // ...
}
//falsly变量 ,以下if语句不会执行
const c = ''
if(c){
    //...
}
const d = null
if(d){
    //...
}
let e
if(e){
    //...
}
逻辑判断
js
console.log(10&&0) 			//0			fasly直接返回
console.log(''||'abc')		//'abc'		truly直接返回
console.log(!window.abc)	//true		

1-4 变量类型相关的面试题 (03:51)

  • 题目

    • typeof能判断哪些类型
    • 何时使用===何时使用==
    • 值类型和引用类型的区别
    • 手写深拷贝
  • typeof能判断哪些类型

    • 识别所有值的类型
    • 识别函数
    • 判断是否是引用类型(不可再细分)
  • 何时使用===何时使用==

    除了 == null其他一律用===

  • 值类型和引用类型的区别

    出场景题

    js
    const obj1 = {x:100,y:200}
    const obj2 = obj1
    let x1 = obj1.x	//这里是干扰,值类型,可以删除
    obj2.x = 101
    x1 = 102	////这里是干扰,值类型,可以删除
    console.log(obj1)	//{x:101,y:200}
    
  • 手写深拷贝

    • 注意判断值类型和引用类型
    • 注意判断是数组还是对象
    • 递归

第2章 JS基础-原型和原型链【三座大山之一,必考!!!】

本章介绍原型、原型链和 class 相关的知识点和题目。包括 class ,继承,原型,原型链,instanceof。原型是“JS 三座大山”之一,原型和原型链也是必考知识点。

2-1 JS 原型的考点和面试题 (04:17)

原型作用是啥:

  • es6之前js是用原型来实现继承的
  • es6是用class来继承的

3个题目:

  • 如何准确判断一个变量是不是数组
  • 手写一个简易的jquery,考虑插件和扩展性
  • class原型本质,怎么理解

知识点:

  • class和继承
  • 类型判断instanceof
  • 原型和原型链

2-2 如何用 class 实现继承 (14:50)

class有哪些东西
  • constructor 构建
  • 属性
  • 方法

class-demo.js

js
class Student{
	constructor(name ,number){
		this.name = name
		this.number = number
	}
	sayHi(){	//定义方法
		console.log(`姓名${this.name},学号${this.number}`)
	}
}
//通过new 类声明对象实例
const xiaomi = new Student('小米',100)
console.log(xiaomi.name)
console.log(xiaomi.number)
xiaomi.sayHi()

//通过new 类声明对象实例
const apple = new Student('苹果',200)
console.log(apple.name)
console.log(apple.number)
apple.sayHi()
继承
  • extends
  • super
  • 扩展或重写方法

代码演示

js
class People {
    constructor(name){
        this.name = name
    }
    eat(){
        console.log(`${this.name} eat something`)
    }
}
//子类
class Student extends People{
    constructor(name, number){
        super(name)		//获取父类属性
        this.number = number
    }
    sayHi(){	
		console.log(`姓名${this.name},学号${this.number}`)
	}
    
}
//子类
class Teacher    extends People{
    constructor(name, number){
        super(name)		//获取父类属性
        this.major = major
    }
    teach(){	
		console.log(`${this.name}${this.major}`)
	}
    
}
//通过new 类声明对象实例
const apple = new Student('苹果',200)
console.log(apple.name)
console.log(apple.number)
apple.sayHi()
apple.eat()
//通过new 类声明对象实例
const ai = new Student('小爱老师',前端)
console.log(ai.name)
console.log(ai.major)
ai.teach()
ai.eat()

2-3 如何理解 JS 原型(隐式原型和显示原型) (09:10)

类型判断 instanceof 来判断是否是子类
js
xiaomi instanceof Student //true
xiaomi instanceof People //true
xiaomi instanceof Object //true Object是所有引入类型的父类

[] instanceof Array //true Array是[]的父类
[] instanceof Object //true

{} instanceof Object //true
原型
js
//class实际上是函数,可见是语法糖
typeof People //'function'
typeof Student 
//隐式原型和显示原型
console.log(xiaomi.__proto__) //隐式原型只有在实例中
console.log(Student.prototype) //显示原型在类中
console.log(xiaomi.__proto__===Student.prototype)
原型关系
  • 每个class都有显示原型prototype
  • 每个实例都有隐式原型__proto__
  • 实例的__proto__指向class的prototype
基于原型的执行规则
  • 获取属性xiaomi.name活执行方法xiaomi.sayHi()时
  • 先在自身属性和方法中寻找
  • 如果找不到择取__proto__寻找

1651818578116

2-4 instanceof 是基于原型链实现的 (08:57)

原型链是指带有继承关系的类的原型

1651818966369


console.log(Student.prototype.__proto__) //Student类是People类的继承也是某种程度的实例
console.log(People.prototype) //eat函数
console.log(Student.prototype.__proto__===People.prototype)

hasOwnProperty()方法,判断是否是自己的属性

js
xiaomi.hasOwnProperty('name') //true
xiaomi.hasOwnProperty('sayHi') //false sayHi是Student的方法 是xiaomi通过原型链去寻找的

如何找到hasOwnProperty找到原型链

1651819367708

那么instanceof就是看你是否能找到对应顶层的类型是否相等,实现原理就是根据原型链

2-5 JS 原型本章相关的面试题 (12:30)

题目

  • 如何准确判断一个变量是不是数组

  • 手写一个简易的jquery,考虑插件和扩展性

  • class原型本质,怎么理解

    class的原型本质

    • 原型和原型链的图示
    • 属性和方法的执行规则
  • 手写一个简易的jquery,考虑插件和扩展性

js
class JQuery{
    constructor(selector){
        const result = document.querySelectorAll(selector)
        const length = result.length
        for(let i = 0;i< length;i++){
            this[i] = result[i] //获取每一个dom     
        }
        this.length = length
        this.selector = selector
    }
    get(index){
        return this[index]
    }
    each(fn){	//遍历
        for(let i = 0;i<this.length;i++){
            const elem = this[i]
            fn(elem)
        }
    }
    on(type, fn){ //监听
        return this.each(elem=>{
            elem.addEventListener(type, fn ,false)
        })
    }
    //扩展很多DOM操作
}


//html
<p>1</p>
<p>2</p>
<p>3</p>
//定义一个jquery对象
const $p = new JQuery('p')
console.log($p) 
$p.get(1)
$p.each((elem)=>console.log(elem.nodeName))
$p.on('click',()=>alert('clicked'))
考虑插件扩展性
  • 方式1:使用插件(原型)
  • 方式2:复写机制(继承)
js
//插件
JQuery.prototype.dialog = function(info){
    alert(info)
}
$p.dialog('abc')//弹出abc

//造轮子
class myJQuery extends JQuery{
    constructor(selector){
        super(selector)
    }
    //扩展自己的方法
    addClass(classname){
        
    }
    style(data){
        
    }
}

第3章 JS基础-作用域和闭包【三座大山之二,不会闭包,基本不会通过】

本章介绍作用域和闭包的知识点和题目。包括作用域,自由变量,闭包,this 等部分。作用域是“JS 三座大山”之二,不知道闭包的话,面试通过概率不大。

3-1 什么是作用域?什么是自由变量? (07:11)

因为存在多个函数调用所以作用域很重要

题目
  • this的不同应用场景,如何取值
  • 手写bind函数
  • 实际开发中闭包的应用场景,举例说明
  • 场景题
    • 1651902041333
知识点
  • 作用域和自由变量
  • 闭包
  • this
作用域

一个变量的合法的使用范围,如果超出使用范围就会报错

1651902161988

种类:

  • 全局作用域
  • 函数作用域
  • 块级作用域(es6新增)
js
//es6块级作用域
if(true){
	let x = 100
}
console.log(x)	//会报错
自由变量:(没有定义的变量)
  • 一个变量在当前作用域没有定义,但被使用了
  • 向上级作用域,一层一层依次寻找,直到找到为止
  • 如果到全局作用域都没找到,则报错xx is not defined

3-2 什么是闭包?闭包会用在哪里? (07:46)

闭包

  • 作用域的特殊情况,有两种表现:
    1. 函数作为参数被传递
    1. 函数作为返回值被返回

1.closure.js

js
//1.函数作为返回值
function create(){
    let a = 100;
    return function(){
        console.log(a)
    }
}
const fn = create()
const a = 200
fn()	//求该结果 为100

//2.函数作为返回值被返回
function print(fn){
    const a = 200
    fn()
}
const a = 100
function fn(){
    console.log(a)
}
print(fn)	//返回100
总结:
闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找不是在执行的地方

3-3 this 有几种赋值情况 (04:35)

1.this在5种场景中调用
  1. 作为普通函数
  2. 使用call apply bind
  3. 作为对象方法被调用
  4. 在class方法中调用
  5. 箭头函数中被调用
总结:
this取什么值是在函数执行的时候确定的不是在函数定义的时候确定的
js
function fn1(){
    console.log(this)
}
function fn2(a,b){	//有参数的函数
    console.log(this)
    console.log(a)
    console.log(b)
}
fn1() //window
//call:改变this指向
fn1.call({x:100})	//{x:100}

//apply:改变this指向,和call基本上一致,唯一区别在于传参方式,是用数组
fn2.apply({x:100},[1,2])	//{x:100} 1 2
fn2.call({x:100},1,2)	//{x:100} 1 2

//bind:作用和call作用是相同的改变this指向,但是是返回一个新的函数
const fn2 = fn1.bind({x:200})
fn2()		//{x:200}


//对象方法中
const zhangsan = {
    name: '张三',
    sayHi(){
        //this即当前对象
        console.log(this)
    },
    wait(){
        // this===window
        setTimeout(function(){	//setTimeout调用的是window的方法
            console.log(this)
        })
    }
}

//对象方法中,箭头函数
const zhangsan1 = {
    name: '张三',
    sayHi(){
        //this即当前对象
        console.log(this)
    },
    wait(){
        // this即当前对象
        setTimeout(()=>{	//箭头函数中this永远返回上级作用域
            console.log(this)
        })
    }
}

//类中的this
class People{
    constructor(name){
        this.name = name
        this.age = 20
    }
    sayHi(){
        console.log(this)
    }
}
const zhangsan = new People('张三')
zhangsan.sayHi()	//zhangsan对象

3-4 作用域相关的面试题 (11:47)

题目

  • this的不同应用场景,如何取值
    1. 作为普通函数
      • winow
    2. 使用call apply bind
      • 返回指向对象
    3. 作为对象方法被调用
      • 返回当前对象
      • 如果是setTimeout返回window
    4. 在class方法中调用
      • 返回new出来的对象
    5. 箭头函数中被调用
      • 返回上一级作用域
  • 手写bind函数

bind-demo.js

js
//bind示例
function fn1(a,b,c){
    console.log('this',this)
    console.log(a,b,c)
    return 'this is fn1'
}
const fn2 = fn1.bind({x:100}, 10, 20, 30)
const res = fn2()	//返回出了{x:100}   10 20 30
console.log(res)
js
//手写bind
Function.prototype.bind1 = function(){
	//将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)
    //获取this(数组第一项)
    const t = args.shift()
    //fn1.bind(..)中的fn1
    const self = this
    //返回一个函数
    return function(){
        return self.apply(t,args)
    }
}
  • 实际开发中闭包的应用场景,举例说明
    • 隐藏数据
    • 做一个简单的cache工具
js
//闭包隐藏数据,只提供API
function createCache(){
    const data = {}	//闭包中的数据,被隐藏,不被外界访问
    return {
        set:function(key,val){
            data[key] = val
        },
        get:function(key){
            return data[key]
        }
    }
}

const c = createCache()
c.set('a',100)
console.log(c.get('a'))

//这里只能通过set函数来修改data没有其他方法
应用:

jq的事件绑定,比如一个列表多个li绑定对应不同的事件

例题

1652272520251

绑定函数不会立即执行的情况,需要闭包来解决循环数值相同问题

3-5 补充 - 原型中的 this (02:18)

js
xiaoluo.sayHi()	//执行父类中定义的sayHi方法
xiaoluo.__proto__.sayHi.call(xiaoluo)	//等效于xiaoluo.sayHi()

第4章 异步【三座大山之三,必考!!!】

本章介绍异步的知识点和题目。包括异步和同步的区别,异步应用场景,以及 Promise 。异步是“JS 三座大山”之三,所有公司的 JS 面试,100% 会考察异步和 Promise 。

4-1 同步和异步有何不同 (09:31)

异步和单线程
  • 题目

    • 同步和异步的区别是什么?
    • 手写用promise加载一张图片
    • 前端使用异步的场景有哪些?
    • 场景题
    js
    //setTimeout 笔试题 是按什么顺序打印
    console.log(1)
    setTimeout(function(){
        console.log(2)
    },1000)
    console.log(3)
    setTimeout(function(){
        console.log(4)
    },0)
    console.log(5)
    
  • 知识点

    • 单线程和异步
    • 应用场景
    • callback hell和Promise
  • 解答

单线程和异步
  • js是单线程语言,只能同事做一件事儿
  • 浏览器和nodejs已支持js启动进程,如 web work
  • js和dom渲染共用同一个线程,因为js可修改dom结构

需求

  • 遇到等待(网络请求,定时任务)不能卡住
  • 需要异步
  • 回调callback函数形式
js
//异步  程序会立即执行 100 300 再等待1s后执行200 不会阻塞进程
console.log(100)
setTimeout(function(){
    console.log(200)
},1000)
console.log(300)
//同步 程序 100 弹出200 卡住了 300不会出来
console.log(100)
alert(200)
console.log(300 )
异步和同步
  • 基于js是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行

4-2 异步的应用场景有哪些 (03:28)

应用场景

  • 网络请求,如ajax图片加载
    • cpu是空闲的,需要异步
  • 定时任务,如setTimeout
js
// ajax
console.log('start')
$.get('./data1.json',function(data1){
    console.log(data1)	//这里异步,等到加载完才触发,没有停下来等待
})
console.log('end')
//图片加载
console.log('start')
let img = document.createElement('img')
img.onload = function(){	//这里相当于异步,等到加载完成才触发
    console.log('loaded')
}
img.src = '/xxx.png'
console.log('end')
定时器
js
//setTimeout 一次性
console.log(100)
setTimeout(function(){
    console.log(200)
},1000)
console.log(300)
//setInterval  循环执行
console.log(100)
setInterval(function(){
    console.log(200)
},1000)
console.log(300)

4-3 promise的基本使用 (05:55)

callback hell回调地狱
js
//获取第一份数据
$.get(url1,(data1)=>{
    console.log(data1)
    //获取第二份数据
	$.get(url2,(data2)=>{
        console.log(data2)
        //获取第三份数据
        $.get(url3,(data3)=>{
        	console.log(data3)
        })
    })
})
避免回调地狱,有了promise语法
js
//用promise写法来写上述功能
//定义promise的函数
function getData(url){
     return new Promise((resolve,reject)=>{
         $.ajax({
             url,
             success(data){
                 resolve(data)
             },
             error(err0){  
                 reject(err)
             }
         })
     })
 }

const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1=>{
    console.log(data1)
    return getData(url2)
}).then(data2=>{
    console.log(data2)
    return getData(url3)
}).then(data3=>{
    console.log(data3)
}).catch(err=>console.error(err))

4-4 JS 异步相关的题 (12:38)

题目

  • 同步和异步的区别是什么?
    • 基于js是单线程语言
    • 异步不会阻塞代码执行
    • 同步会阻塞代码执行
  • 手写用promise加载一张图片
js
const url = 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
function loadImg(src){
    return new Promise((resolve,reject)=>{
        const img = document.creatElement('img')
        img.onload = ()=>{	
            resolve(img)
        }
        img.onerror = ()=>{
            reject(new Error(`图片加载失败 ${src}`))
        }
        img.src = src
    })
}
//写法2
function loadImg(src){
    const p = new Promise((resolve,reject)=>{
        const img = document.creatElement('img')
        img.onload = ()=>{	
            resolve(img)
        }
        img.onerror = ()=>{
            reject(new Error(`图片加载失败 ${src}`))
        }
        img.src = src
    })
    return p  //返回promise对象
}
loadImg(url).then(img=>{
    console.log(img.width)
    return img
}).then(img=>{
    console.log(img.height)
}).catch(ex=>console.error(ex))
const url2 = 'https://news-bos.cdn.bcebos.com/mvideo/log-news.png'
loadImg(url).then(img1=>{
    console.log(img1.width)
    return img1		//返回普通对象
}).then(img1=>{
    console.log(img1.height)
    return loadImg(url2)	//promise实例 返回的是resolve(img)中的img
}).then(img2=>{
    console.log(img2.height)
}).catch(err=>console.error(err))
  • 前端使用异步的场景有哪些?
    • 网络请求,如ajax图片加载
    • 定时任务,如setTimeout
  • 场景题
js
//setTimeout 笔试题 是按什么顺序打印
console.log(1)
setTimeout(function(){
    console.log(2)
},1000)
console.log(3)
setTimeout(function(){
    console.log(4)
},0)
console.log(5)
//答案
1 3 5 4 2
小结
  • 单线程和异步,异步和同步的区别
    • 异步不会阻塞
  • 前端异步应用场景
  • promise解决callback hell

4-5 JS基础部分的考点总结 (03:33)

第5章 JS 异步进阶【想要进大厂,更多异步的问题等着你】

JS 的特色就是异步编程,所有有很多关于异步的考点,本章都会讲解。如 event loop、promise、async-await、微任务和宏任务。学不会这些,就不算是精通 JS ,也无法进大厂。 共 18 节 (156分钟)

5-1 本章考点介绍

js异步-进阶
  • 之前讲解js异步,在于初阶的应用
  • 本章在于js异步的原理和进阶
  • 对初学者优点难度,尽量深入浅出
本章主要内容
  • event loop
  • promise进阶
  • async/await
  • 微任务/宏任务

5-2 看⼏个异步的⾯试题

问答题

  • 请描述event loop(事件循环/事件轮询)的机制.可画图
  • 什么是宏任务和微任务,两者有什么区别
  • promise有哪3种状态?如何变化

场景题-promise then和catch的连接

js
//第一题
Promise.resolve().then(()=>{
	console.log(1)
}).catch(()=>{
	console.log(2)
}).then(()=>{
	console.log(3)
})
//第二题
Promise.resolve().then(()=>{
	console.log(1) 
    throw new Error('error1')
}).catch(()=>{
	console.log(2)
}).then(()=>{
	console.log(3)
})
//第三题
Promise.resolve().then(()=>{
	console.log(1) 
    throw new Error('error1')
}).catch(()=>{
	console.log(2)
}).catch(()=>{
	console.log(3)
})

场景题-async/await

js
async function fn(){
    return 100
}
(async function fn(){
    const a = fn()	//??
    const b = await fn() //??
})


(async function(){
 	console.log('start')
    const a = await 100
    console.log('a',a)
    const b = await Promise.resolve(200)
    console.log('a',a)
    const c = await Promise.reject(300)
    console.log('c',c)
})()//执行完毕打印哪些内容

场景题-promise和setTimeout的顺序

js
console.log(100)
setTimeout(()=>{
	console.log(200)
})
Promise.resolve().then(()=>{
    console.log(300)
})
console.log(400)

场景题-外加async/await的顺序问题

js
async function async1(){
    console.log('async1 start')
	await async2()
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function (){
    console.log('setTimeout')
},0)
async1()

new Promise(function (resolve){
    console.log('promise1')
    resolve()
}).then(function(){
    console.log('promise2')
})

console.log('script end')

5-3 什么是event loop

event loop(事件循环/事件轮询)
  • js是单线程运行的
  • 异步要基于回调来实现的
  • event loop就是异步回调的实现原理
js如何执行?
  • 从前到后,一行一行执行
  • 如果某一行执行报错,则停止下面代码的执行
  • 先把同步代码执行完,再执行异步
示例
js
console.log('Hi')	//同步代码
setTimeout(function cb1(){
    console.log('cb1') //异步代码
},5000)
console.log('Bye')	//同步代码

//Hi Bye cb1
event loop过程
  • 初学者可能会感觉难,尽量深入浅出
  • 第一遍讲解,感觉不懂不要停下,会重复讲解3遍
  • 不要抠细节,不要扩大范围,核心是event loop过程

5-4 event loop 的执行过程

示例
js
console.log('Hi')	//同步代码
setTimeout(function cb1(){
    console.log('cb1') //异步代码
},5000)
console.log('Bye')	//同步代码

//Hi Bye cb1
参与event loop的5个角色
  • browser console
    • 浏览器控制台
  • Call Stack
    • 执行语句栈
  • Web APIs
    • web api是js语法之外的浏览器的api,如settimeout
  • Event loop
    • 事件轮询,不断循环执行每一个事件
  • Callback Queue
    • 回调函数队列
总结event loop过程
  1. 同步代码,一行一行放在call stack执行
  2. 遇到异步,先在webAPis中记录一下,等待(定时,网络请求等)
  3. 时机到了,就会移动到Callback Queue
  4. 如果Call Stack为空(即同步代码执行完)Event loop开始工作
  5. 轮询查找callback queue,如有则移动到call stack执行
  6. 然后继续轮询查找(永动机一样)

5-5 DOM事件和event loop的关系

5-6 Promise有哪三种状态

5-7 Promise的then和catch如何影响状态的变化

5-8 Promise关于then和catch的⾯试题

5-9 async-await语法介绍-part1

5-10 async-await和Promise有什么关系

5-11 async-await是语法糖,异步的本质还是回调函数

5-12 for-of的应⽤场景

5-13 什么是宏任务和微任务

5-14 event-loop和DOM渲染的关系

5-15 为什么微任务⽐宏任务执⾏更早

5-16 微任务和宏任务的根本区别

5-17 解答JS异步的⾯试题

5-18 本章考点总结

第6章 JS-Web-API-DOM【学会DOM,才能具备网页开发的基础】

本章介绍 DOM 操作的知识点和题目。包括 DOM 结构,常用 DOM 操作,DOM 性能优化等。DOM 是网页结构的基础,学会 DOM 操作才可以做网页开发。 共 6 节 (42分钟)

6-1 从JS基础到JS-Web-API (03:20)

  • js基础知识,规定语法(ECMA)
  • js web api(w3c)
  • 前者是后者的基础,两者结合才能真正实际应用
js基础知识
  • 变量的类型和计算
  • 原型和原型链
  • 作用域和闭包
js web api
  • dom
  • bom
  • 事件绑定
  • ajax
  • 存储

6-2 DOM的本质是什么 (06:56)

前言
  • vue和react框架应用广泛,封装dom操作
  • 但dom操作一直是前端基础,必备知识
  • 只会vue而不懂dom操作的程序员不会长久
dom操作(document object model)
  • 题目
    • dom是哪种数据结构
    • dom操作常用的api
    • attr和property的区别
    • 一次性插入多个dom节点,考虑性能
  • 知识点
    • dom本质
    • dom节点操作
    • dom结构操作
    • dom性能
  • 解答
DOM本质

HTML是由xml进化而来

xml是树

dom是html语言文件解析出来的一棵树

6-3 DOM节点操作 (13:33)

DOM节点操作
  • 获取dom节点
  • attribute
  • property
获取dom节点

获取dom节点,通过dom节点设置dom的样式

  • property 形式
  • attribute函数
js
const div1 = document.getElementById('div1')
console.log('div1', div1)

const divList = document.getElementsByTagName('div') // 集合
console.log('divList.length', divList.length)
console.log('divList[1]', divList[1])

const containerList = document.getElementsByClassName('container') // 集合
console.log('containerList.length', containerList.length)
console.log('containerList[1]', containerList[1])

const pList = document.querySelectorAll('p')
console.log('pList', pList)

const pList = document.querySelectorAll('p')
const p1 = pList[0]

// property 形式
p1.style.width = '100px'
console.log( p1.style.width )
p1.className = 'red'
console.log( p1.className )
console.log(p1.nodeName)
console.log(p1.nodeType) // 1

// attribute
p1.setAttribute('data-name', 'imooc')
console.log( p1.getAttribute('data-name') )
p1.setAttribute('style', 'font-size: 50px;')
console.log( p1.getAttribute('style') )
property和attribute区别
  • property:
    • 修改对象属性,不会体现到html结构中
  • attribute:
    • 修改html属性,会改变html结构
  • 两者都有可能引起dom重新渲染,尽量使用property,attribute一定会重新渲染因为html结构改变了

6-4 DOM结构操作 (08:34)

dom结构操作
  • 新增/插入节点
  • 获取子元素列表,获取父元素
  • 删除子元素
新增/插入节点
js
// 新建节点
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入节点
div1.appendChild(newP)
// 移动节点	(针对已有节点p1,则是移动节点)
const p1 = document.getElementById('p1')
div2.appendChild(p1)
获取子元素列表,获取父元素
js
// 获取父元素
console.log( p1.parentNode )

// 获取子元素列表
const div1ChildNodes = div1.childNodes
console.log( div1.childNodes )	//这里包含了p标签元素 也包含了文本元素,需要排除文件元素
//Array.prototype.slice.call(div1.childNodes)是将div1.childNodes变成数组类型
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => {
    if (child.nodeType === 1) {	//nodeType为1是p标签
        return true
    }
     return false
})
console.log('div1ChildNodesP', div1ChildNodesP)

删除子元素

js
div1.removeChild( div1ChildNodesP[0] )

6-5 如何优化 DOM 操作的性能 (07:07)

dom性能
  • dom操作非常昂贵,避免频繁的dom操作
  • 对dom查询做缓存
  • 将频繁操作改为一次性操作
dom查询做缓存
js
//不缓存dom查询结果
for(let = 0; i < document.getElementsByTagName('p').length; i++){
    //每次循环,都会计算length,频繁进行dom查询
}
//缓存dom查询结果
const pList = document.getElementsByTagName('p')
const length = pList.length;
for(let i = 0; i< length; i++){
    //缓存length,只进行一次dom查询
}
将频繁操作改为一次性操作
js
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)

console.log(list)

6-6 DOM 操作相关的面试题 (02:03)

  • 题目
    • dom是哪种数据结构
      • 树(DOM树)
    • dom操作常用的api
      • dom节点操作
      • dom结构操作
      • attribute和property区别
    • 一次性插入多个dom节点,考虑性能

第7章 JS-Web-API-BOM【内容虽然不多,但是你不能不会】

本章介绍 BOM 操作的知识点和题目。本章内容虽然不多,但不可不会。 共 1 节 (6分钟)

7-1 BOM 操作相关的面试题 (05:57)

BOM操作(Browser Object Model)
  • 题目

    • 如何识别浏览器类型
    • 分析拆解url各个部分
  • 知识点

    • navigator
      • 浏览器的信息
    • screen
      • 屏幕的信息
    • location
      • url信息
    • history
      • 前进后退的信息
    js
    //navigator(判斷使用的是否是谷歌浏览器)但是不是很准确,浏览器的agent可能包含所有的浏览器标识
    const ua = navigator.userAgent
    const isChrome = ua.indexOf('Chrome')
    console.log(isChrome)
    
    //screen(获取屏幕宽度)
    console.log(screen.width)
    console.log(screen.height)
    
    location和history
    js
    //location
    console.log(location.href) //获取整个网址
    console.log(location.protocol) // 'http:' 'https:'
    console.log(location.host)	//获取域名
    console.log(location.pathname)	//  获取路径   '/learn/199'
    console.log(location.search)	//获取查询参数
    console.log(location.hash)	//获取#内容
    
    //history
    history.back()	//后退
    history.forward()	//前进
    

第8章 JS-Web-API-事件【事件不会,等于残废,必考!必考!】

本章介绍事件绑定的知识点和题目。包括事件绑定,事件冒泡机制,事件代理。事件能让网页和鼠标、键盘进行交互,初级 JS 面试必考。 共 3 节 (29分钟)

8-1 事件绑定和事件冒泡 (11:59)

题目
  • 编写一个通用的事件监听函数
  • 描述事件冒泡的流程
  • 无限下拉的图片列表,如何监听每个图片的点击?
知识点
  • 事件绑定
  • 事件冒泡
  • 事件代理
事件绑定
js
const btn = document.getElementById('btn1')
btn.addEventListener('click',event=>{
    console.log('clicked')
})
定义一个通用事件绑定
js
//通用事件绑定
function bindEvent(elem, type, fn){
    elem.addEventListener(type, fn)
}
const a = document.getElementById('link1')
bindEvent(a, 'click', e=>{
    e.preventDefault() //阻止默认行为
    alert('clicked')
})

event怎么用

  • event.traget
  • event.preventDefault()
  • event.stopPropagation()
    • 阻止事件冒泡
js
function bindEvent(elem, type, fn){
    elem.addEventListener(type, fn)
}
const a = document.getElementById('link1')
bindEvent(a, 'click', e=>{
	console.log(e.target)	//打印出a标签的dom元素 
    e.preventDefault() //阻止默认行为
})
事件冒泡

子元素触发的事件,会一层一层传给父元素

但event.target的元素只有一个就是触发的元素

html
html结构
<body>
    <div id="div1">
    	<p id="p1">
            激活
        </p>
        <p id="p2">
            取消
        </p>
        <p id="p3">
            取消
        </p>
        <p id="p4">
            取消
        </p>
    </div>
    <div id="div2">
    	<p id="p5">
            取消
        </p>
        <p id="p5">
            取消
        </p>
    </div>
</body>

js
<script>
	const p1 = document.getElementById('p1')
    const body = document.body
    bindEvent(p1,'click',e=>{
        e.stopPropagation()	//注释这行,体会事件冒泡 阻止冒泡
        alert('激活')
    })
    bindEvent(body,'click',e=>{	//给body绑定取消就不用每个都给取消元素绑定了,为什么给body绑定可以代替所有的取消元素呢,因为点击了任何body中的元素,那么就算该元素没有绑定事件,一层层往上传递也可触发body的监听事件
        alert('取消')
    })
</script>

8-2 什么是事件代理(面试必考) (12:26)

事件代理

应用场景:有很多元素的列表,每个元素都有绑定对应的事件

html
html
<div>
    <a href="#">a1</a>
    <a href="#">a2</a>
    <a href="#">a3</a>
    <a href="#">a4</a>
</div>
<button>
    点击增加一个 a 标签
</button>

js
<script>
	const div1 = document.getElementById('div1')
    div1.addEventListener('click',e=>{	//通过事件代理的方法就不用单独给每个a标签绑定一个事件 e.target是事件代理的关键
        e.preventDefault()	//阻止事件默认行为 阻止a标签跳转
        const target = e.target
        if(e.nodeName === 'A'){
            alert(target.innerHTML)
        }
    })
</script>

优点

  • 代码简洁
  • 减少浏览器内存占用
  • 不要滥用
    • 适用在瀑布流每个元素事件监听
定义一个通用事件绑定(支持事件代理)
js
function bindEvent(elem, type, selector, fn) {
    if (fn == null) {
        fn = selector
        selector = null
    }
    elem.addEventListener(type, event => {
        const target = event.target
        if (selector) {
            // 代理绑定
            if (target.matches(selector)) {	//matches是dom元素是否符合于一个css选择器
                fn.call(target, event) //call.(thisOject, arg1 ,arg2 ...) event是参数
            }
        } else {
            // 普通绑定
            fn.call(target, event)
        }
    })
}

// 普通绑定
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function (event) {
    // console.log(event.target) // 获取触发的元素
    event.preventDefault() // 阻止默认行为
    alert(this.innerHTML)
})

// 代理绑定
const div3 = document.getElementById('div3')
bindEvent(div3, 'click', 'a', function (event) {	//注意这个不能用箭头函数,因为用箭头函数时this是window
    event.preventDefault()
    alert(this.innerHTML)
})
bindEvent(div3, 'click', 'a', (event)=> {	//如果要使用箭头函数就不要用this,用参数
    event.preventDefault()
    alert(event.target.innerHTML)
})

8-3 DOM 事件相关的面试题 (03:39)

问题解答
  • 编写一个通用的事件监听函数
  • 描述事件冒泡的流程
    • 基于dom树形结构
    • 事件会顺着触发元素往上冒泡
    • 应用场景:事件代理
  • 无限下拉的图片列表,如何监听每个图片的点击?
    • 事件代理
    • 用e.target获取触发元素
    • 用matches来判断是否是触发元素

第9章 JS-Web-API-Ajax【每个工程师必须熟练掌握的技能】

本章介绍 ajax 相关的知识点和题目。包括 XMLHttpRequest ,同源策略,跨域方式,以及常用插件介绍。我们早就进入了动态网页时代,而当下的前后端分离开发方式,更加要求每个工程师必须熟练掌握 ajax 。 共 6 节 (54分钟)

9-1 ajax 的核心API - XMLHttpRequest (19:23)

ajax
  • 题目
    • 手写一个简易的ajax
    • 跨域的常用实现方式
  • 知识点
    • XMLHttpRequest
    • 状态码
    • 跨域:同源策略,跨域解决方案
  • 解答
XMLHttpRequest
js
//get请求
const xhr = new XMLHttpRequest()
xhr.open("GET","/data/test.json",false)	// /data/test.json是请求地址 false是异步请求
xhr.onreadystatechange = function(){	//监听返回结果
    //这里的函数异步执行,可参考之前js基础中的异步模块
    if(xhr.readyState === 4){
        if(xhr.status === 200){
            alert(xhr.responseText)
            console.log(
            	JSON.parse(xhr.responseText)	//将字符串转换为json对象
            )
        }else{
            console.log("其他情况")
        }
    }
}
xhr.send(null)	//发送数据,因为此时是get请求无需发送数据

//post请求
const xhr = new XMLHttpRequest()
xhr.open("POST","/login",true)	// /data/test.json是请求地址 true是异步请求
xhr.onreadystatechange = function(){	//监听返回结果
    //这里的函数异步执行,可参考之前js基础中的异步模块
    if(xhr.readyState === 4){
        if(xhr.status === 200){
            alert(xhr.responseText)
            console.log(
            	JSON.parse(xhr.responseText)	//将字符串转换为json对象
            )
        }else if(xhr.status === 404){
            console.log("404 not found")
        }else{
            console.log("其他情况")
        }
    }
}
const postData = {
    userName: 'zhangsan',
    password: 'xxxx'
}
xhr.send(JSON.stringify(postData))	//将对象转为字符串 发送数据
xhr.readyState状态的含义
  • 0-(未初始化)还没有调用send()方法
  • 1-(载入)已调用send()方法,正在发送请求
  • 2-(载入完成)send()方法执行完成,接受到全部响应内容
  • 3-(交互)正在解析响应内容
  • 4-(完成)响应解析完成,可以在客户端调用
xhr.status
  • 2xx-表示成功处理请求,如200
  • 3xx-需要重定向,浏览器直接跳转,如301(永久跳转) 302(临时跳转) 304(缓存)
  • 4xx-客户端请求错误,如404 403

9-2 什么是浏览器的同源策略 (08:57)

跨域
  • 什么是跨域(同源策略)
  • jsonp
  • cors(服务端支持)
同源策略
  • ajax请求时,浏览器要求当前网页和server必须同源(安全)
  • 同源: 协议, 域名, 端口 三者必须一致
  • 前端:http://a.com:8080;serve:http://b.com/api/xxx
加载 图片 css js可无视同源策略
  • <img src="跨域的图片地址">
    • 图床
    • <img />可以用于统计打点,可使用第三方统计服务
  • <link href=跨域的css地址>
    • cdn
    • cdn一般是外域
  • <script src="跨域的js地址"></script>
    • cdn
    • jsonp
总结
  • 所有的跨域都必须经过server端允许和配合
  • 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号

9-3 实现跨域的常见方式 - jsonp 和 CORS (10:32)

jsonp
  • 访问http://imooc.com,服务端一定返回个html文件吗?
  • 服务器可以任意动态拼接数据返回,只要符合hrml格式要求
  • 同理<script src="http://imooc.com/getData.js">
  • <script>可以绕过跨域限制
  • 服务器可以任意动态拼接数据返回
  • 所以,<script>可以获得跨域的数据,只要服务端愿意返回
本地请求jsonp演示
html
<script>
    //預先定义好需要执行的函数,等待jsonp传递回来函数,就执行
    window.abc = function (data) {
        console.log(data)
    }
</script>
//jsonp
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script> 
//jsonp传递回来的函数 表示abc函数立即执行
abc(
    { name: 'xxx' }
)
jquery实现jsonp
js
$.ajax({
    url: 'http://localhost:8002/jsonp.js',
    dataType: 'jsonp',
    jsonpCallback: 'callback',
    success: function(data){
        console.log(data)
    }
})
cors-服务器设置http header
js
//第二个参数填写允许跨域的域名称,不建议写 '*'
response.setHeader("Access-Control-Allow-Origin",'http://localhost:8011');
response.setHeader("Access-Control-Allow-Headers",'X-Requested-With');
response.setHeader("Access-Control-Allow-Methods",'PUT,POST,GET,DELETE,OPTIONS');
//接受跨域的cookie
response.setHeader("Access-Control-Allow-Credentials","true");

9-4 ajax 相关的面试题 - part1 (06:26)

题目
  • 手写一个简易的ajax
  • 跨域的常用实现方式
js
function ajax(url){
	const p = new Promise((resolve,reject)=>{
        const xhr = new XMLHttpRequest()
        xhr.open("GET",url,true)	// /data/test.json是请求地址 true是异步请求
		xhr.onreadystatechange = function(){	//监听返回结果
   		 //这里的函数异步执行,可参考之前js基础中的异步模块
  		  if(xhr.readyState === 4){
        		if(xhr.status === 200){
            	alert(xhr.responseText)
            	console.log(JSON.parse(xhr.responseText))	//将字符串转换为json对象
        	}else if(xhr.status === 404){console.log("404 not found")
        	}else{console.log("其他情况")
     		}
    	}//end function
         xhr.send(null);	//必须要写,不然没有请求
    })	//end promise
    return p 
}
//ajax使用                       
const url = '/data/test.json';
ajax(url)
.then(res=>console.log(res))
.catch(err=>console.log(err))
    

9-5 ajax 本章相关的面试题 - part2 (02:40)

跨域实现方式
  • jsonp
  • cors
知识点
  • XMLHttpRequest
  • 状态码: readyState status
  • 跨域:同源策略(如何绕过),JSONP,CROS

9-6 实际项目中 ajax 的常用插件 (05:58)

jquery的ajax
js
   $(function(){
        //请求参数
        var list = {};
        //
        $.ajax({
            //请求方式
            type : "POST",
            //请求的媒体类型
            contentType: "application/json;charset=UTF-8",
            //请求地址
            url : "http://127.0.0.1/admin/list/",
            //数据,json字符串
            data : JSON.stringify(list),
            //请求成功
            success : function(result) {
                console.log(result);
            },
            //请求失败,包含具体的错误信息
            error : function(e){
                console.log(e.status);
                console.log(e.responseText);
            }
        });
    });
//$(function(){ }是什么意思

$(function(){
// do something
});
等价于
$(document).ready(function(){
//do something
})
等价于
$().ready(function(){
//do something
})
这个就是jq ready()的方法就是Dom Ready,他的作用或者意义就是:在DOM加载完成后就可以可以对DOM进行操作。
一般情况先一个页面响应加载的顺序是:域名解析-加载html-加载js和css-加载图片等其他信息。
fetch

使用fetch

js
fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));
axios

使用文档

官网

js
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

第10章 JS-Web-API-存储【内容虽然不多,但不可不会】

本章介绍存储的知识点和题目。包括 cookie、localStorage 和 sessionStorage 。本章内容虽然不多,但不可不会。 共 2 节 (13分钟)

题目
  • 描述cookie localStorage sessionStorage区别

知识点

  • cookie
  • localStorage和sessionStorage
  • 本身用于浏览器和server通讯
  • 被借用到本地存储来
  • 可用document.cookie = '..'来修改
js
//在控制台上输入
console.log(document.cookie)  //返回cookie字符串 ""
document.cookie = 'a=100';
document.cookie = 'b=200';
document.cookie = 'a=300';//必须一个一个加cookie,否则会自动截取
console.log(document.cookie) //"b=200; a=300"
cookie的缺点
  • 存储大小,最大存储是4kb
  • http请求时需要发送到服务端,增加请求数据量
    • 本来cookie就是为了浏览器和server通讯,只不过是在h5以前没有本地存储方式,只能借用cookie来存储
  • 只能用document.cookie= "..."来修改,太简陋
  • HTML5专门为存储而设计的,最大可存5M
  • API简单易用setItem getItem
  • 不会随着http请求被发送出去
js
localStorage.setItem('a',100)
localStorage.getItem('a')
sessionStorage.setItem('b',200)
sessionStorage.getItem('b')

localStorage 和 sessionStorage

  • localStorage数据会永久存储,除非代码或手动删除
  • sessionStorage数据只存在于当前会话,浏览器关闭则清空
  • 一般用localStorage会更多一些
描述cookie localStorage sessionStorage区别
  • 容量
  • API易用性
  • 是否跟随http请求发送出去

第11章 http 面试题【前后端分离的时代,网络请求是前端的生命线】

前端工程师做出网页,需要通过网络请求向后端获取数据,因此 http 协议是前端面试的必考内容。本章讲解 http 协议常考的知识点,如状态码、header、method、缓存等。特别是 http 缓存策略,非常重要。共 10 节 (91分钟)

11-1 http的几个面试题 (04:22)

http的重要性
  • 前端工程师开发界面
  • 需要调用后端接口,提交/获取 数据--http协议
  • 要求事先掌握好ajax
题目
  • http常见状态码有哪些
  • http常见的header有哪些
  • 什么是Restful API
  • 描述一下http缓存机制(重要)

11-2 http常见的状态码有哪些(10:00)

知识点
  • 状态码分类
    • 1** 服务器收到请求
    • 2** 请求成功 如200
    • 3** 重定向 如302 这里不行,其他行
    • 4** 客户端错误 如404
    • 5** 服务端错误 如500
  • 常见的状态码
    • 200 成功
    • 301 永久重定向 配合location浏览器自动处理(不会再访问这个地址)
      • 如老域名到期了,永久重定向到新域名
    • 302 临时重定向 配合location浏览器自动处理
      • 短链接
      • 百度搜索
    • 304资源未被修改
      • 请求过了,再请求一遍缓存
    • 404资源未找到
    • 403没有权限
    • 500服务器错误
    • 504网关超时
      • 服务器内部问题
  • 关于协议和分类
    • 就是一个约定
    • 要求大家都跟着执行
    • 不要违反规范

11-3 什么是Restful-API (11:46)

http methods
  • 传统的methods
  • 现在的methods
  • Restful API
传统的methods
  • get 获取服务器的数据
  • post像服务器提交数据
  • 简单的网页功能,就这两个操作
现在的methods
  • get 获取数据
  • post 新建数据
  • patch/put 更新数据
  • delete删除数据
Restful API
  • 一种新的api设计方法(早已推广使用)
  • 传统api设计:把每个url当作一个功能
  • Restful API:吧每个url当做唯一的资源
如何设计成一个资源
  • 尽量不用url参数
    • 传统api设计: /api/list?pageIndex=2
    • Restful API设计: /api/list/2
  • 用method表示操作类型
    • 传统api设计
      • post请求 /api/create-blog
      • post请求 /api/updat-blog?id=100
      • get请求 /api/get-blog?id=200
    • Restful API设计
      • post请求 /api/blog
      • patch请求 /api/blog/100
      • get请求 /api/blog/100

11-4 http哪些常见header (12:54)

http headers(请求头和响应头)
  • 常见的Request Headers
  • 常见的Response Headers
  • 演示
Request Headers
  • Accept浏览器可以接受的数据格式
  • Accept-Encoding 浏览器可接受的压缩算法 如gzip
  • Accept-Languange 浏览器可接受的语言 如zh-CN
  • Connection: keep-alive 一次TPC连接可重复使用
  • cookie
  • HOST 请求的域名
  • User-Agent(简称 UA)浏览器信息
  • Content-type发送数据的格式,如application/json
Response Headers
  • Content-type 返回数据格式,如application/json
  • Content-length 返回数据大小 多少字节
  • Content-Encoding 返回数据的压缩算法 giz
  • Set-Cookie 服务端向客户端设置cookie
自定义header

axios可以在header的请求头上加自定义字段

json
headers: {'X-Requested-With': 'XMLHttpRequest'}
缓存相关的headers
  • Cache-Control Expires
  • Last-Modified If-Modified-Since
  • Etag If-None-Match

11-5 http为何需要缓存 (08:21)

http缓存
  • 关于缓存的介绍
  • http缓存策略(强制缓存+协商缓存)
  • 刷新操作方式,对缓存的影响
关于缓存
  • 什么是缓存
  • 为啥要缓存
    • 让请求尽可能减少,加速页面加载
  • 哪些资源可以被缓存? -静态资源 (js css img)
    • 使用webpack配置静态资源的文件名hash值为固定,可以达到缓存的作用

11-6 cache-control是什么意思-http强制缓存 (10:06)

cache-control的含义
  • 初次请求,服务器判断改资源可以被缓存(如css,js,img)Response Headers会带上一个Cache-Control
  • 在Response Headers中(由后端控制)
  • 控制强制缓存的逻辑
  • 例如Cache-Control:max-age=31536000 (单位是秒) 在客户端缓存时间一年
  • 在networks中看到请求的size为disk cache表明该请求是缓存
强制缓存

1653459617073

强制缓存成功状况

1653459695075

cache-control的值
  • max-age
    • 缓存最大过期时间
  • no-cache
    • 不用强制缓存,交給服务端,服务端怎么判断缓存不管
  • no-store(不常见)
    • 不用强制缓存,不让服务端做缓存
  • private
    • 最终用户做缓存
  • public
    • 中间的代理也可以做缓存
关于Expires
  • 同在Response Headers中
  • 同为控制缓存过期
  • 已被Cache-Control代替

11-7 Etag和Last-Modified是什么意思-http协商缓存 (15:27)

协商缓存(又称对比缓存)
  • 服务器端缓存策略
    • 服务端来判断一个资源是不是可以被缓存 但不是缓存在服务端,服务端收到请求可以直接返回客户端直接用缓存资源,就不请求了
    • 服务器判断客户端资源,是否和服务端资源一样
    • 一致则返回304,否则返回200和最新资源
资源标识
  • 在ResponseHeaders中,有两种
    • Last-Modified资源最后修改时间
    • Etag资源的唯一标识(一个字符串,类似人类的指纹)
Last-Modified

1653458610363

Etag

1653458664404

请求成功读取缓存

1653458816646

Last-Modified和Etag
  • 会优先使用Etag
  • Last-Modified只能精确到秒级
  • 如果资源重复生成,内容不变,则Etag更精确
http缓存流程图

1653458943243

11-8刷新页面对http缓存的影响 (05:00)

三种刷新操作
  • 正常操作:地址栏输入url,跳转链接,前进后退
  • 手动刷新:F5,点击刷新按钮,点击菜单刷新
  • 强制刷新:ctrl+F5
不同刷新操作,不同的缓存策略
  • 正常操作:强制缓存有效,协商缓存有效
  • 手动刷新:强制缓存失效,协商缓存有效
  • 强制操作:强制缓存失效,协商缓存失效
小结
  • 强制缓存Cache-Control
  • 协商缓存Last-Modified和Etag,304状态码
  • 完整流程图

14-9 http考点总结 (03:22)

第12章 开发环境

本章介绍开发环境相关的知识点和题目。包括 git ,调试工具,抓包工具,webpack 和 babel ,以及 linux 常用命令。熟练使用开发环境的各个工具,才能证明你真的做过前端开发,真的有项目经验,否则只能被认定为菜鸟小白。

12-1 前端开发常用的开发工具 (04:56)

12-2 什么是 git (05:40)

协助工具

12-3 git 的常用命令有哪些 (09:48)

提交

推送

拉取

先拉后推送

12-4 git 常用命令演示 (14:10)

冲突合并

12-5 如何用 chrome 调试 js 代码 (06:41)

打断点方式

  • 在源代码中输入debugger
  • 在sources中点击某行,多个断点可以按开始直接跳到下一个断点

12-6 移动端 h5 如何抓包网络请求 (09:57)

抓包

用chorme手机模式

移动端h5页,查看网络请求,需要用工具抓包,没有chorme那么方便,也可以

抓包工具
  • window

    • fiddle
    • wireshark
  • charlse

抓包作用

查看网络请求

网址代理(利用抓包工具实现)

https(不能用抓包工具直接看,因为是加密的,利用抓包工具的ssl proxying就可以)

抓包过程

手机和电脑连同一个局域网

将手机代理到电脑上

手机浏览网页,即可抓包

12-7 如何配置 webpack (17:23)

webpack和babel解决的问题

  • es6模块化,浏览器暂不支持
  • es6语法,浏览器不支持
  • 压缩代码,整合代码,以让网页加载更快
shell
npm init webpack-demo
npm i webpack webpack-cli -D

在文件中新建webpack.config.js

js
module.exports = {
    mode: 'development', // production 就可以压缩
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    }
}

在文件中package.json,新增build

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
  },

执行

shell
npm run build

下载插件

shell
npm i html-webpack-plugin -D
npm i webpack-dev-server -D

配置webpack.config.js的启动项目

js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'development', // production 就可以压缩
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'src', 'index.html'),  //找到模板
            filename: 'index.html'  //产出的文件名
        })
    ],
    devServer: {
        port: 3000,
        static: {
            directory: path.join(__dirname, 'dist'),
        },
        compress: true  //压缩
    }
}

新增package.json

json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "dev": "webpack-dev-server"
},

12-8 如何配置 babel (08:36)

为了转换es6

下载

shell
npm install @babel/core @babel/preset-env babel-loader -D

新建.babelrc

json
{
    "presets": ["@babel/preset-env"] //这是预先写好了许多babel的配置
}

12-9 ES6 模块化规范是什么 (07:11)

a.js 单个导出

js
export function fn(){
    console.log('fn')
}
export const name = 'a'
export const obj = {
    name: 'zhangsan'
}

b.js 一起导出

js
function fn(){
    console.log('fn')
}
const name = 'a'
const obj = {
    name: 'zhangsan'
}
//es5导出写法
export {
	fn:fn,
    name:name,
    obj:obj
}
//es6导出写法
export {
	fn,
    name,
    obj
}

c.js 只导出一个

js
写法1
export default {
    name : 'xxxx'
}

写法2
const obj = {
    name : 'xxx'
}
export default obj

index.js

js
import {fn ,name ,obj} from './a' //es6模块化解构赋值
import {fn ,name ,obj} from './b' //es6模块化解构赋值
import xxx from './c'
fn()
console.log(name)
console.log(obj)

12-10 如何配置 webpack 生产环境 (05:26)

新建webpack.prod.js

js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'production', 
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
        filename: 'bundle.[contenthash].js',    //根据代码内容做出文件名变不变
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [        //配置babel
            {
                test:/\.js$/,       //匹配规则
                loader: 'babel-loader',   
                include: path.join(__dirname,'src'),
                exclude: /node_modules/ 
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'src', 'index.html'),  //找到模板
            filename: 'index.html'  //产出的文件名
        })
    ],
    
}

配置package.json

json
"scripts": {
    "build2": "webpack --config webpack.prod.js",
  },

12-11 前端用到的 linux 常用命令有哪些 (16:28)

linux命令

  • 测试机,为了复现bug

登录测试机

shell
ssh work@192.168.10.21
ls			//查看文件
ls -a		//查看文件全部
ll 			//以列表的形式去看
clear		//清除屏幕
mkdir abc //创建文件夹
rm -rf abc //删除文件
cd dist //进入文件夹
mv index.html index1.html //修改文件名
mv index1.html ../   //移动到上级目录
cp a.js a1.js  //拷贝文件
rm a1.js //删除文件
touch 1.js //新建文件
vim d.js  //新建并用vim打开
输入 i 可以写入
输入esc
输入:wq 可保存退出
cat 1.js //输出内容
head 1.js	//输出开始内容
tail  1.js //输出末尾内容
grep "babel" package.json // 查找babel关键字在package.json中

12-12 开发环境的考点总结 (01:55)

第13章 运行环境

本章介绍运行环境相关的知识点和题目。包括浏览器加载和渲染机制,性能优化,web 安全。网页在浏览器加载和运行,这些内容必须掌握,也是面试常考。

13-1 JS 上线之后在什么哪里运行? (03:44)

运行环境

  • 浏览器中运行
  • server中也有nodejs运行

运行过程

下载网页代码,渲染出页面,执行js

保证代码在浏览器中

  • 稳定且高效

运行环境涉及到3个方面

  • 网页加载过程
  • 性能优化
  • 安全

13-2 网页是如何加载并渲染出来的 (09:46)

加载过程:

  1. dns解析:域名->ip地址
  2. 浏览器根据ip地址向服务器发起http请求
  3. 服务器处理http请求,并返回给浏览器

渲染过程1:

  1. 根据html代码生成dom tree
  2. 根据css代码生成cssom
  3. 将dom tree和csssom整合行程Render Tree

渲染过程2:

  1. 根据render tree渲染页面
  2. 遇到<script>则暂停渲染,优先加载并执行js代码,完成再继续
  3. 直至把Render Tree渲染完成

13-3 网页加载和渲染的示例 (07:32)

示例1:

当没有css时的html(直接渲染)

示例2:

有css的html(渲染dom后渲染cssom)

示例3:

有js的html(为什么会script停止渲染,因为js中可能存在修改dom的语句,要重新渲染)

建议:

<script>放在最后

示例4:

html中有img标签(直接渲染dom,再在之后渲染img标签)

window.onload和DOMContentLoaded的哪种方式好:

使用DOMContentLoaded是更好的选择

js
window.addEventListener('load',function(){
    //页面的全部资源加载完才会执行,包括图片,视频登
})
document.addEventListener('DOMContentLoaded',function(){
    //DOM渲染完即可执行,此时图片,视频还可能没有加载完
})

13-4 网页加载和渲染相关的面试题 (03:10)

  1. 从输入url到渲染出页面的整个过程

注意两个点:

  • 下载资源
    • 各个资源下载过程
  • 渲染页面
    • 结合html css js 图片等
  1. window.onload和DOMContentLoaded的区别

    window.onload资源全部加载完才能执行,包括图片

    DOMContentLoaded DOM渲染完成即可,图片可能尚未下载

13-5 前端性能优化有哪些方式 (11:52)

没有标准答案,但要求尽量全面

某些细节可能单独提问:手写防抖,节流

只关心核心点

性能优化原则
  • 多使用内存,缓存或其他方法
  • 减少cpu计算量,减少网络加载耗时
  • 用空间换时间
从何入手
  • 让加载更快
    • 减少资源体积:
      • 压缩代码
    • 减少访问次数:
      • 合并代码
      • SSR服务器端渲染
      • 缓存
    • 使用更快的网络
      • CDN
  • 让渲染更快
    • css放在header,js放在body最下面
    • 尽早开始执行js,用DOMContentLoaded触发
    • 懒加载(图片懒加载,上滑加载更多)
    • 对DOM查询进行缓存
    • 频繁DOM操作,合并到一起插入DOM结构
    • 节流throttle防抖debounce

13-6 前端性能优化的示例 (09:40)

资源合并(webpack的功能)

缓存(需要配置webpack,让文件名不变)

cdn

ssr:

  • ssr指的是服务器端渲染:将网页和数据一起加载,一起渲染.(技术原理就是先前的JSP ASP PHP,现在就是vue React SSR)
  • 非ssr(前后端分离):先加载网页,再加载数据,再渲染数据

懒加载:

html
<img id="img1" src="preview.png" data-realsrc="abc.png">
//一开始请求的是假的图片如缩略图,到了页面一定位置后再加载新的图片
<script>
    var img1 = document.getElementById('img1')
    img1.src = img1.getAttribute('data-realsrc')
</script>

缓存DOM查询:

js
//不缓存DOM查询结果
for(let i = 0; i < document.getElementsByTagName('p').length;i++){
    //每次循环,都会计算length,平法进行DOM查询
}
//缓存DOM查询结果
const pList = document.getElementsByTagName('p')
const length = pList.length
for(let i = 0; i < length; i++){
    //缓存length,只进行一次dom查询
}

多个dom操作一起插入都dom结构中

js
const listNode = document.getElementById('list')
//创建一个文档片段,此时还没有插入到DOM数中
const frag = document.createDocumentFragment()

//执行插入
for(let x = 0; x < 10; x++){
    const li = document.createElement("li")
    li.innerHTML = "List item " + x
    frag.appendChild(li)
}

//都完成后再插入DOM树
listNode.appendChild(frag)

尽早开始js执行

js
window.addEventListener('load',function(){
    //页面的全部资源加载完才会执行,包括图片,视频登
	js代码
})
document.addEventListener('DOMContentLoaded',function(){
    //DOM渲染完即可执行,此时图片,视频还可能没有加载完
    js代码
})

13-7 手写防抖 debounce (15:37)

指频发操作最后才触发

应用场景

  • 监听一个输入框,文字变化后触发change事件
  • 直接用keyup事件,则会频频触发change事件
  • 防抖:用户输入结束或暂停时,才会触发change事件

没有进行防抖的监听操作

js
const input1 = document.getElementById('input1')
input1.addEventListener('keyup',()=>{
        //模拟触发change事件
    	console.log(input1.value)
})

防抖的监听操作

js
const input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup',()=>{
    if(timer){
        clearTimeout(timer)
    }
    timer = setTimeout(()=>{
        //模拟触发change事件
    	console.log(input1.value)
        //清空定时器
        timer = null
    },500)
})

封装debounce 函数,可以让多个input使用

js
const input1 = document.getElementById('input1')
function debounce(fn,delay=500){
    //timer是在闭包中,这样就隐藏了,外部拿不到
    let timer = null
    return function(){
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(()=>{
            fn()//传入参数的情况下fn.apply(this,arguments)
            timer = null
        },delay)
    }
}
input.addEventListener('keyup',debounce(function(){
    console.log(input1.value)
}),600)

13-8 手写节流 throttle (11:25)

节流指频发操作保持一个频率连续触发

应用场景

  • 拖拽一个元素时,要随时拿到该元素被拖拽的位置
  • 直接用drag事件,则会频频触发,很容易导致卡顿
  • 节流:无论拖拽速度多快,都会每隔100ms触发一次

没有进行节流的拖拽

js
const div1 = documenet.getElementById('div1')

div1.addEventListener('drag',function(e){
        console.log(e.offsetX,e.offsetY)
})

进行节流的拖拽

js
const div1 = documenet.getElementById('div1')

let timer = null

div1.addEventListener('drag',function(e){
    if(timer)return //看timer是否有值,定时器是否启动
    timer = setTimeout(()=>{
        console.log(e.offsetX,e.offsetY)
        timer = null
    },500)
})

将节流封装成函数

js
const div1 = documenet.getElementById('div1')

let timer = null

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


div1.addEventListener('drag',throttle(function(e){
    console.log(e.offsetX, e.offsetY)	//此语句是传到throttle函数,参数要传到返回的函数中需要fn.apply(this,arguments)
}, 200) )

13-9 如何预防 xss 攻击 (06:54)

web安全常见的攻击
  • xss攻击
  • xsrf攻击
xss攻击原理

一个博客网站,嵌入script,获取cookie

js将获取到的cookie,发送到服务器(服务器配合跨域)

cookie中可能存账号密码

预防xss攻击

替换特殊字符,不让脚本执行

13-10 如何预防 xsrf 攻击 (03:49)

购物中,调用支付接口,xxxx.com/pay/id=200

发一个电子邮件,<img src="xxxx.com/pay/id=10">这样此时在登录状态就会直接购买了id=10的商品

预防:

  • 使用post接口
  • 增加验证

13-11 运行环境的考点总结 (01:47)