web面试宝典

前端常见的面试流程

一面(基础知识)

  • JS基础知识

  • 框架基本使用

二面(高级特性+原理)

  • 框架高级特性
  • 框架原理

三面(设计+经验)

  • 项目设计能力
  • 工作经验和环境

HTML

1.如何理解HTML语义化?

  • 让人更容易读懂(增加代码的可读性)
  • 让搜索引擎更容易读懂(SEO)

2. 块状元素&内联元素

  • display: block/table; 元素独占一行 (div,h1~6,table,ul,ol,p)
  • display:inline/inline-block; 元素不独占一行 (span,image,input,button)等

CSS

布局相关问题

  • 盒子模型宽度计算?
  • margin 纵向重叠的问题?
  • margin负值?
  • BFC 理解
  • float布局,以及clearfix
  • flex布局
1. 盒模型宽度的计算
<!-- 如下代码,请问 div1 的 offsetWidth 是多大? -->
#div1{
    width:100px;
    padding:10px;
    border: 1px solid #ccc;
    margin: 10px;
}

offsetWidth = width + padding-top/bottom + border-top/bottom = 100 + 10*2 +1*2 = 122px

// 如果让 offsetWidth = 100px 如何做?
box-sizing: border-box;
2. margin纵向重叠
  • 相邻元素的 margin-top 和 margin-bottom 会发生重叠
  • 空白内容的

    也会重叠
  • 下面代码的最终 margin = 15px
//  margin = 15px
p{
    font-size: 16px;
    line-height: 1;
    margin-top:10px;
    margin-bottom:15px;
}

<p>AAAAA</p>
<p>BBBBB</p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
3. margin 负值(<0的值)
  • 对margin的top,left,right,bootom设置负值,有何结果?
  • margin-top 和 margin-left 负值,元素向上、向左移动
  • margin-right 负值,右侧元素左移,自身不受影响
  • margin-bottom 负值,下方元素上移,自身不受影响
4. BFC理解应用?
  • BFC – Block format context 块级格式化上下文

  • 一块独立渲染区域,内部元素的渲染不会影响外界元素

形成 BFC 的常见条件
  • float 不是 none
  • position 是 absolute 或 fixed
  • overflow 不是 visible
  • display 是 flex inline-block等
用途
  • 清除浮动
5. float布局
  • 如何实现圣杯布局和双飞翼布局?

    • 圣杯布局和双飞翼布局目的

      • 三栏目布局:中间一栏最先加载和渲染(内容重要)
      • 两侧的内容固定,中间内容随着宽度自适应
      • 一般用于PC网页
    • 技术总结

      • 使用 float
      • 两侧使用 margin 负值,以便中间内容横向重叠
      • 防止中间内容被两侧覆盖,一个用padding 一个用margin
  • 手写 clearfix

    .clearfix:after{
        display:block;
        content:'';
        clear:both;
    }
    .clearfix{
      *zoom:1; // 兼容低版本
    }
    
6. flex布局
  • flex实现一个三点色子

    <!-- 父元素 -->
    flex-direction
    justify-content
    align-items
    flex-wrap
    
    <!-- 子元素 -->
    align-self
    
.box{
	display: flex;
	justify-content: space-between; /*两端对齐*/
}
.item{
    /*背景色、大小、边框*/
}
.item:nth-child(2){
    align-self: center; /*第二项居中对其*/
}
.item:nth-child(3){
	align-self: flex-end; /*第三项尾对齐*/
}

定位

1. absolute 和 relative 分别依据什么定位?
  • relative 依据自身定位
  • absolute 依据最近一层的定位元素定位
    • absulote relative fixed
    • body
2. 居中对其有哪些实现方式?
- 水平居中
  • inline 元素:

    text-align:center

  • block 元素:

    margin :auto

  • absolute 元素

    left:50% + margin-left 负值(必须知道子元素的尺寸)

- 垂直居中
  • inline 元素:

    line-height 的值等于 height

  • block 元素:

​ margin :auto

  • absolute 元素

    • top:50% + margin-top 子元素的一半负值 (必须知道子元素的尺寸)

    • 通过 transform(-50%,-50%) CSS3的属性(不知道子元素的宽高)

      top:50%;
      transform:translate(-50%,-50%)
      // 只写垂直方向的
      transform:translateY(-50%)
      
    • top,left,bootom,right = 0 + margin:auto (不需要知道子元素的宽高)浏览器兼容性好

图文样式

- line-height 如何继承?
  • 写具体数值,如 30px,则继承改值

  • 写比例,如 2/1.5, 则继承该比例

  • 百分比:

  • 子元素继承父元素的

    // P 标签的行高是 40px
    body{
    	font-size: 20px;
    	line-height: 200%;
    }
    p{
    	font-size: 16px;
    }
    
    <body>
     	<p>这是一行文字</p>
    </body>
    

响应式

rem是什么?

rem是一个长度单位。r 代表的是 root

  • px ,是绝对长度单位,最常用
  • em, 相对长度单位, 相对于父元素, 不常用
  • rem , 相对长队单位, 相对于根元素,常用语响应式布局
body{
	font-size: 100px;
}
p{
	font-size: 0.16rem; // = 16px
}
响应式布局的实现方案 – media?
  • media-query,根据不同的屏幕宽度设置根元素 font-size

  • rem, 基于根元素相对单位

// 一个项目一般只写一次
@media {}


## JS 

// 问题:

  • typeof能判断哪些类型?
  • 何时使用 === 何时使用 ==
  • window.onload 和 DOMContentLoaded的区别?
  • JS创建 10个a标签,点击的时候弹出对应的序号
  • 手写节流、防抖
  • Promise解决了什么问题?

// 思考问题的结论

  • 考点
  • 不变应万变(题不变,考点不变)
  • 题目到知识点,再到题目

### 知识模块一:基础知识

### 1. 变量类型和计算

>常见题目:
>
>- typeof能判断哪些类型?
>
>  值类型:number,undefinde,string,symbol,boolen,  [object,array,function]---object
>
>- 何时使用 === 何时使用 ==?
>
>  除了 null 和 undefined 外其它都有 ===
>
>- 值类型和引用类型的区别?
>
>  let obj1 = {x:100}
>
>  let obj2 = obj1
>
>  let x1 = obj1.x // 这块执行的是值类型的赋值
>
>  obj2.x = 101
>
>  x1 = 102
>
>  console.log(obj1)  // { x: 101 }
>
>- 手写深拷贝

#### 值类型 vs 引用类型

```js
// 值类型: undefined 、number、string、symbol、boolen
let a = 100
let b = a
a = 200
console.log(b) // 100

// 引用类型:array、object、null(特殊引用类型,指针指向空地址)、函数
let a = { age: 20}
let a = b
b.age = 21
console.log(a.age) // 21
判断 typeof 运算符
  • 识别出所有的值类型

  • 识别函数

  • 判断是否是引用类型(不可再细分)

type 判断所有的值类型( \ 函数 \ 引用类型 )
let atypeof aundefined
const str=‘abc’typeof strstring
const n = 100typeof nnumber
const b =truetypeof bboolean
const s = Symbol(‘a’)typeof ssymbol
typeof function() {}能识别引用类型但不能继续识别object
typeof null能识别引用类型但不能继续识别object
typeof [‘a’,‘b’]能识别引用类型但不能继续识别object
typeof {x:100}能识别引用类型但不能继续识别object
深拷贝
const obj = {
    age:20,
    address:{
        city:'beijing'
    },
    arr:['read','write']
}

const obj2 = obj1; // 浅拷贝

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

// 方法二
function deepClone2(arr){
    return JSON.parse(JSON.stringfy(arr))
}
变量计算 - 类型转换
  • 字符串拼接

    const a = 100 + 10 // 110
    const b = 100 + '10' // 10010
    const c = true + '10' // 'true10'
    
  • ==

    • 除了 == null | undefined之外,其它一律用 ===
    // 变量先转换再比较
    100 == '100' // true
    0 == '' //true
    0 == false //true
    false == '' //true
    null == undefined // true
    
  • if 语句和逻辑运算符

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

    • falsely 变量: !!b === false

    • 逻辑判断

      console.log(0 && 10) // 0
      console.log('abc' || '') // abc
      console.log(!window.abc) //true
      
    // 以下是 falsely 变量,其它都是truely 变量
    !!0 === false
    !!NaN === false
    !!‘’ === false
    !!null === false
    !!undefined === false
    !!false === false

2. 原型和原型链

ES5 的继承

题目:

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

    arr instanceof Array

  • class的原型本质,怎么理解?

    原型和原型链的图示

    属性和方法的执行规则

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

class JQuery {
    constructor(selector){
        const result = document.querySelectorAll(selector )
        const length = result.length
        for (let i = 0; i<length; i++){
            this[i] = result[i]
        }
        this.lenght = length
    }

    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(element=>{
            elem.addEventListener(type,fn,false)
        })
    }

}

// 插件
JQuery.prototype.dialog = function (info) {
    console.log(info)
}

// “造轮子”
class myJQuery extends JQuery{
    constructor(selector){
        super(selector)
    }

    // 扩展自己的方法
    addclass(classname){}

    style(data){}
}
class 实现继承
// class 和 class继承
class People {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat`)
    }
}

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, major) {
        super(name)
        this.major = major 
    }
    teach() {
        console.log(`姓名 ${this.name} 教授 ${this.major}`)
    }
}
instanceof 判断类型
  • Object 是默认所有类的父类
  • instanceof 是基于原型链的
xialuo instanceof Student // true
xialuo instanceof People // true
xialuo instanceof Object // true

[] instanceof Array  // true
[] instanceof Object // true 
{} instanceof Object // true
理解原型和原型链

《图示和使用规则》

  • 原型

    • 每个 class 都有显示原型 prototype
    • 每个实例都有隐式原型 __proto__
    • 实例的隐式原型 __proto__指向 每个类的显示原型 prototype
    xiaoming.__proto__ 
    Student.prototype
    console.log(xiaoming.__proto__  === Student.prototype) // true
    
  • 原型链

    • instanceof 是基于原型链的
    • hasOwnProperty()
    • object.__proto__ === null
    Student.prototype.__proto__
    People.prototype
    Student.prototype.__proto__ === People.prototype
    
重要提示!!!
  • class 是ES6语法规范,有ECMA委员会发布
  • ECMA只规定语法规则,即我们代码的书写规范,不确定如何实现
  • 以上实现方式都是V8引擎的实现方式,也是主流的

3. 作用域和闭包

题目

  • this 的不同应用场景,如何取值?

  • 手写 bind,返回一个新的函数。

    function fn(){}
    
    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) 
        }
    
    }
    
  • 实际开发中的闭包应用场景,举例说明

    • 作为参数
    • 作为函数返回值
    // 隐藏数据,只提供API
    // 简单做一个 cache的工具
    function  createCache(){
        const data = {}
        return {
            set:function(key,value){
                data[key] = value
            },
            get:function(key){
                return data[key]
            }
        }
    }
    
作用域和自由变量
  • 全局作用域

  • 函数作用域

  • 块级作用域(ES6新增 { })

    if(x){
        let x = 3
    }
    console.log(x) // 报错
    
let a = 0
function fn1(){
    let a1 = 1
    function fn2(){
        let a2 = 2
        function fn3(){
            let a3 = 3
            return a+a1+a2+a3;
        }
        fn3()
    }
    fn2()
}
fn1()
  • 自由变量
    • 一个变量在当前作用域没有定义,但是却被使用了
    • 向上级作用域,一层一层一次寻找,直到找到为止
    • 如果到全局作用域都没找到,则报错 xx is not defined
闭包

闭包–所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方

作用域应用的特殊情况,有两种表现:

  • 函数作为返回值

  • 函数作为参数

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

4. this的几种情况

this取什么值是在函数执行的时候确认的,不是在定义的时候确认的

  • 作为普通函数 : window
  • 使用 call \ apply \ bind
  • 作为对象方法被调用 :this 是对象
  • 在 class 方法中调用 : 实例本身
  • 箭头函数 : 自己本身不会有this的值,取它上级作用域的值
  • setTimeout 中指向 window
  • 原型中的 this: 有时会出现undefined , 因为会当做对象本身执行 xialuo.__proto__.sayHi() xialuo.__proto__会作为对象
function fn1(){
    console.log(this)
}

fn1()// window

fn1.call({x:100}) // {x:100}

const fn2 = fn1.bind({x:200}) 
fn2() // {x:200}  bind会返回一个新的函数再重新执行返回的函数

5. 异步和单线程

题目:

  • 同步和异步的区别是什么?

  • 手写 Promise 加载一张图片

    const url = ''
    function loadImg(src){
        const p = new Promise((resolve,reject)=>{
            const img = document.creteElement('img')
            img.onload =  ()=>{
                resolve(img)
            }
            img.onerror = ()=>{
                const err = new Error(`图片加载失败 ${src}`)
                reject(err)
            }
            img.src = src
           }
        )
        return p;
    }
    loadImg(url).then(img1=>{
        return img //返回普通对象
    }).then(img1=>{
        return loadImg(url2) // 返回 promise 
    }).then(img2=>{
        
    }).catch(err=>console.log(err))
    
  • 前端使用异步的场景有哪些?

    • 等待的场景:网络请求 & 定时任务
单线程和异步
  • JS是单线程语言,只能同时做一件事情
  • 浏览器和 nodejs 已支持 JS 启动进程,如 web worker
  • JS 和 DOM 渲染共用同一个线程,因为JS可以修改DOM结构
  • 遇到等待(网路请求,定时任务)不能卡住
    • 需要异步
    • 回调 callback 的形式
异步和同步
  • 基于JS是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行
异步在前端的使用场景
  • 网络请求,如 ajax图片加载

  • 定时任务,如 setTimeout

    // 网络请求
    console.log('start')
    $.get('./data.json',function(data){
        console.log('loaded')
    })
    console.log('end')
    
    // 图片加载
    console.log('start')
    let img = document.creteElement('img')
    img.onload = function (){
        console.log('loaded')
    }
    img.src = '/xxx.png'
    console.log('end')
    
    // 定时器
    setTimeout(function(){console.log(111)},1000)
    setInterval(function(){console.log(111)},1000)
    
callback hell 和 Promise
// callback hell
$.get(url1,(data1)=>{
    $.get(url2,(data2)=>{
        $.get(url3,(data3)=>{
        })
    })
})

// promise
function getData(){
    return new Promise((resove,reject)=>{
        $.ajax({
            url,
            success(data){
                resove()
            },
            error(err){
                reject(err)
            }
        })
    })
}
const url1 = '';
const url2 = '';
const url3 = '';
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))

知识模块二

  • JS基础知识,规定的是语法(ECMA 262 标准)
  • JS Web API ,网页操作的API(W3C标准)
  • 前者是后者的基础,两者结合才能真正实际应用

6. JS-Web-API-DOM / JS-Web-API-BOM

6-1 DOM

题目

  • DOM 是那种数据结构?

  • 常用 API

    • 节点操作
    • 结构操作
    • attr / property
  • attribute vs property

    • property :修改对象属性,不会体现到 html 结构中
    • attribute : 修改 html 属性,会改变 html 的结构
    • attributes 和 property 都可能影响DOM结构的重新渲染
    • 尽量使用 property

《Document Object Model》

  • vue 和 react 矿建应用广泛,封装了DOM操作
  • 但 DOM操作一直都是前端工程师的基础、必备知识
  • 只会vue而不懂DOM操作的前端程序员,不会太长久
DOM 本质
  • 前身 <?xml>
  • 一棵树
DOM 节点操作
  • attributes 和 property 都可能影响DOM结构的重新渲染

  • attribute: 修改 html 属性,会改变 html 的结构

    • p.getAttribute(‘data-name’)
    • p.setAttribute(‘data-name’,‘icmmo’)
  • property 形式:修改对象属性,不会体现到 html 结构中

    • nodeName
    • nodeType
    • style.[height|width]
    • className
  • 获取DOM节点

    • document.getElementById
    • document.getElementsByClassName // 集合
    • document.getElementsByTagName // 集合
    • document.querSelectorAll // 集合 |选择器
    • document.querySelector
DOM 结构操作

《DOM属于那种数据结构》

  • 新增、插入 节点

  • 获取子节点列表,获取父节点

  • 删除子节点

    // 新增、插入
    const div1 = document.getElementById('div1')
    const p1 = document.createElement('p')
    div1.appendChild(p1)
    
    // 对现有节点重新插入的话,会移动
    const div2 = document.getElementById('div2')
    const p1 = document.getElementById('p1')
    div2.appendChild(p1)
    
    p1.parentNode
    
    const div1ChildNodes = div1.childNodes
    const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child=>{
       if(child.nodeType === 1) return true
       return false
    })
    
    // 删除
    div1.removeChild(div1ChildNodesP[0])
    
DOM 性能操作的性能优化
  • DOM 操作非常 ”昂贵“, 避免频繁操作 DOM 操作

  • 对 DOM 查询做缓存

  • 将频繁操作改为一次性操作

    // 创建一个文档片段,此时还没有插入到 DOM 树中
    const frag = document.createDocumentFrgment()
    
6-2 BOM

题目

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

Browser Object Model

navigator 浏览器信息
  • userAgent 查看当前浏览器的信息 , 简称 ua
screen 屏幕
  • width
  • height
location 地址
  • location.href
  • location.protocol
  • localtion.host
  • location.search
  • location.hash # 后面内容
  • location.pathname
history
  • history.back()
  • history.forward()

8. JS-Web-API-事件

题目:

  • 编写一个通用的事件监听函数

    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)){
                    fn.call(target, event)
                }
            }else{
                // 普通绑定
                fn.call(target, event)
            }
        })
    }
    
    
  • 描述事件冒泡的流程

    • 基于DOM树形结构

    • 事件会顺着触发元素网上冒泡

    • 应用场景:代理

  • 无限下拉的图片列表,如何监听每个图片的点击?

    • 事件代理
    • 用 e.target 获取触发元素
    • 用 matche 来判断是否触发元素
事件绑定
// 通用绑定事件绑定函数
function bindEvent( elem, type,fn){
    elem.addEventListener(type,fn)
}

const btn = document.getElementById('btn1')
bindEvent(btn,'click', function(event){
    console.log(event.target) // 获取触发的元素
    event.preventDefault() // 阻止默认行为; eg: a 标签的跳转事件
    event.stopPropagation() // 阻止事件冒泡
    alert('click')
})
事件冒泡
event.preventDefault()
event.stopPropagation()
// 冒泡机制
事件代理

事件代理是在事件冒泡的基础上做的

  • 代码简洁
  • 减少浏览器内存占用
  • 只在父元素上挂事件
  • 但是,不要滥用;(瀑布流式的结构)
<div id="div3">
    <a href="#">A</a>
    <a href="#">B</a>
    <a href="#">C</a>
    <a href="#">D</a>
</div>

const div3 = document.getElementById('div3')
bindEvent(div3,'click', function(event){
    event.preventDefault()
    alert(this.innerHTML)
})

9. JS-Web-Ajax

题目

  • 手写一个简易的 ajax

    function ajax(url){
        const p = new Promise((resolve,reject)=>{
            const xhr = new XMLHTTPRequest()
            xhr.open('GET','/api/test.json',true)
            xhr.onreadystatechange = function(){
                if(xhr.readystate === 4){
                    if(xhr.state === 200){
                       resolve(JSON.parse(xhr.responseText))
                    }
                } else if(xhr.state === 404){
                      reject(new Error(`404 not found`)) 
                }
            }
            xhr.send(null)
        })
        return p
    }
    
  • 跨域的常用实现方式

    • JSONP
    • CORS 单纯的服务端实现
XMLHttpRequest
  • xhr.readyState
    • 0 - UNSET 尚未调用 open
    • 1- OPENED open 已经被调用
    • 2 - HEADERS_RECEIVED send 方法已经被调用,header 已被接收
    • 3 - LOADING 下载中,responsText 已经有部分内容
    • 4 - DONE 下载完成
  • xhr.state http协议的状态码
// get  请求
const xhr = new XMLHttpRequest()
xhr.open("GET","/api",true)  // true 是异步的请求
xhr.onreadystatechange = function(){
    // 这里的函数异步执行,可参考之前 JS 基础中的异步模块
    if(xhr.readyState === 4){
       if(xhr.status === 200){
         alert(xhr.responseText)
       }
     }
}
xhr.send(null)

// post 
const xhr = new XMLHttpRequest()
xhr.open("POST","/login",true)  // true 是异步的请求
xhr.onreadystatechange = function(){
    // 这里的函数异步执行,可参考之前 JS 基础中的异步模块
    if(xhr.readyState === 4){
       if(xhr.status === 200){
         alert(xhr.responseText)
       }
     }
}
const postData = {
    name:'xxx',
    age:1
}
xhr.send(JSON.stringify(postData)) // 转换成 字符串发送
状态码
  • 2xx 表示成功处理请求
  • 3xx 重定向;
    • 301 永久重定向
    • 302 临时重定向
    • 304 资源未改变,浏览器用缓存的内容
  • 4xx 客户端请求错误
    • 404 地址不存在
    • 403 没有权限
  • 5xx 服务端错误
同源策略和跨域
什么是跨域(同源策略)?
  • ajax 请求时,浏览器要求当前网页和 server 必须同源(安全)

  • 同源:协议、域名、端口,三者必须一致

    • 防盗链限制是服务器做的

    • 加载 css js 可无视同源策略

      <img src=跨域的图片地址/>

      <link src=跨域的css地址/>

      <script src=跨域的js地址></script>

      • <img/>图片可用于统计打点,可使用第三方统计服务
      • <link/><script>可以使用CDN,CDN一般都是外域
      • <script>可实现JSONP
  • 跨域

    • 所有的跨域,都必须经过 server 端的允许和配合
    • 未经 server 端允许就实现跨域,说明浏览器有漏洞,危险新号
JSONP
  • 访问 https://xx.com ,服务端一定会返回一个 html 吗?

    服务端可以任意动态拼接数据返回,只要复合 html 格式要求

  • 同理 <script src="https://xxxxx/getData.js"> 只要符合js的格式就可以

  • 实现原理

    • <script> 可以绕过跨域
    • 服务器可以任意动态凭借数据返回
    • 所以,<script>就可以获得跨域数据,只要服务端愿意返回就可以
    <script>
    window.callback = function(data){
        console.log(data)
    }
    </script>
    <script src = "https://xxxx.com/getData.js?username=xxx&callback=callback"></script>
    <!-- 将返回 callback({x:1,y:2}) -->
    
  • Jquery 封装的使用示例

    $.ajax({
    	url:'http://xxxx:8080/x-origin.json',
    	dataType:'jsonp',
    	jsonpCallback:'callback',
    	success:function(data){
    		console.log(data)
    	}
    })
    
CORS – 服务器端设置 http header
// 第二个参数是允许跨域的于名称,不建议直接写“*”
res.setHeader("Access-Control-Allow-Origin", '*' ) // 允许所有跨域网站的响应值
res.setHeader("Access-Control-Allow-Origin", 'www.baidu.com' ) // 跨域网站中仅允许baidu返回的响应者
res.setHeader("Access-Control-Allow-Headers", 'Content-Type, X-Custom-Header' ) // 允许所有跨域网站的响应值
res.setHeader("Access-Control-Allow-Methods", 'POST, GET, HEAD, DELETE' ) // 允许这四个方法
res.setHeader("Access-Control-Allow-Methods", '*' ) // 允许所有方法

// 接收跨域的cookie
res.setHeader("Access-Control-Allow-Credentials", 'true' ) 
ajax常用的插件
  • jquery

    $ajax({
        type:'',
        contentType:'',
        url:'',
        data:'',
        success:function(){},
        error:function(){}
    })
    
  • fetch 新的api

    • fetch(),返回的 Promise不会被标记为 reject
    • fetch(), 不会从服务端发送或接收任何 cookies
    fetch(url,{})
    .then()
    .then()
    .catch(e=>{})
    
  • axios 支持 browers and nodejs

    • support promise

10. 存储

题目:描述 cookie、localStorage、vs sessionStorge

  • 容量

  • 易用性

  • 是否跟随 http 发送

Cookie
  • 本身用于浏览器和server通讯
  • 被 ”借用“ 到本地存储
  • 存储最大是 4kb
  • http 请求时候需要发送到服务端,增加请求数据量
  • 只能用 document.cookie = ‘ ’ 来修改
localStorage && SessionStorage
  • HTML5专门为存储设计,最大存储5M

  • API 简单易用 getItem \ setItem

  • 不会随着 http 发送到服务器

  • 差异

    • localStorage 数据会永久存储,除非代码或手动删除
    • sessionStorage 数据只存储于当前会话,浏览器关闭则清空
    • localStorage 用的多一些

11. 节流防抖

  • applay 的应用
手写节流 throttle
  • 拖拽一个元素时,要随时拿到该元素被拖拽的位置

  • 直接用 drag 事件,则会频繁触发,很容易导致卡顿

  • 节流:无论拖拽速度多快,都会每隔 100ms 触发一次

const div1 = document.getElementById('div1')
let timer = null
div1.addEventListener('drag', function(e){
    if(timer){
        return
    }
    timer = setTimeout(()=>{
        console.log(offset.X,offset.Y)
        // 清空定时器
        timer = null
    },100)
})

// 节流
function throttle(fn, delay = 500){
    let timer = null
    
    return function(){
        if(timer){
        	return
        }
        timer = setTimeout(()=>{
            fn.apply(this,arguments)
            timer = null
        },delay)
    }
}
div1.addEventListener('drag', throttle(function(e){
    console.log(e.offsetX,e.offsetY)
},200))
手写防抖 debounce
  • 监听一个输入框,文字变化后触发 change 事件
  • 直接用 keyup事件,会频繁触发 change 事件
  • 防抖:用户输入结束或暂停时,才会触发 change 事件
const input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup', function(){
    if(timer){
        clearTimeOut(timer)
    }
    timer = setTimeout(()=>{
        // 模拟触发 change 事件
        console.log(input1.value)
       
        // 清空定时器
        timer = null
    },500)
})

// 防抖
function debounce(fn, delay = 500){
    // timer 在闭包中
    let timer = null
    return function(){
        if(timer){
            clearTimeOut(timer)
        }
        timer = setTimeout(()=>{
            fn.apply(this,arguments)
            timer = null
    	},delay)
    }
}
input1.addEventListener('keyup',debounce(function(e){
    console.log(e.target)
    console.log(input1.value)
}),600)          

框架

Vue 面试题

  • v-show 和 v-if 的区别?

    答:v-show 是通过 css 来控制, v-if 通过vue 本身的机制实现组件动态显示和销毁

    ​ 组件频繁切换用 v-show, 切换一次后不频繁切换使用

    ​ keep-alive 的区别 — 缓存,不会走到 destory 生命周期函数去销毁重新渲染

  • 为何 v-for 中要用 key?

    答:

  • 描述 Vue 组件生命周期(有父子组件的情况)

    答: 单组件 — 生命周期(创建、更新、销毁)

    ​ 父子组件 —

  • Vue 组件如何通讯

    答: 父子组件 :属性和$emit触发

    ​ 组件之间 :触发事件的方式 event. o n ( ) e v e n t . on() event. on()event.emit() event.$off()

    ​ vuex的方式

  • 描述组件渲染和更新的过程

  • 双向数据绑定 v-model 的实现原理

React 面试题

  • React 组件如何通讯
  • JSX 本质是什么
  • context 是什么,有何用途?
  • shouldComponentUpdate 的用途:性能优化
  • 描述 redux 单项数据流
  • setState 是同步还是异步?

框架综合应用

  • 基于 React 设计一个 todolist (组件结构,redux state 数据结构)
  • 基于 Vue 设计一个购物车(组件结构, vuesx state 数据结构)

wevpack 面试题

  • 前端代码为何要进行构建和打包?
  • module chunk bundle 分别什么意思?有何区别?
  • loader 和 plugin 区别?
  • webpack 如何实现懒加载?
  • webpack 常见性能优化
  • babel-runtime 和 babel-polyfill 的区别

如何应对?

  • 框架的使用(基本使用,高级特性,周边插件)
  • 框架原理(基本原理的了解,热门技术的深度,全面性)
  • 框架的实际应用,即设计能力(组件结构,数据结构)

1. Vue

先学vue2再学vue3
  • vue2还会被继续使用,面试还会继续考察

  • vue2的语法,绝大部分会被vue3支持

  • Vue和React越来越接近

    • Vue3 Options API 对应 React class Component
    • Vue3 Composition API 对应 React Hooks
Vue使用 - 知识点
  • 基本组件使用,组件使用 – 常用,必须会
  • 高级特性 – 不常用,但是体现深度
  • Vuex 和 Vue-router 的使用

自己看文档:

  • 行。但是是一种低效方式
  • 文档是一个备忘录,给会用的人查阅,并不是入门教程
  • 文档全面冗长,细节过多,不能突出考试重点
Vue 基本使用 - 知识点
1. 自己用 vue-cli 创建项目
$vue create project-name
$
2. 指令、插值
  • 插值、表达式

  • 指令、动态属性

  • v-html: 会有xss 风险, 会覆盖子组件

    <template>
    	<p>文本插值:{{message}}</p>
    	<p>
            JS 表达式 {{ flag? 'yes':'no'}} (只能是表达式,不能是js语法)
        </p>
    	<p :id="dynamicId">
            动态属性
        </p>
    	<p v-html="rawHtml">
            <span>有xss风险</span>
            <span>【注意】使用 v-html 之后,将会覆盖子元素</span>     
        </p>
    	
    </template>
    <script>
    export default {
        data() {
            return {
                message:'ssd',
                flag: true,
                rawHtml: '指令- 原始 html <b>加粗</b><i>斜体</i>',
                dynamicId: `id-${Date.now()}`
            }
        }
    }
    </script>
    
3. computed 和 watch
  • computed 有缓存,data不变则不会重新计算

    <template>
    	<p>
            num:{{num}}
        </p>
    	<p>
            double1 {{double1}}
        </p>
    	<input v-modle="double2"/>
    </template>
    <script>
        export default {
            data() {
                return {
                    num: 20
                }
            },
            computed: {
                double1() {
                    return this.num*2;
                },
                double2() {
                    get() {
                        return this.num*2;
                    },
                    set(val) {
                        this.num = val/2;
                    }    
                }
            }
        }
    </script>
    
  • watch 如何深度监听?

  • watch 监听引用类型,拿不到 oldValue !!!

    <template>
    	<p>name:{{name}}</p>
    	<div>
            <input v-module="name"/>
            <input v-module="info.city"/>
        </div>
    </template>
    <script>
        export default{
            date(){
                name:'xxx',
                info:{
                    city:'北京'
                }    
            },
            watch:{
                name(val,oldVal){
                    console.log('watch name', oldVal, val) // 值类型,可以正常拿到 oldVal和 val
                },
                info:{
                    handler(oldValue, val){
                        console.log('watch info', oldVal, val)// 引用类型,拿不到 oldVal。因为指针相同,但是已经指向了新的 val
                    },
                    deep:true // 深度监听
                }
            }
        }
    </script>
    
4. class 和style
  • 使用动态属性

  • 使用驼峰写法

    <template>
    	<p :class="{black:isBlack, yellow:isYellow}">
            使用class类
        </p>
    	<p :class="[black,yellow]">
            使用class数组
        </p>
        <p :style="styleData">
            使用class类
        </p>
    </template>
    <script>
    export default{
        data() {
            return {
                isBlack: true,
                isYellow: true,
                
                black: 'black',
                yellow: 'yellow',
                
                styleData: {
                    fontSize: '40px', //转换驼峰写法
                    color: 'red',
                    backgroundColor:'#ccc' //转换驼峰写法
                }
            }
        }
    }
    </script>
    
5. 条件渲染
  • v-if \ v-else-if \ v-else 的用法,可使用变量,也可以使用 === 表达式

  • v-if 和 v-show 的区别

  • v-if 和 v-show 的使用场景

    • v-if 判断DOM节点中不渲染

    • v-show DOM 节点中渲染只是不显示

    • v-if 更新的不频繁

    • v-show 切换的比较频繁

    <template>
    	<div>
            <p v-if="type === 'a'">A</p>
            <p v-else-if="type === 'b'">B</p>
            <p v-else>other</p>
            
            <p v-show="type === 'a'"> A by v-show</p>
            <p v-show="type === 'b'"> B by v-show </p>
        </div>
    </template>
    <script>
    export default{
        data() {
            return {
                type: 'a'
            }
        }
    }
    </script>
    
6. 循环(列表)渲染
  • 如何遍历对象?----- 也可使用 v-for

  • key 的重要性。key 不能乱写(如random或者index)

    • 与业务相关的一个值
    • key是v-for里边的唯一标识,key可以标识组件的唯一性,为了更好的区别各个组件,key的作用主要是为了高效的更新虚拟DOM
  • v-for 和 v-if 不能一起使用!!!

    <template>
    	<div>
            <ul>
                <li v-for="(item,index) in listArr" :key="item.id">{{index}} - {{item.id}} - {{item.title}}</li>
                <li v-for="(val,index,key) in listObj" :key="key">{{index}} - {{key}} - {{val.title}} </li>
        	</ul>
        </div>
    </template>
    <script>
    export default{
        data() {
            return {
                listArr: [
                    {id:'a',title:'标题1'},
                    {id:'b',title:'标题2'},
                ],
                listObj: {
                    a:{title:'标题1'},
                    b:{title:'标题2'},
                }
            }
        }
    }
    </script>
    
7. 事件
  • event 参数,自定义参数

    • event 是原生的
    • 事件被挂在到当前元素
  • 事件修饰符,按键修饰符

    <!-- 事件修饰符 -->
    <!-- 阻止事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThis"></a>
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    <!-- 添加事件监听器时使用的事件捕获模式 -->
    <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">
        ...
    </div>
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">
        ...
    </div>
    
    <!-- 按键修饰符 -->
    <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
    <button @click.ctrl="onClick"> A</button>
    
    <!-- 有且只有 Ctrl 被按下的时候才触发 -->
    <button @click.ctrl.exact="onCtrlClick"> A</button>
    
    <!-- 没有任何系统修饰符被按下的时候才触发 -->
    <button @click.exact="onClick"> A</button>
    
    
    
  • 【观察】事件被绑定到哪里 ?

    <template>
    	<div>
          <p>{{num}}</p>
          <button @click="increment1">+1</button>
          <button @click="increment2(2,$event)">+2</button>
        </div>
    </template>
    <script>
    export default{
        data() {
            return {
                num:0
            }
        },
        methods: {
        	increment1($event){
        		console.log('event', event, event.__proto__.constructor) // MouseEvent 是原生的event 对象    				console.log(event.target) // 
        		console.log(event.currentTarget) // 注意,事件
        		this.num++
        	},
        	increment2(val,str,event){
        		console.log(event.target)
        		this.num = this.num + val
        	},
        	loadHandler() {
        		// do some thing
        	}
        }
    }
    </script>
    
8. 表单
  • v-model
  • 常见表单项 textarea checkbox radio select
  • 修饰符 lazy number trim
Vue 组件使用 - 知识点
1. 组件间的通讯
props 和 $emit (父子组件)
  • 父传递给子

    父组件通过一个属性传递到子组件,子组件这定义 props 接收

  • 子传递给父

    父亲组件定义事件 : @事件名称

    子组件触发事件 : this.$emit(‘事件名称’,参数)

    父 – 子 : 传递一个事件

    子 – 父 : 触发一个信息

自定义事件(兄弟组件)
  • 创建自定义事件实例: component / event.js 导出vue的一个实例
  • event.$on(‘事件名称’,事件方法) // 绑定自定义事件
  • event.$emit(‘事件名称’,参数) // 触发自定义事件
  • event.$off(‘事件名称’,事件方法)// 销毁自定义事件,防止内存泄漏
<!--- component event.js --->
import Vue from 'vue';
export default new Vue();

<!--- child1 --->
import event from 'event.js';
event.$emit('事件名称',参数) //来触发一个事件

<!--- child2 --->
import event from 'event.js';
event.$on('事件名称',方法);

beforeDestory() {
	event.$off('事件名称',方法)
}
2. 组件生命周期
生命周期(单个组件)
  • 挂载阶段 created / mounted

  • 更新阶段 update

  • 销毁阶段 destroy

    • 解除绑定、销毁子组件以及事件监听
  • created VS mounted

    • created 生成变量,页面并未渲染,但是 vue 的初始化已经完成
    • mounted 页面渲染已经完成
生命周期(父子组件)
  • created 创建由外向内(父 – 子)
  • mounted 渲染由内像外(子 – 父)
Vue 高级特性
  • 不是每一个都很常用,但是用到的时候必须知道
1. 自定义 v-model
<template>
	<input type="text"
           :value = "text1"
           @input="$emit('change',$event.target.value)"
    <!--- 
		1. 上面的 input 使用了 :value 而不是 v-model ;
		2. 上面的 change 和 model.event 要对应起来;
		3. text1 属性对饮起来
	--->
</template>
<script>
export default {
    model: {
        prop: 'text1', // 对应 props text
        event: 'change'
    },
    props: {
        text1: String,
        default(){
            return ''
        }
    }
}
</script>

<!--- 使用 --->
<CustomInput :text1="name"/>
2. $nextTick and refs
  • $nextTick

    • vue 是异步渲染
    • data 改变之后,DOM 不会立刻渲染
    • $nextTick 会在 DOM 渲染之后触发,以获取最新的DOM 节点
  • refs

    • 获取DOM元素
    <template>
    	<div>
            <ul ref='ul1'>
                <li v-for="(item,index) in list" :key="index">{{item}}</li>
        	</ul>
            <button @click="addItem">添加一项</button>
        </div>
    </template>
    <script>
        export default{
            name:'app',
            data() {
                return {
                    list: ['a','b','c','d']
                }
            },
            methods:{
                addItem() {
                    this.list.push(`${Date.now()}`)
                    this.list.push(`${Date.now()}`)
                    this.list.push(`${Date.now()}`)
                    
                    // 1. 异步渲染,$nextTick 待 DOM 渲染完再回调
                    // 3. 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
                    this.$nextTick(()=>{
                        // 获取 DOM 元素
                    	const ulElem = this.$refs.ul1 
                    	console.log(ulElem.childNodes.length)
                    })
                    
                }
            }
        }
    </script>
    
3. slot 插槽
  • 基本使用: 让父组件给子组件传递一段内容

  • 作用域插槽:ScopedSlot

    <!-- 子定义 -->
    <a :href="url">
    	<slot :slotData="website">{{website.subTitle}}</slot>
    </a>
    
    <!-- 父使用 -->
    <ScopedSlotDemo :url="website.url">
        <template v-slot="slotProps">
    		{{slotProps.slotData.title}}
        </template>
    </ScopedSlotDemo>
    
  • 具名插槽

    <!-- 子定义 -->
    <div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    </div>
    
    
    <!-- 父使用 -->
    <NamedSlot>
        <!-- 缩写 <template #header> -->
        <template v-slot:header></template>
        <p>
            将 插入到main slot 中,即未命名的slot
        </p>
        <template v-slot:footer></template>
    
    </NamedSlot>
    
<template>
	<div>
        <a :href="url">
            <slot>默认内容,即父组件没设置内容时,这里显示</slot>
    	</a>
    </div>
</template>
<script>
    export default{
        props:['url'],
        data() {
            return {}
        }
    }
</script>

<!-- ScopedSlot.vue -->
<template>
	<div>
        <a :href="url">
            <slot :slotData="website">{{website.subTitle}}</slot>
    	</a>
    </div>
</template>
<script>
    export default{
        props:['url'],
        data() {
            return {
                website: {
                    url:'',
                    title:'儿子scoped',
                    subTitle:'er2'
                }
            }
        }
    }
</script>

<!-- UseSlot -->
<template>
	<div>
        <SlotDemo :url="website.url">
    		{{website.url}}
    	</SlotDemo>
        
        <ScopedSlotDemo :url="website.url">
            <template v-slot="slotProps">
                {{slotProps.slotData.title}}
        	</template>
        </ScopedSlotDemo>
    </div>
</template>
<script>
    import SlotDemo from './SlotDemo'
    export default{
        name:'app',
        compontents:{
            'SlotDemo',
            'ScopedSlotDemo'
        },
        data() {
            return {
                name:'',
                website: {
                    url:'',
                    title:'父亲',
                    subTitle:''
                }
            }
        }
    }
</script>
4. 动态、异步组件
4-1 动态组件
  • 根据数据,动态渲染的场景。即组件类型不确定

  • :is=“component-name” 用法

    <component :is="NextTickName"></component>

4-2 异步组件(性能优化)
  • import() 函数

  • 按需加载,异步加载大组件

    <script>
    export default{
        components: {
            FormData : import('../BaseUse/FormDemo')
        }
    }
    </script>
    
5. keep-alive (缓存组件)(性能优化)
  • 缓存组件:频繁切换,不要重复渲染

    • destroyed 不会走到
  • Vue 常见的性能优化

  • keep-alive 在 vue层级控制的,v-if 是原生的js控制的

    <template>
    	<keep-alive>
            <KeepAliveStageA v-if="state===A"/>
            <KeepAliveStageB v-if="state===B"/>
            <KeepAliveStageC v-if="state===C"/>
        </keep-alive>
    </template>
    <script>
        export default {
            data(){
                return {
                    state:'A'
                }
            },
            mounted(){},
            destroyed(){}
        }
    </script>
    
    
6. mixin
  • 多个组件有相同的逻辑,抽离出来

  • minx并不是完美的解决方案,会有一些问题

    • 来源不明确,不利于阅读
    • 多个mixin会照成命名冲突(data/method); mounted 是个生命周期的东西所以不会冲突
    • mixin组件可能会出现多对多的关系,复杂度比较高
  • Vue3提出的CompositionAPI旨在解决这些问题

    <!-- mixin.js -->
    export default{
        data(){
            return {
                city:'北京'
            }
        },
        methods:{
            showName(){
            	console.log(this.name)
            }
        },
        mounted(){
        	console.log('mixin mounted',this.name)
        }
    }
    
    <!-- MixinDemo -->
    <template>
    	<h1>
            {{city}}
        </h1>
    	<button @click="showName">
            打印
        </button>
    </template>
              
    <script>
        import myMixin from './mixin'
        export default{
           mixins:[myMixin], // 可以添加多个,会自动合并起来
           data(){
                return {
                    name:'',
                    major:''
                }
            },
            methods:{},
            mounted(){
                console.log('comm',this.name)
            }
        }
    </script>
    
vuex 知识点串讲
  • 面试考点并不多(熟悉了vue之后,vuex没有难度)
  • 但是基本概念、基本使用和API 必须掌握
  • 可能会考察 state 的数据结构
  • state
  • getters
  • action
  • mutation
  • 用于 Vue 组件
    • dispatch
    • commit
    • mapState
    • mapGetters
    • mapActions
    • mapMutations
vue-router 知识点串讲
  • 官网 : router.vuejs.org/zh/guid/

  • 路由模式(hash, H5 history)

    • hash模式(默认模式) http://abc.com/#/user/10
    • H5 history 模式 http://abc.com/user/10 (需要server端支持,因此无需特需原因用 hash 的默认模式)
  • 路由配置(动态路由、懒加载)

    const router = new VueRouter({
    	routes: [
    		// 动态路径参数 以:开头,能命中 ‘user/10’ ‘user/2’ 等格式的路由
    		{path:'/user/:id',component:User},
    		{path:'',component:()=>import() // 懒加载}
    	]
    })
    
Vue 原理
  • 面试为何会考察原理?知其然知其所以然;了解原理,才能应用更好;大厂造轮子(技术KPI)
  • 面试中如何考察?以何种方式?
    • 考察重点,而不是考察细节
    • 和使用相关的原理,如 vdom、模板渲染
    • 整体流程是否全面?热门技术是否有深度?
  • Vue原理包括哪些?
    • 组件化
    • 响应式
    • vdom 和 diff
    • 模板编译
    • 渲染过程
    • 前端路由
** 组件化基础 — Vue MVVM **
1. 很久以前的组件化

​ jsp,php…

​ 只是静态渲染

2. 数据驱动视图(MVVM,setState)
  • 传统组件,只是静态渲染,更新还要依赖于操作DOM

  • 数据驱动视图 — Vue MVVM (Model ViewModel View)

    • ViewModel 是一个链接层,如 view 修改 model
  • 数据驱动视图 — React setState

** Vue 响应式 **
  • 组件 data 的数据一旦变化,就会立刻触发视图的更新
  • 实现数据驱动视图的第一步

核心API - Object.defineProperty

  • 如何实现?

  • Object.defineProperty 的一些缺点(Vue 3.0 启用 Proxy:Proxy 有兼容性问题,无法用 polyfill)

const data = {}
const name = ‘zhangsan’
Object.defineProperty(data,“name”, {
get: function(){
return name
},
set: function(newVal){
value = newVal
}
})


<font color=red><b>深度监听data变化</b></font>

- 深度监听,需要递归到底,一次性计算量大
- 新增属性/删除属性,监听不到(所以需要 Vue.set  Vue.delete)
- defineProperty 无法监听数组

```js
// 重新定义数组的原型
const oldArrayProperty = Array.prototype
const arrProto = 

function defineReactive(target, key, value){
  // 深度监听
  observe()
  
  Object.defineProperty( target, key, {
      get: function(){
          return value
      },
      set: function(newVal){
          value = newVal
          
          updateView() // 触发更新
      }
  })
}

function observe(target){
  if(typeof target!= 'object' || target === null) {
  	return target   
  }
  
  // 重新定义各属性
  for(let key in target){
      defineReactive(target, key, target[key])
  }
}

function updateView(){
  console.log("视图更新")
}

const data = {
  name:'zhangsan',
  age:21,
  info:{
      city:'北京'
  },
  nums : [2,3,5]
}

observe(data)
data.name = 'lisi'
data.info.city = 'shanhai'

** 虚拟 DOM**

2. React

React 基本使用
React 高级特性
React 原理

3. webpack和babel

Webpack 配置
性能优化
babel

4. 项目设计

状态设计
组件设计
组件通讯

5. 项目流程

全栈

面试技巧

  • 简历:简洁明了,突出个人技能和项目经验,技术栈
  • 可以把个人博客、开源作品放在简历中(但博客要有内容)
  • 不要造假,保证能力上的真实性(斟酌用词,如精通xxxx)
  • 注意事项
    • 如何看待加班:像借钱,救急不救穷
    • 千万不要挑战面试官,反考面试官
    • 学会给面试官惊喜,证明你能想到更多,做的更好,但是不要太多
    • 遇到不会的问题,说出你知道的部分即可,但是别岔开话题
    • 谈谈你的缺点:说一下你最近在学什么即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值