[重点]2023前端全方位知识点

一.学习文章

有兴趣的同学可以查看这篇文章,会不定期更新一些优秀文章
前端优秀文章收集
主要介绍自己开发时定义的基本规范
前端开发命名规范
主要介绍vue3的新特性
Vue3.x新特性总结及与Vue2.x的对比

二.JS

1.闭包

含义:闭包就是一个函数,两个函数彼此嵌套,内部函数就是闭包形成闭包条件
缺点: 局部变量会常驻在内存中, 容易造成内存泄漏,因为闭包会长期不被释放,不易被垃圾回收机制回收
使用场景:
1.setTimeout
2.回调
3.函数防抖
4.计时器

function test(){
  let name='123';
	function aa(){
	console.log(name);
}
}

2.深拷贝浅拷贝 | 深克隆浅克隆

浅拷贝还是同一块内存地址,深拷贝则是重新开辟一块!
浅拷贝

  • 就是一个变量赋值给另一个变量,其中一个变量的值改变,两个变量的值都变了,会随着源对象的变化而变化,这就叫做浅拷贝
  • 浅拷贝的方法Object.assign(target, sources)

深拷贝

  • 新拷贝的对象内部所有数据都是独立存在的,不会随着源对象的改变而改变
  • 递归拷贝 和 利用JSON函数深拷贝JSON.parse(JSON.stringify(a))

浅克隆

  • 就是复制,因为引用型变量保存的是内存地址,其实后来操作的都是同一块内存,导致了数组内容都一样

深克隆

  • 克隆的时候判断一下属性的类型是不是引用型变量,如果是的话就用递归方法让它一层一层进去复制自己。

3.ES5和ES6区别及特性

ES5
1.严格模式,限制一些用法,‘use strict’
2.Array增加every,some,forEach,filter,indexOf,map,isArray等方法
3.Object增加Object.defineProperties , Object.freeze ,Object.create等方法
4.require引入包
ES6
1.块级作用域 let const
2.字符串模板 `测试${name} ’
3.Modules模块可配置加载和export
4.Proxy 使用代理监听对象操作
5.import引入包
6.箭头函数
7.解构
8.展开运算符

4.JS中数据类型及区别

基本数据(值)类型
string,number,Boolean,Null,Undefined,Symbol
引用数据类型
Object,Array,Function
值类型与引用类型的区别
(1) 存储位置不一样
① 值类型的变量和引用类型的变量会保存在栈内存中
② 但是引用类型的变量值会存储在堆内存
在这里插入图片描述
(2) 复制方式不一样
① 值类型的变量直接赋值就是深复制,如 var a = 10; var b = a;那么a的值就复制给b了,b修改值不会影响a
② 引用类型的变量直接赋值实际上是传递引用,只是浅复制

5.Js中精度问题

解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)
比如: (0.1 * 10 + 0.2 * 10) / 10 == 0.3 // true

推荐查看这篇文章 https://www.cnblogs.com/goloving/p/7712742.html

6.原型和原型链

原型:
所有的函数都有一个特殊的属性prototype(原型),prototype属性是一个指针,指向的是一个对象(原型对象),原型对象中的方法和属性都可以被函数的实例所共享。所谓的函数实例是指以函数作为构造函数创建的对象,这些对象实例都可以共享构造函数的原型的方法。
原型链:
原型链是用于查找引用类型(对象)的属性,查找属性会沿着原型链依次进行,如果找到该属性会停止搜索并做相应的操作,否则将会沿着原型链依次查找直到结尾。常见的应用是用在创建对象和继承中。

原型和原型链 四个规则
1.可自由扩展属性
2.都有隐式原型_proto_,是一个普通的对象
3.隐式_proto_指向它的显式原型prototype
4.如果当前对象某个属性没有该值时,会自动下探到_proto_中的prototype中查找 最终为null

7.原型链继承

参考文章:js实现继承的四种方法

  1. 原型链继承(有缺陷):
    缺陷1:切断了Zi.prototype.constructor与Zi的关系
    缺陷2:原型链上的引用类型的数据会被所有实例共享

  2. 构造函数继承(有缺陷):
    缺陷1:Fu.prototype上的方法无法继承

  3. 组合继承(推荐):
    优点:解决了原型链继承和构造函数继承的缺点
    缺点:调用了两次Fu的构造函数,即new Fu()使用了两次,原型链继承Fu的构造函数一次,实例化一次

  4. 寄生组合式继承(推荐):
    特点:使用到了Object.create(Fu.prototype)实现原型链的浅拷贝
    优点:解决了原型链继承和构造函数继承的缺点
    缺点:暂无
    在这里插入图片描述

8.谈一谈 JavaScript 的异步

常用为以下四种

  • setTimeout() 定时器
  • aynsc/await
  • promise
  • 回调callback

9.JavaScript的运行机制

基本概念
JavaScript是单线程,执行任务需要排队执行
同步任务下进入主线程排队,异步任务进入事件队列等待进入主线程执行
宏任务与微任务方式理解
代码运行被作为宏任务开始执行,执行中如遇到微任务,则依次执行微任务,直至当前任务队列中的任务执行完毕
当一个宏任务中的微任务全部执行完毕后,则开始执行下一个宏任务,依次类推

10.事件冒泡和事件捕获

事件冒泡
简单概括:由内到外
从当前事件向父级直至根元素(Html),当某个元素的某类型事件被触发时,那么它的父元素同类型的时间也会被触发,直到触发到根元素上
举例: Vue常见的div内部Button添加@click.stop事件, 阻止冒泡
事件捕获
简单概括:由外向内
当某元素被触发时,先触发根元素的同类型事件,朝子级逐级触发,直至触发到事件源

11.null和undefined的异同点有哪些

相同点
都是空变量 都是假值,
转布尔值都是false
null == undefined 为 true
不同点
typeof判断null为object,判断undefined为undefined
null转数字为0,undefined转数字为NaN
null是一个对象未初始化,undefined是初始化了,但未定义赋值
null === undefined 为 false

12.基本类型到底存在哪里

字符串: 存在堆里,栈中为引用地址,如果存在相同字符串,则引用地址相同。
数字: 小整数存在栈中,其他类型存在堆中。
其他类型: 引擎初始化时分配唯一地址,栈中的变量存的是唯一的引用

通俗的解释: 值类型在栈上. 引用类型,引用在栈上,变量数据在堆上

13.什么是虚拟dom

虚拟dom就是JavaScript的一种抽象数据结构, 之所以需要虚拟dom, 是因为浏览器中操作dom的代价比较高,频繁操作dom会产生性能问题
而vue会通过对比更新前后的虚拟dom, 来找出需要更新的真实dom,从而减少操作dom

14.如何解决跨域问题

jsonp
websocket
nginx反向代理

15. ts 跟 js有什么区别,优点和缺点

ts 是 js 的超集,即你可以在 ts 中使用原生 js 语法。
ts 需要静态编译,它提供了强类型与更多面向对象的内容。
ts 最终仍要编译为弱类型,基于对象的原生的 js,再运行。

三.手写方面

1.instanceof的底层实现原理,手动实现一个instanceof

从当前引用的proto一层一层顺着原型链往上找,能否找到对应的prototype。找到了就返回true

function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 
    var O = R.prototype;   // 取 R 的显示原型 
    L = L.__proto__;  // 取 L 的隐式原型
    while (true) {    
    	if (L === null)      
    	    return false;   
    	if (O === L)  // 当 O 显式原型 严格等于  L隐式原型 时,返回true
    	    return true;   
    	L = L.__proto__;  
    }
}

2.手写bind函数

  • call()、apply()、bind() 方法的存在是为了改变函数体内 this 的指向
  • call()、bind() 方法分别接收参数,apply() 方法接收数组形式的参数,它们的第一个参数都是 this 的指向可省略或为 null
  • call()、apply() 方法会立即执行。bind() 方法不会立即执行,它会返回一个函数,可以将函数存储在变量中,再通过变量获取函数的返回值
Function.prototype.bind1 = function () { // 这块不可以使用箭头函数,因为 this 的指向不同
  // arguments 可以获取一个函数的所有参数,arguments 是一个伪数组
  // 使用 Array.from() 方法将 arguments 伪数组转化成数组
  const args = Array.from(arguments)
  // 获取 this 指向取出数组第一项,数组剩余的就是传递的参数
  const _this = args.shift()
  const self = this // 当前函数 fn1.bind(...) 中的 fn1
  return () => {
    return self.apply(_this, args)
  }
}
 
function fn1(a, b, c) {
  console.log('this', this)
  console.log(a, b, c)
}
 
const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
const res = fn2()

参考文章: https://www.cnblogs.com/datiangou/p/10192664.html

四.Vue

1.complie构建过程

主要为 parse,optimize,generate
这三部分 compile 的作用是解析模板,生成渲染模板的 render
AST即用数据形式描述一个东西的特征项
第一步parse接收template的原始模板,按照模板的节点和数据生成对应的AST
第二步optimize遍历递归每一个AST节点,标记静态的节点,这样可以对比出哪部分不需要变化,则在页面更新时,减少这部分DOM的比对
第三步generate把前两步生成完善的AST组装成render字符串函数,然后,generate逐步接收AST,逐级递归处理,一点点拼接直至完成

2.diff算法过程

vue2和vue3diff算法的对比

在Vue2.0当中,当数据发生变化,它就会新生成一个DOM树,并和之前的DOM树进行比较,找到不同的节点然后更新。但这比较的过程是全量的比较,也就是每个节点都会彼此比较。但其中很显然的是,有些节点中的内容是不会发生改变的,那我们对其进行比较就肯定消耗了时间。所以在Vue3.0当中,就对这部分内容进行了优化:在创建虚拟DOM树的时候,会根据DOM中的内容会不会发生变化,添加一个静态标记。那么之后在与上次虚拟节点进行对比的时候,就只会对比这些带有静态标记的节点。

1.当组件创建和更新时,vue会执行内部的update函数,该函数使用render函数生成的虚拟dom树,将新旧两树进行对比,找到差异点,最终更新到真实dom
2.对比差异的过程叫diff,vue在内部通过一个叫patch的函数完成该过程,在对比时,vue采用深度优先、同级比较的方式进行比对。同级比较就是说它不会跨越结构进行比较
3.在判断两个节点是否相同时,vue是通过虚拟节点的key和tag来进行判断的
具体来说,首先对根节点进行对比,如果相同则将旧节点关联的真实dom的引用挂到新节点上,然后根据需要更新属性到真实dom,然后再对比其子节点数组;如果不相同,则按照新节点的信息递归创建所有真实dom,同时挂到对应虚拟节点上,然后移除掉旧的dom。
4.在对比其子节点数组时,vue对每个子节点数组使用了两个指针,分别指向头尾,然后不断向中间靠拢来进行对比,这样做的目的是尽量复用真实dom,尽量少的销毁和创建真实dom。如果发现相同,则进入和根节点一样的对比流程,如果发现不同,则移动真实dom到合适的位置。
5.这样一直递归的遍历下去,直到整棵树完成对比。

3.vue响应式原理

Vue2.x

第 1 步:Observer内通过Object.defineProperty对数据进行劫持,并绑定getter和setter。
getter用于返回数据并通知Dep收集订阅器。
setter用于设置新值并通知Dep数据变化
第 2 步:Compile对指令(v-text、v- html、{{ }} 等)进行解析,并准备初始化页面。
第 3 步:初始化页面前需要执行3,实例化Watcher,为即将渲染到页面的数据绑定自身对应的watcher(watcher中有更新视图的回调函数)。
第 4 步:拿数据时会触发getter,getter将数据返回用于渲染页面,并执行4-1,告诉Dep收集之前为该数据绑定的watcher,然后Dep就执行4-2去收集watcher。
第 5 步:当数据变化时会触发setter,setter为数据设置新值,并执行5,告诉Dep数据变化了,Dep又通知Watcher数据变化了,又watcher执行回调去更新页面。
在这里插入图片描述

Vue3.x
可以监听属性的增删操作。
可以监听数组某个索引值的变化以及数组长度的变化。

通过proxy对象,将所有的请求都进行拦截,针对性的进行模块更新

    let datas = {
        num: 0
    }
    let proxy = new Proxy(datas, {
        get(target, property) {
            return target[property]
        },
        set(target, property, value) {
            target[property] += value
        }
    })

两者区别
vue2和vue3的区别
a. defineProperty API 的局限性最大原因是它只能针对单例属性做监听。

  • Vue2.x中的响应式实现正是基于defineProperty中的descriptor,对 data 中的属性做了遍历 + 递归,为每个属性设置了 getter、setter。
  • 这也就是为什么 Vue 只能对 data 中预定义过的属性做出响应的原因,在Vue中使用下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter监听的,这是defineProperty的局限性。

b. Proxy API的监听是针对一个对象的

那么对这个对象的所有操作会进入监听操作,这就完全可以代理所有属性,将会有很大的性能提升和更优的代码。
Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

c.响应式是懒惰的

  • 在 Vue.js 2.x 中,对于一个深层属性嵌套的对象,要劫持它内部深层次的变化,就需要递归遍历这个对象,执行 Object.defineProperty 把每一层对象数据都变成响应式的,这无疑会有很大的性能消耗
  • 在 Vue.js 3.x 中使用 Proxy API 并不能监听到对象内部深层次的属性变化,因此它的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部属性才会变成响应式,简单的可以说是按需实现响应式,减少性能消耗

4.vue3.x编译优化了哪些

生成Block Tree

Vue2.x
数据更新并触发重新渲染的粒度是组件级的,单个组件内部 需要遍历该组件的整个 vnode 树
渲染效率的快慢与组件大小成正相关:组件越大,渲染效率越慢
并且对于一些无修改的节点也进行了遍历,这是性能浪费
Vue3.x
做到了通过编译阶段对静态模板的分析,编译生成了 Block tree
每个区块只需要追踪自身包含的动态节点
渲染效率不再与模板大小成正相关,而是与模板中动态节点的数量成正相关

slot编译优化

Vue2.x
每次父组件更新时,都会重新强制渲染子组件
Vue3.x
只会更新动态生成的子组件,如使用了v-if,v-for等导致slot会动态变化的

diff算法优化
详见上方 四.2 diff算法优化

5.vuex和全局变量的区别

1.vuex刷新页面会丢失数据; 全局变量不会
2.vuex多个组件共用一个状态时,可以实时更新; 全局变量无法更新

6.Vue通信方式

provide/inject 依赖注入
emit on
props emit
vuex
ref

五.CSS

1.什么是 BFC

BFC即块级格式上下文(Block Formatting Context)

在一定条件下会触发

  • 浮动元素 float
  • display
  • postion定位元素
  • overflow

特性

  • 垂直方向上,元素从上到下一次放置
  • 同一个BFC的两个相邻兄弟Box的margin会叠加
  • BFC是独立的布局容器,不受内部与外部的元素干扰

可解决的问题

  • 外边距塌陷问题
    这时外边距会怎么计算呢?
    1.两个都是正数,取较大的值
    2.两个都是负数,取绝对值较大的值
    3.一正一负,取两个值得和

  • 清除浮动问题

参考文章: https://blog.csdn.net/qq_44815747/article/details/114164636?spm=1001.2014.3001.5506

2.什么是盒模型及盒子模型高度计算

w3c 盒模型
width height= content
IE怪异盒模型
width height=content+border+padding

元素的实际高度=border+padding+height

3.CSS垂直居中

第一种: flex方式
 body {
    display: flex;
    align-items: center; /*定义body的元素垂直居中*/
}

body{
		display:flex;
		flex-direction:column;
	    justify-content: center; /*定义body的里的元素水平居中*/
}

第二种: 绝对定位+transform   //无需知道被居中元素的大小
child{
	position:absolute;
	top:50%
	transform:translateY(-50%);
}

第三种: padding方式 //给父元素设置相等的上下内边距
#box{
	width: 300px;
	background:#ddd;
	padding: 100px O;
}
#child{
	width: 150px;
	height:100px;
	background: orange;
}


4.CSS实现0.5px

通过缩放实现
  .a2{
      height: 1px;
      background-color: #f00;
      -webkit-transform: scaleY(.5);
      transform:scaleY(.5);
}
通过伪元素实现
  .border {
        position: relative;
    }
    .border::after {
        content: " ";
        position: absolute;
        width: 100%;
        height: 1px;
        background: red;
        transform: scaleY(0.5);
    }

5.CSS实现斑马线

利用css属性 background: liner-gradient

六.前端工程化

1. Vite和Webpack的区别

  • vite先启动服务器,在懒加载模块; webpack先将文件打包然后再启动服务器
  • vite由于是懒加载,再初始进入页面时会较慢(但可忽略不计); webpack由于是先打包,所以反应较快
  • vite热更新只更新编辑的模块,并且会利用HTTP来进行协商缓存 ; webpack会重新构建整个包

Vite打包原理

当script标签为moudle类型时,浏览器会像服务发送get请求,首先找到main.js文件,检测import引入的包,并通过劫持浏览器的请求,将请求的文件返回给浏览器进行解析

webpack打包原理

1.逐渐递归识别依赖,构建依赖图谱
2.将代码转换成AST抽象语法树
3.在AST阶段中取处理代码
4.把AST抽象语法树变成浏览器可识别的代码,并输出

七.浏览器

从浏览器地址栏输入url到请求返回发生了什么

首先会进行 url 解析,根据 dns 系统进行 ip 查找,双方进行三次握手建立链接,然后请求html文件,如果本地有html缓存则直接取,无则从服务器拿,最后前端进行渲染

为什么url要解析

因为网络标准规定了URL只能是字母和数字及部分特殊符号,如果不转义会出现歧义,造成浏览器识别错误

前端如何进行DNS优化

前端的dns优化,可以在html页面头部写入dns缓存地址
<link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />

dns解析流程

1.浏览器中输入如www.baidu.com域名,操作系统会先查本地hosts文件是否有记录,有的话则把对应的IP返回
2.如果本地hosts文件没有记录,则会去查本地dns解析器有没有缓存
3.有缓存则会去我们的计算机上配置的dns服务器查询缓存
4.否则则会去根DNS根服务器,然后判断.com是哪个服务器管理,如果无法解析,就查找baidu.com服务器能否解析,直到可以查到www.baidu.com的ip地址

encodeURIComponent比encodeURI有什么区别

encodeURIComponent编码范围更广,适合给参数编码,encodeURI适合给URL本身(locaion.origin)编码

http协议的三次握手

第一次握手:主机A发送位码为SYN=1的TCP包给服务器,并且随机产生一个作为确认号(这是tcp包的一部分),主机B收到SYN码后直到A要求建立连接;
第二次握手:主机B收到请求后,向A发送确认号(主机A的seq+1),syn=1,seq = 随机数 的TCP包;
第三次握手: 主机A收到后检查确认号是否正确,即第一次A发送的确认号是否+1了,以及位码ack是否为1,若正确,主机A会再发送确认号(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

为什么不是两次握手

因为在第二次握手时,主机B还不能确认主机A是否已经收到确认请求,也就是B已经准备好发数据了,但A一直接收不到,那攻击B就很容易了,光发包不接收,服务器很容易挂掉

浏览器缓存

三级缓存原理
1.先在内存中查找,如果有,直接加载。
2.如果内存中不存在,则在硬盘中查找,如果有直接加载。
3.如果硬盘中也没有,那么就进行网络请求。
4.请求获取的资源缓存到硬盘和内存。
缓存的分类
1.强缓存
关键词: Expires:失效的绝对时间 Cache-Control:np-cache或设置max-age时间
浏览器在加载资源时,会先根据本地缓存资源的header中的信息判断是否命中强缓存,如果命中则直接使用缓存中的资源,而不进行网络请求操作
2.协商缓存
关键词: Last-Modify:浏览器请求时,会返回一个最后修改时间的标识;当再次请求时,会包含If-Modify-Since字段,来判断时间是否命中缓存. 缺点就是如果资源在短时间发生改变,Last-modify将不会改变
Etag标识:如果浏览器请求时发现ETag不一致,则进行更新
当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存
缓存的优点
1.减少了冗余的数据传输
2.减少了服务器的负担,大大提升了网站的性能
3.加快了客户端加载网页的速度

参考文章: 彻底搞懂浏览器缓存

CSRF攻击和XSS攻击

CSRF(Cross-site request forgery) 跨站请求伪造
一般常见于网站欺诈,如陌生链接盗取你的cookie信息
解决办法:
1.Token验证
2.Referer验证,只允许接受本站的请求,外站一律不受理
XSS (Cross Site Scripting): 跨域脚本攻击
向网站注入JS,HTML代码,进行篡改网站的操作
Vue和React都是基于Dom,所以避免了大量的xss
也要注意减少v-html个内嵌js代码的操作

八.性能优化

篇幅较长,遂另开了一篇文章
vue优化篇-1.前端性能优化及注意点

九.算法

冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对

var arr=[1,35,21,2,565,888,96554,1222];   //先把他们放到一个数组
for(var i=1;i<arr.length;i++){    // 比较的轮数,这里就代表总共比较7轮
     for(var j=0;j<arr.length-1;j++){     //每一轮比较的次数
             //交换2个元素的值
            if(arr[j]>arr[j+1]){
                var tmp=arr[j];    //这里var 了个tmp,作用就是作为一个arr[j]和arr[j+1]交换的载体(空间),在此处不可以直接交换
                arr[j]=arr[j+1];
                arr[j+1]=tmp
              }
    }
}
console.log(arr);

快速排序

将数组分割成两个部分, 并找一个基准点, 比当前基准点小的放到左边,大的则放到右边 当两边都有序的时候则实现了排序

function quickSort(arr) {
    let len = arr.length;
    if (len === 0) return arr;
    let first = arr[0];
    let lesser = [], greater = [];
    for (let i = 1; i < len; i++) {
      if (arr[i] < first) {
        lesser.push(arr[i]);
      } else {
        greater.push(arr[i]);
      }
    }
    return quickSort(lesser).concat(first, quickSort(greater))
}
var temp = quickSort([8, 12, 50, 2, 6, 7]);
console.log('最终值:'+temp);

选择排序

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕

function swap(arr, index1, index2) {
  let temp = arr[index1];
  arr[index1] = arr[index2];
  arr[index2] = temp;
}

function selectSort(arr) {
  let len = arr.length;
  let max;
  for (let i = len - 1; i >= 1; i--) {
    max = i;
    for (let j = 0; j < i; j++) {
      if (arr[j] > arr[max]) {
        max = j;
      }
    }
    swap(arr, i, max);
  }
  return arr;
}

console.log(selectSort([15, 8, 14, 2]));

归并排序

在列表中选择一个元素作为基准值,排序围绕这个基准值进行,将列表中小于基准值的放入数组底部大于放顶部。

function mergeSort(arr) {
  let len = arr.length;
  if (len < 2) return arr;
  let middle = Math.floor(len / 2),
    left = arr.slice(0, middle),
    right = arr.slice(middle);
  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  let result = [];
  while (left.length > 0 && right.length > 0) {
    if (left[0] <= right[0]) {
      result.push(left.shift());
    } else {
      result.push(right.shift());
    }
  }

  while(left.length) result.push(left.shift());
  while(right.length) result.push(right.shift());

  return result;
}

二分查找

基于有序序列
找到返回元素索引,否则返回-1

function binarySearch(arr, target) {
  let len = arr.length;
  let low = 0,
    high = len - 1;
  while (low <= high) {
    let middle = Math.floor((low + high) / 2);
    if (arr[middle] < target) {
      low = middle + 1;
    } else if (arr[middle] > target) {
      high = middle - 1;
    } else {
      return middle;
    }
  }
  return -1;
}
console.log(binarySearch([2, 4, 5, 6, 7], 7));

二叉树

前序遍历:根结点-左结点-右结点
中序遍历:左结点-根结点-右结点
后序遍历:左结点-右结点-根结点
在这里插入图片描述
按照前序遍历的结果就是 BADCE。
按照中序遍历的结果就是 ABCDE。
按照后续遍历的结果就是 ACEDB。
按照层次遍历的结果就是 BADCE。

十.语言博弈

你觉得上家公司做的怎么样
先大概的夸一夸上家公司,然后再谈一谈让你不想待的原因,千万不要开吐槽大会,抱怨这个,抱怨那个的。比如说我觉得上家公司各种方面做的都不错,无论是公司环境,管理制度,团队氛围都很好,但是技术栈更新比较缓慢,调薪制度不理想。

为什么要干前端
觉得前端比较有意思,可以看到界面,可以做一下好玩的东西,给父母孩子女朋友显摆。

你平时是怎么学习的
看纸质书,电子书,视频,博客论坛。

看过什么书
看过什么就说什么,千万不要瞎编。我听说过有的面试官会问你某本书的封面是什么颜色的,目录是什么等奇葩问题。

你觉得你的优势/不足有什么
优势在于主动学习,乐于分享。不足是不感兴趣的内容学习不下去,比如数据库。

举一个例子,证明自己是乐于学习的
xx社区优秀作者
公司的年度进步奖
开源项目

你对自己的职业规划
四个字,逼格直接上来了,一专多精。

你还有什么想要问我的么
我一般会问技术团队的规模
技术团队有几个人,
几个前端,
几个后端,
高级,中级,初级的分别是多少人

目前在使用什么技术栈
将来打算使用什么技术栈
自己是否可以决定未来技术栈的走向

然后是自己在团队中的角色
负责什么工作
对于项目的决策度

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

情系半生e

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值