文章目录

  • 勇往直前的菜鸟修炼手册
    • 自我介绍
    • 项目相关
    • 项目业务组件相关
      • 前端框架和业务组件
    • 管理方面
      • 走查代码篇
        • 日常怎么走查代码
        • 企业微信的机器人道具,可以钩住代码push的消息。
      • 假如你是一个前端leader负责前端团队管理(技术管理,人员管理,任务管理),请浅谈一下你的管理思路。
      • 团队质量如何管理
      • 在开发过程中发现问题,可能要延期,怎么处理
    • css篇
      • css预编译器,less和sass
      • 盒子上下左右居中的方法
      • 盒子模型box-sizing
      • flex布局使用过程中的问题
    • js篇
      • var let const 有什么区别
      • [场景题]for循环
      • 有什么方式能改变函数的this指向呢
      • call,apply,bind的区别和具体实现原理
      • 原型
      • 原型链
      • new这个操作符做了哪些
      • js中的继承实现方式
      • 项目中常用的遍历object的方法
      • for in ,for of, forEach ,map的区别(迭代)
      • 项目中常用的深拷贝方法
      • 项目中有遇到节流或者防抖的优化场景吗
      • 有做过图片懒加载优化吗
      • js的事件循环(Event Loop)
      • 宏任务微任务的关系
      • promise构造函数是同步执行还是异步执行?then方法呢?
      • Promise原理
      • MVC和MVVM的区别
      • jquery的事件委托(addEventLisenters)
      • 事件传播
      • 关于浮点数计算误差问题
    • 浏览器篇
      • 浏览器组成
      • 浏览器请求上限
      • 网页可视化过程
      • 网页可视化过程对于前端开发的启示
      • 介绍下重绘和重排,以及如何优化
      • cookie和token都存放在header中,为什么不劫持token
      • 本地存储
      • cookie ,localstorage,seesionstorage的区别和使用场景(2次)
      • 如何开启强缓存
        • htpp缓存---强缓存,协商缓存(什么时候出现200,304)
      • web可视化相关内容
        • 现在web可视化的方向
        • canvas和svg
      • 浏览器关闭当前页面的事件是否能监听到,一种是通过关闭标签页,一种是通过关闭浏览器
      • 前端性能优化(具体)
      • 大量数据的前端优化方案
      • 减少dom操作提升性能的方法
      • 怎么落实开发规范
      • 乾坤中跨组件跨应用的通信方式有哪些
      • 项目中处理跨域的方式
      • 项目中对webpack的了解
      • 平常如何对自己项目的经验和学习到的东西进行管理
      • 浏览器响应code码有哪些,分别是什么含义
    • vue源码篇
      • 在vue中,子组件为何不可以修改父组件传递的prop?子组件怎么修改父组件中的数据?
      • vue父子组件加载的原理
      • watch 和computed
      • 在vue中动态的引入图片为什么要使用require
      • vue的响应式原理是什么
        • vue响应式原理中Object.defineProperty有什么缺陷?为什么在vue3.0采用了Proxy,抛弃了Object.definePrototype?
      • 在dom中,数据和vue中的数据如何进行双向绑定,它的原理是什么,(比如现在有个组件,在渲染的时候,怎么对数据和页面实现双向绑定)
      • 路由有哪些模式
      • vue2和vue3的响应式原理的区别,优缺点。
      • 高内聚低耦合
      • 在共用组件的时候需要用到new吗
      • 前端模块化解决了哪些问题?
      • 使用nuxt或者next进行服务端渲染,如何避免因代码逻辑错误或数据不一致造成服务器渲染报错,导致页面无法访问的问题?
      • 实际项目中做过导出pdf
      • 场景题
    • 版本管理
    • 试题篇
      • 大数相加
      • 千位数
      • 给定两个数组,写一个方法来计算它们的交集
      • 数组里面有10万个数据,取第一个元素和第n个元素的时间差是多少?
      • 请输出下面代码结果

勇往直前的菜鸟修炼手册

自我介绍

项目相关

以前项目中遇到的问题和解决方法

项目业务组件相关

前端框架和业务组件

管理方面

走查代码篇

日常怎么走查代码

代码走查的目的:
1,可以帮助新同事快速熟悉代码并了解系统。
2,通过在一起讨论和审查,加强团队代码阅读和编写能力。
3,在做资损防控的事前检查,在事前规避引发线上事故。
核心的目的还是通过代码走查提前发现问题并解决问题。
代码走查的时机:
1,定期,每几个月定期做一次。
2,有重大变更时做代码走查。比如代码第一次上线,代码改了主线流程,或者增加了较多的代码。
如何进行代码走查:
代码走查的角色:
主持人:负责主持整个走查活动。包括会议邀约时间和控制时长和会议进度。
讲解人:负责对代码进行讲解并跟进修改计划,一般时系统的owner或者代码编写者。
记录人:记录代码走查记录,包括走查中发现的问题点,修复方法和最佳实践。问题需要指定到对应的人。
评审人:对代码进行评审发现问题并找出最佳实践,一般时资深开发和测试同学。
参与人:参加代码走查,主要以学习为主。
走查前的准备工作:
讲解好本次需要走查的代码分支,和代码入口。通知所有参会人员。参会人员提前阅读分支和代码,针对看不懂的代码,有问题的代码和设计复杂的代码全部提交review记录。
讲解人必须想好走查哪些代码,一般是主流程或者有问题的点,控制整个代码走查的时间。
走查过程中控制节奏
讲解人应该先大概先讲解一下系分设计,讲一部分设计再讲一部分代码,讲解人带着大家一行一行读代码,讲解代码的含义和思考,记录人负责记录review出的问题和最佳实践。
代码走查的评判标准
需要注意几个点:
编码规范:可以使用IDEA的插件自动扫描有没有编码问题
设计规范
幂等性
逻辑问题:是否满足需求
一致性问题
并发和锁:在并发情况下,代码执行结果是否有问题
性能问题:代码是否存在性能问题
分支覆盖率:是否有分支没有覆盖
走查后总结
在代码走查之后,要优化代码走查,会发一个调查问卷给大家
1,参加代码走查有什么收获
2,对代码走查有什么建议。
参考文档: 代码走查如何保证软件质量

企业微信的机器人道具,可以钩住代码push的消息。

假如你是一个前端leader负责前端团队管理(技术管理,人员管理,任务管理),请浅谈一下你的管理思路。

  1. 技术管理方面:技术创新,代码走查,技术培训。
  2. 人员管理方面:人力资源计划,人力复用计划,阶梯培养,人员带教。
  3. 任务管理方面:任务分解,任务排期计划,任务量化,进度跟进,风险预判和处理。

团队质量如何管理

  1. 前期概要设计和详细设计把控项目需求和技术难点
  2. 研发过程任务拆解/计划,每个功能按照计划进行,投入时间必须产出
  3. 研发过程中每日验收和走查,保证每日交付内容质量
  4. 预留研发自测时间,在项目体测之前进行自我发现,自我修复
  5. 当日bug当日清,提高测试机回归效率
  6. 技术培训和带教提升团队整体实力,从技术上规避简单问题、

在开发过程中发现问题,可能要延期,怎么处理

找到需要延期的原因,查找解决方案,确定方案可行性和时间。上报项目经理和产品经理,共同沟通之后决定处理方案和延期时间。
后续提交项目延期的报告。

css篇

css预编译器,less和sass

less和sass
变量定义
函数
遍历
mixins
includes
继承 @extend

盒子上下左右居中的方法

绝对定位

.parent{position:relative;
}
.children{position:absolute;top:0;left:0;right:0;bottom:0;margin:auto;
}

绝对定位,ransform:translate()

.parent{display:relative;
}
.children{.position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
}

table-cell
弹性盒子flex 居中

.parent{display:flex;flex-direction:row;justify-content:center;align-item:center;
}

盒子模型box-sizing

盒子模型是什么:css盒子模型是在网页设计中经常用到的CSS技术所使用的一种思维模型。
盒子模型组成:content-padding-border-margin;
标准盒子模型
box-sizing:content-box;(默认)
标准盒子模型中,盒子的宽度是content+padding+border+margin的值
怪异盒子模型
box-sizing:border-box;
怪异盒子模型中,盒子的宽度是content+margin的值。而content的值是包含你border+padding的值。
弹性盒子模型

flex布局使用过程中的问题

flex-basis的缺陷,排版溢出问题 –flex-basis

js篇

var let const 有什么区别

【答】
区别一:var 可重复定义相同的变量名;let和const在当前作用域内只能定义唯一变量名;
区别二:var和let声明的变量可以修改,const声明的常量不可修改(如果声明的是一个引用数据类型,比如对象的话,是可以修改对象属性的值的)。
区别三:var存在变量提升,在定义变量之前去获取到这个变量,获取到的值为undefined。let和const存在暂时性死区,在定义变量之前去调用,会抛错
【续问】为什么const定义的对象可以修改对象的值
【答】
因为对象是属于引用类型,变量中保存的值是存放在栈内容中的引用地址,实际的对象数据是存放在堆内存中的。而修改堆内存地址中变量的属性值是不会改变栈内存中的引用地址的值的。
【关于变量提升原理】浏览器引擎在解析js代码之前会对其进行预编译,在预编译阶段会找到所有的声明,并用合适的作用域将其关联起来。也就是说包括变量声明和函数声明都会在代码执行之前被预先处理。变量提升其实就是变量的预处理。被提升的仅仅是对变量的声明,赋值操作不会被提升。
函数声明和变量申明都会被提升,函数属于一等公民,会优先被提升,然后才会提升变量。需要注意的是,相同命名的变量和函数,最后变量会覆盖函数。

var a = 34;
function a(){console.log("dsgdsg")
}
----------------------------------
console.log(a)  // 34
(tips:以上两个声明需要同时执行,不然后执行者会对a重新进行赋值。)反之亦然

[场景题]for循环

场景:例如现在有一个for循环

 for(var i = 0;i<5;i++){setTimeout(function(){console.log(i);},0)}打印结果为:--------------------  答案分界线  -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------55555

【续问1】

for(let i = 0;i<5;i++){setTimeout(function(){console.log(i);},0)}打印结果为:--------------------  答案分界线  -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------01234

【续问2】造成两者区别的原因是:

【续问3】

for(var i = 0;i<5;i++){console.log(i);}打印结果为:--------------------  答案分界线  -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------01234

【续问4】
最初的问题和续问3的问题为什么得到的答案结果不一样呢(关于setTimeout的执行时间)




【答】因为setTimeout是属于异步,for循环是属于同步,js代码会先执行同步代码之后再执行异步
【续问5】为什么【续问1】中使用let定义的i,能在setTimeout中取到对应的值呢
【答】因为使用let定义的i会产生一个块级作用域,setTimeout里面的i都是互不干扰的。
【续问6】每一次for循环都会生成一个块级作用域吗
【答】是的

有什么方式能改变函数的this指向呢

call,apply,bind的区别和具体实现原理

【答】
call,apply,bind都是object原型上面的方法,任何一个方法都可以调用这三种方法。
区别一:传参区别:三个方法的第一个参数是新的this对象,call和bind第一个是this,剩余的其他参数为传给函数的参数;apply只有两个参数,第一个是this,第二个参数是一个数组对象,里面接受传给函数的所有参数。
区别二:call,apply会执行运行出方法的结果,bind会返回一个方法,需要执行之后才能得到结果。
实现原理如下代码

 function myCall(_this,strArray){const oldThis = this;_this.$fun = oldThis;_this.$fun(strArray);}            Object.prototype.myCall = myCall;function a(){let b = "123";console.log("我是b方法里面的:",this.b);}let c={b:"我是c对象里面的b"}a.myCall(c); -------------------------------------------------------------------输出答案为:我是b方法里面的: 我是c对象里面的b

原型

所有的引用数据类型都有一个隐式原型__proto __,属性值是一个普通对象
所有的函数都有一个prototype(原型)属性,属性值是一个普通的对象
所有引用类型的__proto __是指向它构造函数的prototype。

原型链

如下示例分析原型链

function Person(){this.name = function (){console.log('打印Person的方法name')}
}
let xm = new Person();
xm.name();// 打印Person的方法name
xm.age();// xm.age is not a function

上诉过程中,我们从实例对象xm自身属性找到name方法返回结果。再查找age方法,未找到。然后就查找__proto __上是否有name方法。此时xm.__proto __ 是指向 Person.prototype,未找到。开始查找Person.__proto __(指向Function.prototype),未找到,继续查找Function.__proto __,查找结果为undefined。

Person.__proto__ == Object.prototype // false
Person.__proto__ == Function.prototype // true
Person.prototype.constructor //指向Person自身

【实战题】

Function.prototype.eat = function(){console.log('eat方法')
};
function Person(){};
let person = new Person();
Person.eat();
person.eat();

new这个操作符做了哪些

我们常常使用new的场景,比如 new Array(),new Set()。在使用构造函数时,也常常使用new创建一个实例。我们看下创建一个实例的时候,new做了哪些步骤呢。
第一步;创建一个对象 a
第二步:将a的隐式原型,__proto__指向构造函数的显式原型:prototype;a. _ proto _ = A.prototype;
第三步:改变构造函数的this全部指向新的对象a。let result = A.call(a);
第四步:返回对象值。判断构造函数A的返回值类型(为什么需要判断返回值类型?因为如果在构造函数中返回的this是基本数据类型(number,string,boolean,null,undedind)的值时,这时候返回新的实例对象,如果构造函数返回的值时引用类型,则返回的值时引用类型)
if (typeof (result) === “object”) {
func = result;
} else {
func = a; // 默认返回
}
我们用代码浅还原一下

function NewObj (){let a = {};a.__proto__ = A.prototype;let reslut = A.call(a);if(typeof reslut  == 'object'){return reslut}else{return a;}
}

js中的继承实现方式

方式一、原型链继承

//父类型
function Animal(name) {this.name = name;this.eat = function (food) {console.log(this.name + "正在吃:"+ food);}
}function Dog() {}
Dog.prototype = new Animal();
Dog.prototype.name = "大皇狗";var dog = new Dog();console.log(dog.name);
dog.eat('打骨头');console.log(dog instanceof Animal); //true
console.log(dog instanceof Dog); //true

特点:

非常纯粹的继承关系,实例是子类的实例,也是父类的实例
父类新增原型方法/原型属性,子类都能访问到
简单,易于实现

缺点:

要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
无法实现多继承
来自原型对象的所有属性被所有实例共享
创建子类实例时,无法向父类构造函数传参

方式二: 借用构造函数继承

 function Dog() {Animal.call(this);this.name = name || '大黄狗';}var dog = new Dog();console.log(dog.name);dog.eat("大骨头");console.log(dog instanceof Animal); // falseconsole.log(dog instanceof Dog); // true

特点:

解决了1中,子类实例共享父类引用属性的问题
创建子类实例时,可以向父类传递参数
可以实现多继承(call多个父类对象)

缺点:

实例并不是父类的实例,只是子类的实例
只能继承父类的实例属性和方法,不能继承原型属性/方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

方式三:组合继承

// 父类
function Person(name,age){this.name = name;this.age = age;this.greed = function(){console.log("名字为"+this.name);}
}
//子类
function student(name,age,sex){Person.call(this);this.sex = sex;this.name = name;this.age= age;
}
student.prototype = new Person('student','14','男');

特点:

这个方法结合了原型链继承和构造函数继承两种方式的结合体。结合了这两种的优点。

缺点:

需要调用两次父类的构造函数,分别是在prototype和实例化子类新对象的时候调用的,造成了一定的内存浪费。

方式四:原型继承
利用一个空对象,将某个对象直接赋值给空对象构造函数的原型。

function Student2(){}
Student2.prototype = Person;
let stu = new student2();

方式五:寄生式继承
方式六:ES6中class 的继承

 class Person {//调用类的构造方法constructor(name, age) {this.name = namethis.age = age}//定义一般的方法showName() {console.log("调用父类的方法")console.log(this.name, this.age);}}let p1 = new  Person('kobe', 39)console.log(p1)//定义一个子类class Student extends Person {constructor(name, age, salary) {super(name, age)//通过super调用父类的构造方法this.salary = salary}showName() {//在子类自身定义方法console.log("调用子类的方法")console.log(this.name, this.age, this.salary);}}let s1 = new Student('wade', 38, 1000000000)console.log(s1)s1.showName()

call()
【续问1】class类,通过extends继承了一个父类,实际上是继承了父类的什么
【续问2】子类是一个class类,子类中的constructor构造函数,constructor内可以调用super 方法,这个super方法的作用是?
【答】extends主要是继承了父类的原型对象上面的属性和方法,子类中的super方法是想复制一份父类的构造函数上面的自己的属性和方法,这里是两个对象,父类自己的原型对象和构造函数对象。子类想要把整个父类都继承下来。
它只是一种优雅的写法,实际上它是寄生组合式继承。即继承父类的构造函数也继承父类的原型对象。

项目中常用的遍历object的方法

for in
object.keys
object.values

for in ,for of, forEach ,map的区别(迭代)

**for...in**:遍历自身和继承的可枚举的属性,不能直接获取属性值,可中断
**for...of**:具有iterator 接口,就可以使用for...of进行遍历它的成员(属性值),可遍历数组,new Set,new Map数据结构,某些类似数组的数据结构,Generator ,以及字符串。可以中断循环。
**forEach**:只能遍历数组,不能中断,没有返回值(或者返回值是undefined)
**map**:只能遍历数组,不能中断,返回值是修改后的数组
**Object.keys()**:给出对象所有可枚举的属性的字符串数组,不包括继承自原型的属性和不可枚举的属性)
**Object.values()**:给出对象所有可枚举的属性值的字符串数组forEach和map的区别:相同点1,使用过程中,浏览器会在其回调函数中传递三个参数(item,index,arr)item:当前正在遍历的元素,index:当前正在遍历的元素的索引,arr:正在遍历的数组2,都是循环遍历数组中的每一项3,回调函数中的this都是指向的window。4,只能遍历数组不同点:1,forEach允许修改原数组,map会返回新的数组2,map会分配内存空间存储新数组并返回,forEach不会返回数据。

【续问】
for in 遍历对象时,如果这个对象有原型链,能遍历对象的原型对象上的key吗
【答】能遍历,可以使用使用Object.hasOwnProperty来判断是否是原型链上的对象属性a.hasOwnProperty(key),如果是原型上的属性,则为false。
【问】forEach 能中断吗
不能
【问】原生for循环内怎么中断
【答】break和contiun;
【问】

项目中常用的深拷贝方法

JSON.parse(JSON.stringfy())
【续问】它的问题是?
还有自己写递归方法进行深拷贝,持续递归,直至最后一层
【续问1】怎么判断数据类型是对象或者数组
1,使用typeof 区分基本数据类型和对象
2,isArray 可以判断是否为数组
用什么方法判断是个{};
3,使用instanceof进行判断
Array.instanceof(Object) 是true还是false
instanceof 是判断某一个数据是否为某一个数据对象的实例。沿着原型链去查找
4,Object.prortype.toString.call()

项目中有遇到节流或者防抖的优化场景吗

【续问】防抖节流的实际运用场景
【答】在项目中,常常会出现一些交互场景,比如输入框搜索,下滑动态加载,表单提交按钮等操作场景,在遇到这些交互场景是,很容易因为频繁的交互出现频繁的接口请求,影响性能。所以我们需要对用户的操作做一些优化。节流常用于
【续问1】代码层面如何实现

有做过图片懒加载优化吗

【续问】解决了什么问题
一次性加载大量的图片,每一张图片是一个资源地址,浏览器需要发起大量的http请求,http请求时同时发出去的,会阻塞带宽,导致其他请求的响应速度变慢,页面也需要等待较长时间,用户体验不友好。
【续问1】实现思路是怎么样的,如何实现的
可视区范围内
监听滚动条
只要不给img标签的scr属性赋值,它就不会发送请求

js的事件循环(Event Loop)

参考文章
单线程
javascript是单线程,也就是说同一时间只能做一件事,为什么javascript不能是多线程呢?

由于javascript是浏览器脚本语言,它可以操作dom。如果javascript是多线程,一个线程在执行删除某个dom节点,一个线程在执行修改这个dom节点的内容,那么以谁的操作为准呢。

任务
在js中我们将任务分为同步任务和异步任务。任务分为调用和得到结果两步。调用之后立即得到结果为同步任务,调用之后无法‘立即’得到结果,需要其他的操作才能得到结果的为异步任务。
在异步任务中,分为宏任务和微任务
宏任务:MacroTask
如:setTimeout,setInterval,script(整体代码),I/O操作,UI渲染等
微任务:MicroTask
如:new Promise().then(回调);MutationObserver等
执行栈

宏任务微任务的关系

在执行宏任务的时候,产生了微任务,这个微任务应该怎么执行
【续问】setTimeout是宏还是微
【续问】nextTick是宏还是微
【自答】
vue中的nextTick方法底层是一个promise,属于微任务,但是它有一个对浏览器的向下兼容,最后会用setTimeout

promise构造函数是同步执行还是异步执行?then方法呢?

promise构造函数是同步执行,但是then是属于异步执行。

【字节面试真题】这段代码的输出结果

console.log("script start")
setTimeout(function(){console.log("setTimeout")
},0)
new Promise(resolve =>{console.log("new promise1");resolve();console.log('new promise2')
}).then(function(){console.log('promise1')
}).then(function(){console.log('promise2')throw new Error('new error')console.log('promise3')
}).catch(e=>{console.log(e.message)
}).finally(()=>{console.log('finally1')
})
console.log('script end')

Promise原理

Promise简单来说就是一个容器,存放着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的信息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点
1,对象的状态不受外界影响。Promise对象代表一个异步操作,有三个状态:pending(进行中)fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2,一旦状态发生改变,就不会再改变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变成fulfilled或者rejected中的一种。只要状态状态改变,状态就会冻结,不再改变,这时候就称为resolved(已定型)。
Promise的缺点
1,无法取消Promise,一旦新建它就会立即执行。无法中途取消。
2,如果不设置回调函数,Promise内部抛出的错误不会反应到外部。
3,处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

简析Promise原理

//Promise里面只有一个参数executor,默认new的时候就会使用,且默认Promise的executor是同步执行
function MyPromise(executor){let self = this;self.status = 'pending';//初始状态self.value = undefined;//成功的值self.reson = undefined;//失败的值function resolve(value){//成功的方法if(self.status == 'pending'){self.status = 'resolved';self.value = value;}}function reject(reason){//失败的方法if(self.status == 'pending'){self.status = 'rejected';self.reason = reason;}}executor(reslove,reject);
}
//创建then方法
MyPromise.prototype.then = function(onFufiled,onRejected){let self = this;if(self.status == 'resolved'){onFufiled(self.value);// self.value 成功的原因}if(self.status == 'rejected'){onReject(self.reason);// self.reason 失败的原因}
}
module.exports = MyPormise;构造一个Promise实例需要给Promise构造函数传入一个函数,传入的函数需要两个形参,两个形参都是function类型的参数,分别是resolve和reject。
promise上的then方法。(then方法是异步调用的事件环),then方法就是用来指定Promise对象的状态改变时确定执行的操作,resolve时执行第一个函数(onFulfilled),reject时执行第二个函数(onRejected)。
当状态变为resolve或者reject之后就不可再改变。
promise无论成功(resolve)还是失败(reject)都会走then,只不过成功是走then的成功回调,失败是走then的失败回调。此时如果统一处理catch,可以直接把error函数提出来。

MVC和MVVM的区别

【续问】MVC为什么不是数据驱动,它也有module层
【续问】jquery是属于哪种设计模式,如何体现的呢(比如:jquery在module层做了什么,在view层做了什么,在control层做了什么)
【续问】如果我想用jquery,又想使用jquery去驱动view,又什么方案呢
了解数据驱动视图:
在mvc和MVVM之前,我们使用的是jq。只是静态渲染,更新还是依赖于操作DOM。这就是为什么jq运用广泛,jq操作DOM方便。但是有了MVC和MVVM之后;我们想要修改什么地方,只需要修改VUE或者React里面的数据就行,框架本身就会根据数据去渲染视图,不需要我们再操作DOM。
MVC模式:
MVC全名是:model(模型)-view(视图)-controller(控制器)的缩写,是一种软件设计典范。
view视图是指用户看到并与之交互的界面,比如由html元素组成的网页界面,或者软件的客户端界面。
model模型是指模型,表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。
controller控制器,接受用户的输入。
MVVM模式:
MVVM全名是:model(模型)-view(视图)-viewModel(视图模型)

jquery的事件委托(addEventLisenters)

【续问】绑定一个父元素,为什么能触发到子元素的onclick,ontarch这些方法呢,是基于什么原理呢
【续问】冒泡是如何冒上来的(例如我现在有一个table,我将事件绑定在table上面,我现在点击table的某一项某一行,我想要获取当前点击的这一行的innerTest文本,是否能获取到,是怎么样的冒泡机制能让你获取到的呢。我在table上使用addEventLisenters绑定的事件,当我点击行的实际触发这个事件,事件返回的event是table的还是tr的。 )
【答】当前返回的是点击的tr,而不是最初绑定的table。

事件传播

什么是事件传播?
当事件发生在DOM元素上时,该事件并不完全发生在哪个元素上。在“冒泡阶段”中,事件在冒泡或向上传播至父级,祖父母,祖父母或父级,直到到达window为止。而在“捕获阶段”中,事件从window开始向下触发元素事件或event.target。
事件传播有三个阶段:
1,捕获阶段-事件从window开始,然后向下到每个元素,直到到达目标元素。
2,目标阶段-事件已达到目标元素。
3,冒泡阶段-事件从目标元素冒泡,然后上升到每个元素,直到到达window。

关于浮点数计算误差问题

浮点数的概念:
浮点数指的是带有小数的数值,浮点运算即是小数的四则运算,常用来测量电脑的运算速度,大部分计算机都是采用的二进制的表示方式。位(bit)是衡量浮点数所需存储空间的单位,通常为32位或者64位,分别被叫做单精度和双精度。
误差现象:

console.log(0.1+0.2); // 输出0.30000000000000004
console.log(0.15+0.15);// 输出0.3
console.log(0.7+0.1);    // 输出 0.7999999999999999
console.log(0.6+0.2);    // 输出 0.8
console.log(0.3*3);      // 输出 0.8999999999999999

我们可以看出,只有部分浮点数运算会有问题。同样都是浮点数,为什么会出现这个差异呢?
造成误差的原因:
不仅仅是js,大多数语言在处理浮点数的时候都会遇到精度问题,准确的来说,所有支持二进制浮点数运算的系统都存在这个问题。
造成这个问题的原因就是,在有限的存储空间下,绝大部分的十进制小数都不能使用二进制来精确表示。例如:0.1这个简单的十进制小数就不能用二进制浮点数来表示。所谓【计算机浮点数】,其实就是二进制的【科学计算法】。在十进制中,科学计数法的形式是:

相应的,二进制的科学计数法就是

而在优先的存储空间下,十进制小数0.1无论如何也不能用这样形式来表示,因此,计算机在存储它时,就会产生精度丢失。
参考文章
解决思路
首先考虑的是如何解决浮点数运算的精度问题,有 3 种思路:
1· 考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));
2. 将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1 + 2)/10。(转化后的两个整数相乘的结果有可能超过 MAX_SAFE_INTEGER)
3. 把浮点数转化为字符串,模拟实际运算的过程。
【续问】
32位计算机和64位计算机能存储的最大数字位数分别时多少呢?
我们需要了解浮点数的存储规范:IEEE 754

value = sign * exponent * fraction
其中value表示浮点数的实际值
sign(bit)表示符号位:0表示整数 1表示负数
exponent表示的是转换成科学计数法后的指数偏移量
fraction 表示小数部分

在IEEE 754标准中,对于32位浮点数的各部分长度约定如下:

1bit的sign + 8bit的exponent + 23bit的fraction

对于64位浮点数的各部分长度约定如下:

1bit的sign + 11bit的exponent + 52bit的fraction

既然我们知道了32位和64位浮点数的小数部分展示需要的bit数,则可以知道对应的最大数值是多少。
32位浮点数小数部分最大值为:(223)-1 ==8388607。即最长位数为7位,最小精度为6位。
64位浮点数小数部分最大值为:(2
52)-1 ==4503599627370495。即最长位数为16位,最小精度为15位。
解释浮点数的二进制表达,以及超过位数超出之后的裁剪规则,可以查看此文档:参考文档
解释浮点数最大范围参考文档 浮点数最大范围参考文档

浏览器篇

浏览器组成

用户界面
包括地址栏,后退/前进,书签目录等
浏览器引擎
用来查询及操作渲染引擎的接口
渲染引擎
用来显示请求的内容,例如,如果请求的内容为html,则负责解析html和css,并将解析的结果显示出来
网络
用来完成网络调用,例如,http请求,它具有平台无关的接口,可以在不同平台上工作
UI后端(不是每个浏览器都有的)
js解释器
用来执行js代码。
数据存储
属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据。

浏览器请求上限

正常来说,常用的谷歌浏览器同时可请求数为6个,多了的话,会有明显的等待时间。
TCP是网卡罗传输层中的协议,三次握手简历链接,四次挥手终止链接。问题中,因为使用axios结合async,await异步请求来请求接口。因此,7个TCP同时发起连接,但是客户端和服务端的连接并没有立即全部建立成功。
http协议
http/0.9,http/1.0每个请求单独简历一个TCP链接,请求完成连接断开
http/1.1可以持久连接,TCP建立连接后不会立即关闭,多个请求可以复用同一个TCP连接,同时请求可以并行,但是不同浏览器对并行次数有个数限制:

网页可视化过程

网页框结构:网页层次结构
网页可视化:就是根据描述或者定义构建数学模型,通过模型生成图像的过程。
解析html树以构建dom树–>构建render树–>布局render树(layout tree)–>绘制render树

bilnk核的渲染过程(chrome)
【场景描述】在浏览器地址栏中,输入网址之后,点击回车,浏览器渲染出来页面。
资源加载器通知网络模块(下载资源,可能包含js,css,html),获取到资源之后塞给html资源解释器。html解释器分析资源文档,开始生成DOM树,分析html文档的同时,遇到js代码时,将js代码交给v8引擎运行。由于js本身可以进行dom操作(例如改变dom的状态),v8引擎会关联和影响DOM树的渲染过程。(tips:js会阻碍html文件的加载和DOM树的生成)。生成DOM树在之后,css代码开始交给css解释器开始运行,将DOM树变成RenderObject树进行布局计算(cc),然后获得RenderLayer树,得到绘图上下文之后,再找到css解释器,借助2D图形库3D图形库,画出最终图像

网页可视化过程对于前端开发的启示

  • 尽量减少HTTP请求次数
  • 减少DNS查找次数(图片服务器cdn加速)
  • 尽可能将图片资源压缩
  • 资源加载的速度不会影响DOM树的建立,因为他们都是异步的。但是js的URL除外,如果可以,请尽可能的使用<script async></script>
  • 如果js可能改变DOM,导致RenderObject树重绘,请尽可能提前加载
  • 如果js不会与DOM打交道,可以延迟加载

介绍下重绘和重排,以及如何优化

重绘重排参考文档
重绘:更新了元素的绘制属性,但是没有改变布局,重新把元素外观绘制出来的过程叫做重绘(例如:更改元素背景颜色)。和重排相比,重绘省去了布局和分层结算,所以执行效率比重排高
引起重绘的操作:
color border-style visibility text-decoration background-image outline box-shadow
重排(回流):更改元素的几何属性,浏览器需要重新计算元素的几何属性,将其放置在正确的位置,这个过程叫做重排(回流)。重排意味着节点的几何属性发生改变,需要重新计算并生成渲染树。
重排需要更新完整的渲染流水线,开销最大。
常见引起重排的属性和方法:
任何改变元素位置或者大小的操作(display:none);

  • 添加或删除可见的DOM元素
  • 元素尺寸改变
  • 内容变化,例如在input中输入文字
  • 浏览器窗口尺寸改变
  • 设置style属性的值
  • 激活css伪类
  • 查询某些属性活调用某些方法

cookie和token都存放在header中,为什么不劫持token

http协议本身是无状态的,所以需要一个标志来对用户身份进行验证
1,cookie
用户登录成功后,会在服务器存一个seesion,同时发给客户端一个cookie,这个cookie里面有唯一标识该用户的sessionID数据需要客户端和服务器同时存储
用户再进行请求操作时,需要带上cookie,在服务器进行验证。**cookie是有状态的**
2,token
用户进行任何操作时都需要带上一个token
token的存在形式很多种,header/request/body/url都可以
这个token只需要存在客户端,服务器在收到数据后,进行解析,**token是无状态的**

token对比cookie的优势

  • 支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的。
  • 无状态化,服务端无需存储token,只需要验证token信息是否正确,而seesion需要在服务端存储,一般通过seesionID在服务端查找对应的seesion;
  • 无需绑定到一个特殊的身份验证方案,只需要生成的token符合我们的预期即可。
  • 更适用于移动端,像这种原生平台不支持cookie。
  • 避免CSRF跨站伪造攻击,还是因为不依赖cookie
  • 非常适用于RESTful API,这样可以轻易与各种后端相结合,去耦合。

在项目中,我们通过设置

// 允许携带cookie
axios.defaults.withCredentials = true;

就可以在发送的接口中看到携带的cookie

攻击者通过XSS拿到用户的cookie,伪造cookie。或者通过csrf在同个浏览器下面通过浏览器会自动带上cookie的特性。
但是token不会被浏览器带上。
token是放在jwt里面发给客户端的,而且不一定存储在哪里,不能通过,document.token直接拿到,通过jwt+ip的方式可以防止被劫持,即使被劫持也是无效的jwt。

本地存储

【答】vuex,localStorage,seesionStorage,cookie
【续问】localStorage,seesionStorage,cookie的差别
【答】区别一:存储大小,cookie存储大小4K,localStorage和seesionStorage的存储大小是几M;
区别二:缓存时间
区别三:过期时间
【续问1】三个都支持设置缓存时间和清空缓存吗
【续问2】我们登录之后,会下发一些登录信息,每次请求都需要带回给后端,这些信息是存在在哪里比较合适呢?
【续问3】为什么存放在localStorage里面呢?放在localStorage里面合适吗?如何改进呢?

cookie ,localstorage,seesionstorage的区别和使用场景(2次)

cookie,localstorage,seesionstorage
cookie,localstorage,seesionstorage三者区别
区别一:cookie存放大小为4k,远小于其他两者。localstorage和seesionStorage大小为5M。
区别二:未特殊设置的情况下,cookie的时效是关闭浏览器之后失效,localstorage是关闭浏览器之后失效,seesionstorage是关闭当前会话失效。
区别三:
cookie存储的内容会保留在HTTP请求的header中,并且会随着每次请求发送到浏览器中。而本地存储只会存储在客户端本地,并不会在请求过程中发送到服务端。

如何开启强缓存

【答】有两个设置缓存的属性,E 和cache-
【续问】这两个属性的区别
【续问】协商缓存在什么情况下会返回304

htpp缓存—强缓存,协商缓存(什么时候出现200,304)

对于请求第二次的资源才会出现缓存
当第一次请求设置了强缓存就会缓存在本地,当第二次请求时,浏览器会现在本地查找是否有这个资源,并查看它的过期时间,如果没有过期则直接命中强缓存,如果过期了,会发出一个小流量的问询请求,携带资源的唯一标识(tag)询问服务器是否修改过该资源,服务器拿到请求携带的唯一标识和现在服务器上该资源的唯一标志做比对,如果修改过,服务器则响应200,并响应最新的资源文件。如果没有修改,则命中协商缓存,服务器返回304

web可视化相关内容

现在web可视化的方向

canvas svg webGL 。。。。
three.js

canvas和svg

场景:我现在想要做一个很复杂的table,table中存在很多的交互操作,还有图片上传之类的,hover有卡片效果的复杂table,使用DOM结构来绘制会比较耗费性能,现在我想使用可视化的技术来完成,你觉得应该选择canvas还是svg。
【答案】
canvas和svg的概念:

  1. canvas
    canvas是H5的新标签;
    canvas画布,利用javascript在页面绘制图像
    在标签中给上宽高;不用加单位
    如果在css中给宽高,会给图像造成拉伸
    通过绘制工具.getContext(“2d”)来再画布中绘制图形
  2. svg
    svg是可缩放矢量图形,基于可扩展标记预研XML出来的时间比较老
    svg用来定义用于网格的基于矢量的图形
    svg和canvas的区别

    1. 绘制的图片格式不同
      canvas的工具getContext绘制出来的图形或传入的图片都依赖分辨率,能够以.png和.jpg格式保存存储图像,可以说是位图svg可以在H5中直接绘制,但绘制的是矢量图。由于位图依赖分辨率,矢量图不依赖分辨率,所以canvas和SVG的图片格式的不同实际上也是他们绘制出俩的图片格式不同造成的。
    2. canvas不支持事件处理器,SVG支持事件处理器。
      canvas绘制的图像都在canvas这个画布里面,是canvas的一部分,不能使用js获取已经绘制好的图形元素。canvas就像动画,每次显示全部的一帧内容,想改变里面某个元素的位置或者变化需要在下一帧中全部重新绘制显示。
      SVG绘图时,每个图形都是以DOM节点的形式插入到页面中,可以用js或其他方法直接操作。
    3. 由于canvas和SVG的工作机制不同
      canvas是逐帧像素进行渲染的,一旦图形绘制完成,就不会继续被浏览器关注。而SVG是通过DOM操作来显示的。所以Canvas的文本渲染能力弱,而SVG是适合有大型渲染区域的应用程序,比如地图。
      而canvas最适合有许多对象要被频繁绘制的图形密集型游戏。
      而SVG由于DOM操作,在复杂度高的游戏应用中,会减慢渲染速度,所以不适合游戏应用。

浏览器关闭当前页面的事件是否能监听到,一种是通过关闭标签页,一种是通过关闭浏览器

前端性能优化(具体)

雪碧图,iconfont字体图标,图片压缩,图片,cdn加速。
【标准回答】
代码层面:
v-if和v-show区分使用场景
computed和watch区分使用场景
v-for遍历必须为item添加key,且避免同时使用v-if
长列表性能优化:Object.freeze
事件的销毁
图片资源懒加载
路由懒加载
第三方插件的按需引入
优化无限列表性能
服务端渲染SSRor预渲染
webpack层面:
Webpack对图片进行压缩
提取公共代码
模板预编译
提取组件的CSS
基础的Web技术优化
开启gzip压缩
浏览器缓存
CDN的使用

【续问】资源加载慢如何处理,cdn方面
【续问1】雪碧图中怎么处理加载你需要的小图
【答】在css中使用定位属性,把需要的小图坐标,宽高框出来进行展示
【续问2】是否有更优的方案(图片位置乱了,放大缩小占比)
可以参考文章 css雪碧图处理

大量数据的前端优化方案

大量数据的前端优化方案

减少dom操作提升性能的方法

【答】
css中定位position可以修改为translate动画方法,减少页面的重排。
如果需要在js中操作dom,尽量可以把操作集合在一次操作里面,不要多次操作。
新建dom的时候,把所有的dom元素组成一个对象之后,再一起插入页面。可以参照字符串拼接或者使用虚拟dom(dom片段)
依赖三方组件和三方插件
组件使用层面,什么时候加载数据,什么时候操作数据

怎么落实开发规范

【续问】如果有的同事就是不遵循规范,有强制措施让他遵循吗?而且你们定期去检查代码是否符合规范是否人力成本过高?
人工走查,文本记录,
【续问】如果是你来做这个规范,是否能做成自动化的?
eslint?但是eslint可以越过,能否禁止?
【续问】自动巡检仓库代码?软件测,不影响开发。

乾坤中跨组件跨应用的通信方式有哪些

【续问】乾坤共用组件方面

项目中处理跨域的方式

跨域的产生
跨域是由于浏览器的同源策略限制出现的,它是浏览器最核心也是最基本的安全功能,它的核心在于它认为任何站点安装的信赖内容是不可信的,他们应该只被允许访问来自同一站点的资源,而不是那些可能有恶意的资源。同源是指两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
同源策略又分为:DOM同源策略和XMLHttpRequest同源策略。
DOM同源策略,禁止对不同源页面DOM进行操作。
XMLHttpRequest同源策略,禁止使用XHR对象向不同源的服务器地址发起http请求。
不受同源策略限制的有:
1,页面中的跳转链接,重定向以及表单提交。
2,跨域资源引入是可行的,如:< ifram/> < script/>< img/>< link/>。js不能读写加载的内容
什么是同源策略
怎么解决同源策略
跨域的解决方案
1,document.domain降域
同源策略认为父域和子域属于不同的域,如:child1.a.com与a.com。可以通过设置document.domain = ‘a.com’,浏览器就会认为他们都是同一个源。现在想要实现以上两个页面之间的通信,两个页面必须都设置document.domain = ‘a.com’。
此方法的特点是:
1,只能在父域名与子域名之间使用,且将域名设置为a.com之后,不能再设置成child1.com。
2,存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞
3,这种方法只适用于cookie和iframe窗口。
2,JSONP
JSONP是JSON With Padding(填充式JSON或者参数式JSON)的简写。
JSONP的解决跨域的原理是动态创建script标签,然后利用script的src属性不受同源策略约束来实现跨域获取数据。
JSONP由两部分组成:回调函数数据。回调函数是用来处理服务器端返回的数据,回调函数的名字一般是在请求中指定的。
代码实现如下:

var script = document.creatElement('script');//创建script标签
script.src = "http://baidu.com?callback=foo";//设置src属性此方法的特点是:1,只能是get请求,不能是post请求2,可能被注入恶意代码,篡改页面内容,跨域采用字符串来过滤用来规避这个问题3,使用这种方法,只要是个网站都可以拿到b.com里面的数据,存在安全性问题。目前已知的有referer和token校验。

3,cors跨域资源共享
cors是一个W3C标准,全称为‘跨域资源共享’(Cross-originresource sharing)
它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而客服了AJAX只能同源使用的限制。
代码实现
需要在b.com里面添加响应头申明允许a.com的访问
Access-Control-Allow-Origin :‘http://a.com’
4,proxy
利用vue脚手架中自带的http-proxy代理程序来跨域访问
5,nginx反向代理

项目中对webpack的了解

【续问】loader的作用
【续问】plgus

平常如何对自己项目的经验和学习到的东西进行管理

1,进行笔记记录,包括电脑本地文档保存,CSDN博客文章,代码demo编写。

浏览器响应code码有哪些,分别是什么含义

http通信协议返回状态码

  1. 1XX(临时响应) --表示临时响应并需要请求者继续执行操作的状态码
    100 (继续)–请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分
    101(切换协议)—请求者已要求服务器切换协议,服务器已

100
200
301
302
304
400
404
500
505

vue源码篇

在vue中,子组件为何不可以修改父组件传递的prop?子组件怎么修改父组件中的数据?

因为Vue是单向数据流,为了保证数据的单向流动,便于对数据的追踪,出现了错误可以更加迅速的定位到错误发生的位置。
原因很简单,一个父组件下不只有你一个子组件。 同样,使用这份 prop 数据的也不只有你一个子组件。 如果每个子组件都能修改 prop 的话,将会导致修改数据的源头不止一处。
子组件为何不能修改父组件传递的props
所以我们需要将修改数据的源头统一为父组件,子组件像要改 prop 只能委托父组件帮它。从而保证数据修改源唯一
子组件可以通过父组件的自定义时间,通过$emit触发,让父组件自己更新父组件中的数据。或者使用parent获取到父组件的实例之后再去修改data。

vue父子组件加载的原理

首先我们了解单个组件的加载顺序是
beforeCreate -->created --> beforeMount -->mountd
那么嵌套的父子组件渲染的顺序是
父beforeCreate -->父created -->父beforeMount -->子beforeCreate -->子created --> 子beforeMount --> 子mounted --> 父mounted
子组件更新的顺序:
父beforeUpdate -->子beforeUpdate -->子updated -->父updated
父组件更新过程:
父beforeUpdate --> 父update
销毁过程:
父-

  1. 当父组件执行完beforeMount挂载开始后,会依次执行子组件的钩子,直到子组件全部mounted全部挂载到实例上,父组件才会进入mounted钩子。
  2. 子级触发事件,会先触发父级的beforeUpdate钩子,再去触发子级的beforeUpdateg钩子,下面又会先执行子级的updated钩子,后执行updated钩子。
    父组件先于子组件created,而子组件先于父组件mounted。

watch 和computed

  1. watch
    可以监控一个值的改变,并调用对应执行的方法,可以通过watch动态改变关联的状态,主要就是通过监听值的变化作出相应的事情。

  2. computed
    计算属性,只能对最终结果进行运算功能,只计算一次,具有缓存功能,能实现计算属性与普通属性之间的双向绑定。
    作用:

    1. 减少模块中的计算逻辑
    2. 能够进行数据缓存
    3. 响应式数据依赖固定的数据类型
    

watch和computed的区别

     1. computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据改变会直接触发对应的操作。2. computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化,而watch支持异步。3. computed属性值会默认走缓存,计算属性是基于他们的响应式依赖进行缓存的,也就是基于data中申明过或者父组件传递的props中的数据通过计算得到的值;而watch监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入的值。4. 如果一个属性是由其它属性计算而来的,这个属性依赖其它属性,多对一或者一对一,一般使用computed;而当一个属性发生变化时,需要执行对应的操作,一对多,一般用watch。

在vue中动态的引入图片为什么要使用require

【答】因为动态添加的src,编译过后的文件地址和被编译过后的资源文件地址不一致,从而无法正确引入资源。而使用require,返回的就是资源文件被编译后的文件地址,从而可以正确的引入资源。
【续】1,什么是静态资源
2,为什么动态添加的src会被当做静态的资源
3,什么编译过程
4,加上require为什么就能正确的引入资源了。
【答】1,什么是静态资源?
静态资源:客户端发送请求到web服务器,web服务器从内存中取到相应的文件,返回给客户端,客户端解析并渲染显示出来。
动态资源:客户端请求的动态资源,先将请求交于web容器,web容器连接数据库,数据库处理数据之后,将内容交给web服务器,web服务端解析渲染处理。
简单来说,在一个vue项目中。静态资源就是直接放在项目中的资源,这些资源不需要我们发送专门的请求进行获取。比如assets目录下的图片,视频,音频,css样式,文字字体等。动态资源就是需要发送请求获取到的资源。
2,为什么动态添加的src会被当作静态资源?
当项目运行vue项目时,需要先把vue项目进行打包,打包过程中就是将项目中的vue文件编译成html,css,js文件的过程。而后再在浏览器上运行。
我们可以发现,动态添加的src最终会编译成一个静态的字符串地址。程序运行的时候,会按照这个地址去项目目录中引入资源。而去项目目录中引入资源的这种方式,就是将该资源当成了静态资源。
3,编译过程?
因为动态添加的src编译后的地址,与图片资源编译过后的资源地址不一致,导致无法正确的引入资源。
4,require的作用
require是一个node方法,用于引入模块,json或本地文件。
当我们使用require方法引入一张图片的时候,webpack会将这张图片当成一个模块,并根据配置文件中的规则进行打包。我们可以将require当成一个桥梁,使用了require方法引入的资源,该资源就会当成模块并根据配置文件进行打包,并返回最终答打包结果。
【问】使用require方法引入一张图片之后发发生了什么?
【答】1,如果这张图片小于项目中设置的资源限制大小,则会返回图片的base64插入到require方法的调用处。
2,如果这张图片大于项目中设置的资源限制大小,则会将这个图片编译成一个新的图片资源。require方法返回新的资源路径以及文件名。
【问】为什么使用require能正确的引入资源
【答】因为通过require方法拿到的文件地址,是资源文件编译过后的文件地址(dist下生成的文件或base64文件),因此可以找到对应的文件,从而成功引入资源。
5,为什么使用public下的资源一定要决定路径
因为虽然public不会被编译,但是src下的文件都会被编译。由于引入的是public下的资源,不会走require,会直接返回代码中的定义的文件地址,该地址无法在编译后的文件目录(dist目录)下找到对应的文件,会导致引入资源失败。

参考文档

vue的响应式原理是什么

1,vue2通过object.defineProperty来实现监听数据的改变和读取(属性中的getter和seter方法),实现数据劫持
2,观察者模式(发布-订阅)观察者(订阅者) -Watcherupdate():当事件发生时,具体要做的事情目标(发布者)-Dep1,subs 数组:存储所有的观察者2,addSub();添加观察者3,notify(): 当事件发生,调用所有观察者的update()方法。
3,当数据发生改变通过发布订阅者模式来通知进行界面刷新

首先要对数据(data)进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器(发布者)Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。

【续问】发布订阅者模式时什么模式
【续问】观察者模式和发布订阅模式的区别
【续问】数组时怎么监听到响应式的
【续问】为什么监听不了新增的属性

vue响应式原理中Object.defineProperty有什么缺陷?为什么在vue3.0采用了Proxy,抛弃了Object.definePrototype?

我们在使用Object.definePrototype的时候,需要深层递归,绑定对象上的每一个属性。如果对象的层级比较深就会比较浪费性能。而且Object.definePrototype对于数组下标数据的修改,和对象的新增属性是不能建立响应式的,需要单独处理。
而Proxy是对整个对象进行了代理,性能上比较起来更优了。

在dom中,数据和vue中的数据如何进行双向绑定,它的原理是什么,(比如现在有个组件,在渲染的时候,怎么对数据和页面实现双向绑定)

【续问1】vue2和vue3在数据劫持方向有什么性能方面的差异
vue2的数据劫持需要深度递归,新添加的属性不能直接响应式。数组重写了7个方法。
vue3的数据劫持是劫持的整个对象。
vue3的性能更好,但是它的兼容性没有vue2好

路由有哪些模式

【续问】hash模式和histroy模式有什么区别
【续问】hash模式和histroy模式有什么区别

vue2和vue3的响应式原理的区别,优缺点。

proxy的优点:

  1. proxy可以直接监听对象而非属性
  2. proxy可以监听数组的变化
  3. proxy有多达13中拦截方法,不限于apply,oenKeys,delete Property,has等等
  4. proxy返回的是一个新对象,我们可以只操作新对象达到目的,而object.defineprototype只能遍历对象属性直接修改
  5. proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。
    object.defineprototype的优势
  6. 兼容性好,支持IE9。

高内聚低耦合

在软件设计中。通常用耦合度和内聚度作为衡量模块独立的标准。划分模块的一个准则是高内聚低耦合。
从模块粒度看,高内聚:尽可能类的每一个成员方法只完成一件事情(最大限度的聚合);低耦合:减少类内部,一个成员调用另一个成员方法。
类角度来看,高内聚低耦合:减少类内部对其他类的调用;
功能模块来看,高内聚低耦合:减少模块之间的交互复杂度(接口数量,参数数据)即横向:类与类之间,模块与模块之间;纵向:层次之间;尽可能,内容内聚,数据耦合。
降低耦合度的方法
1,少使用类的继承,多用接口隐藏实现的细节。
2,模块的功能划分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。
3,遵循一个定义只在一个地方出现。
4,少使用全局变量。
5,类属性和方法的声明少用public,多使用private关键字。
6,多用设计模式,比如采用mvc的设计模式就可以避免降低界面与业务逻辑的耦合度。
7,最后当然就是避免直接操作或调用其他模块或类(内容耦合);如果模块之间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。
增强内聚度的方法
1,模块只对外暴露最小限度的接口,形成最低的依赖关系。
2,删除一个模块,应当只影响有依赖关系的其他模块,而不应该影响其他无关部分。
3,只要对外接口不变,模块内部的修改,就不得影响其他模块。

在共用组件的时候需要用到new吗

Vue作为个单页面实际只new了一次,后续组件都是通过this._init创建的实例

前端模块化解决了哪些问题?

各个模块的命名空间独立,A模块的变量不会覆盖B模块的变量。
模块的依赖关系通过模块管理工具(如webpack,require.js)进行管理

使用nuxt或者next进行服务端渲染,如何避免因代码逻辑错误或数据不一致造成服务器渲染报错,导致页面无法访问的问题?

  1. 服务端渲染函数内部进行整体代码try catch,遇到错误情况直接return一个空模板数据格式的对象
  2. 使用koa内核的情况下使用一个全局错误处理中间件
  3. ssr降级渲染,服务端发生错误时降级为客户端渲染

实际项目中做过导出pdf

场景题

假如我现在有一个输入框,我是产品身份,要求输入框内只能输入金额相关的东西。你会怎么去实现,会考虑什么东西?拿到需求之后怎么想的,怎么做的假如现在现在有个接口,返回数据量很大,有几万的数据量,怎么优化。

版本管理

场景
从dev分支拉取一个新的分支,开发之后需要合并到dev分支上去,请说一下你的git代码合并的命令

试题篇

大数相加

大数相加
题目描述
​let a = “9007199254740991.123498594”;​
let b = “1234567899999999999.123455498594”;​

function add(a ,b){​//...​
}​

千位数

给定两个数组,写一个方法来计算它们的交集

例如:给定两个数组nums1=[1,2,2,1],nums2 = [2,2],返回[2,2]
解法1:

let newArray = [];
nums1.forEach((item)=>{if(nums2.indexOf(item)){newArray .push(item);nums2.splice(nums2.indexOf(item),1)}
})
return newArray;

数组里面有10万个数据,取第一个元素和第n个元素的时间差是多少?

时间差为0,因为数组是使用索引取值,取任何索引值的元素的速度是一致的。

请输出下面代码结果

var a = 10;
(function(){console.log(a);a = 5;console.log(window.a)var a = 20;console.log(a)
})()

勇往直前的菜鸟修炼手册相关推荐

  1. java修炼手册3.8_Java修炼手册

    <Java修炼手册免费版>是一款专为想要自学JAVA的用户打造的全方位掌上学习软件,拥有各阶段的科学课程模块,从视频,资料,图片,演示等多种方面全面引导用户科学而快速的融入JAVA的世界中 ...

  2. 谈谈AI的ToB市场,我的新书《B端产品经理修炼手册》正式出版

    2020年是特殊的一年,得益于这次疫情,在2月份有一个大长假,当时被封锁在东北老家的小出租屋内,于是就起笔开始写这本书,其实也是在心理早就有构思的,差不多用了十来天的时间完成了第一版.名字想了好久,最 ...

  3. 命令构建gradle项目_【Android 修炼手册】Gradle 篇 -- Gradle 源码分析

    预备知识 理解 gradle 的基本开发 了解 gradle task 和 plugin 使用及开发 了解 android gradle plugin 的使用 看完本文可以达到什么程度 了解 grad ...

  4. 【Android 修炼手册】常用技术篇 -- 聊聊 Android 的打包

    这是[Android 修炼手册]系列第 10 篇文章,如果还没有看过前面系列文章,欢迎点击 这里 查看- 预备知识 了解 android 基本开发 看完本文可以达到什么程度 了解 Android AP ...

  5. 【Android 修炼手册】常用技术篇 -- Android 自定义 View

    这是[Android 修炼手册]系列第 9 篇文章,如果还没有看过前面系列文章,欢迎点击 这里 查看- 预备知识 了解 android 基本开发 看完本文可以达到什么程度 学会自定义 View 以及其 ...

  6. 【Android 修炼手册】常用技术篇 -- Android 热修复解析

    这是[Android 修炼手册]第 8 篇文章,如果还没有看过前面系列文章,欢迎点击 这里 查看- 预备知识 了解 android 基本开发 了解 ClassLoader 相关知识 看完本文可以达到什 ...

  7. 【Android 修炼手册】常用技术篇 -- Android 插件化解析

    预备知识 了解 android 基本开发 了解 android 四大组件基本原理 了解 ClassLoader 相关知识 看完本文可以达到什么程度 了解插件化常见的实现原理 阅读前准备工作 clone ...

  8. 【Android 修炼手册】Gradle 篇 -- Gradle 源码分析

    预备知识 理解 gradle 的基本开发 了解 gradle task 和 plugin 使用及开发 了解 android gradle plugin 的使用 看完本文可以达到什么程度 了解 grad ...

  9. 【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要 Task 分析

    上文回顾 上篇文章里讲了 android gradle plugin 的整体流程,引入插件以后生成了很多 Task,这篇文章就谈谈生成的这些 Task 都有什么用处,以及一些主要 Task 的实现 预 ...

最新文章

  1. [MATLAB]从已知矩阵中取出子阵
  2. jsp中include指令和动作的区别
  3. activiti 工作流 springboot 后台框架平台 集成代码生成器 shiro 权限
  4. smarty半小时快速上手教程
  5. 在Exchange 2010中重建Exchange安全组
  6. apollo 配置中心_.NET Core 下使用 Apollo 配置中心
  7. java中的v递归的思想,Java中的递归思想 - osc_9lqilnv7的个人空间 - OSCHINA - 中文开源技术交流社区...
  8. init.d目录理解
  9. python要记多少个单词是合理的_词汇量少的人每天背多少单词合适?
  10. 基于 c++ 语言的简易 vim 编辑器
  11. bat复制文件到指定目录同名_利用bat让文件在指定时间自动进行备份
  12. java list 包含字符串_Java8实战:查找列表中包含的字符串
  13. 非计算机专业怎么准备蓝桥杯,大三接触算法,用寒假时间准备蓝桥杯,如何提高成绩?...
  14. php获取当前协议domain,汇总php获取根域名方法($_SERVER['SERVER_NAME']、GetUrlToDomain)...
  15. Python实现简单p2p下载
  16. springboot使用jdbc连接mysql数据库时测试连接错误
  17. SQLT(SQLTXPLAIN)
  18. 麦克斯韦方程组的组成由来、媒介的电磁性质和边界条件
  19. HTML写一个登录框样式
  20. Android RecyclerView之RecycledViewPool、SortedListAdapter

热门文章

  1. jenkins执行远程服务器命令返回code127解决办法
  2. SQL Server2019重新下载失败
  3. 大数据企业面试真题汇总一
  4. sql2000 mysql 兼容_sql2005兼容2000 | 向后兼容组件
  5. ISO 3166-1代码列表
  6. [渝粤教育] 东北财经大学 财务管理 参考 资料
  7. 谁能想到微软CRM也能用上SliverLight?——微软CRM炫酷介绍之二
  8. java的stackoverflow_call stack - 导致java.lang.StackOverflow的原因
  9. fastapi、flask和tornado对获取请求IP的探索
  10. 7-8 整数四则运算 (10分)