1、基础数据类型
基本数据类型共有6种。字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined),Symbol 类型, BigInt。
2、如何判断是否为数组
1、Array.isArray();
2、var arr=[];
console.log(arr instanceof Array) //返回true
3、console.log([].constructor === Array) // true
4、Object.prototype.toString.call(arr) === '[object Array]' // true
3、new 对象的底层逻辑
1、以构造器的prototype属性为原型,创造一个新的、空的对象
2、 将它的引用赋给构造器的 this,同时将参数传到构造器中执行
3、 如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象。
4、从浏览器输入地址到页面加载的过程
-
输入地址
-
DNS解析获取域名对应的IP地址
## 请求一旦发起,浏览器首先要做的事情就是解析这个域名。 1、一般来说,浏览器会首先查看本地硬盘的 hosts 文件,看看其中有没有和这个域名对应的规则,如果有的话就直接使用 hosts 文件里面的 ip 地址。 2、如果在本地的 hosts 文件没有能够找到对应的 ip 地址,浏览器会发出一个 DNS请求到本地DNS服务器 。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动。 3、查询你输入的网址的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果,此过程是递归的方式进行查询。如果没有,本地DNS服务器还要向DNS根服务器进行查询。 4、根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。这种过程是迭代的过程。 5、本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。 6、最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。- 建立TCP连接
## 在HTTP工作开始之前,web浏览器首先要通过网络与web服务器建立连接,该连接是通过TCP来完成的。 -
浏览器向服务发送请求
-
服务器的永久重定向响应
## 服务器给浏览器响应一个301永久重定向响应,这样浏览器就会访问“http://www.google.com/” 而非“http://google.com/”。 -
浏览器跟踪重定向地址
-
服务对请求做出应答。
-
浏览器显示HTML
## webkit下 解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树 -
浏览器发送获取资源
其实这个步骤可以并列在步骤8中,在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件。比如我要获取外图片,CSS,JS文件等,类似于下面的链接: 图片:http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif CSS式样表:http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css JavaScript 文件:http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js 这些地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等... 不像动态页面,静态文件会允许浏览器对其进行缓存。有的文件可能会不需要与服务器通讯,而从缓存中直接读取,或者可以放到CDN中 -
服务器关闭tcp连接
-
5、vue的diff算法和 React的diff算法的区别
vue和react的diff算法,都是忽略跨级比较,只做同级比较。vue diff时调动patch函数,参数是vnode和oldVnode,分别代表新旧节点。
1.vue对比节点。当节点元素相同,但是classname不同,认为是不同类型的元素,删除重建,而react认为是同类型节点,只是修改节点属性。
2.vue的列表对比,采用的是两端到中间比对的方式,而react采用的是从左到右依次对比的方式。当一个集合只是把最后一个节点移到了第一个,react会把前面的节点依次移动,而vue只会把最后一个节点移到第一个。总体上,vue的方式比较高效。
6、diff算法中 key的作用是什么
key是虚拟DOM 对象的标识
当状态发生改变时, 会根据新的数据生成新的虚拟DOM, 并与旧的虚拟DOM进行比较
旧虚拟DOM中找到与新虚拟DOM中相同的key
若虚拟DOM中内容没有改变, 直接使用之前的真实DOM
若虚拟DOM中的内容发生改变, 则生成新的真实DOM, 随后替换页面中的真实DOM
旧虚拟DOM中未找到与新虚拟DOM中相同的key
根据数据创建新的真实DOM, 随后渲染到页面
使用index作为key可能引发的问题
对数据进行逆序添加、删除等【破坏顺序】的操作时
产生没有必要的真实DOM更新
如果结构中包含输入类DOM
7、CSS的 bfc
块级格式化上下文,是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响
8、给定一个事件循环的js,判断出调用的步骤
1. 执行同步任务
1.1 异步任务队列
1.1.1 宏任务, 微任务
2. 执行完同步任务
2.1 清空微任务
2.2 执行 一个 宏任务
2.3 执行所有微任务
// 实例1
setTimeout(() => {
console.log("4");
setTimeout(() => {
console.log("8");
}, 0);
new Promise((r) => {
console.log("5");//构造函数是同步的
r();
}).then(() => {
console.log("7");//then()是异步的,这里已经入队
});
console.log("6");
}, 0);
new Promise((r) => {
console.log("1");//构造函数是同步的
r();
}).then(() => {
console.log("3");//then()是异步的,这里已经入队
});
console.log("2");
//输出顺序:1 2 3 4 5 6 7 8
// 实例2
setTimeout(function(){
console.log('1');
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3');
});
console.log('4');
//输出顺序:2 4 3 1
// async/await
async function async1() {
// 同步
console.log("1");
// 会卡在这等执行完才往下走
await new Promise((resolve) => {
// 同步
console.log("2");
// 微任务 -> 跳出去再正常执行其他代码
resolve();
}).then(() => {
console.log("3");
});
console.log("13");
// 多个 await promise
await new Promise((resolve) => {
// 同步
console.log("4");
// 微任务 -> 跳出去再正常执行其他代码
resolve();
}).then(() => {
console.log("5");
});
// await async2();
console.log("6");
}
async function async2() {
// 同步
console.log("7");
}
// 从这开始
async1()
// 等到 async 函数内 await 后所有的 promise 都执行完才执行
.then(console.log);
// 同步代码
console.log("8");
new Promise((resolve) => {
// 同步代码
console.log("9");
// 微任务
resolve();
}).then(() => {
console.log("10");
});
// 宏任务
setTimeout(() => {
console.log("11");
}, 0);
// 同步代码 -> 再回去 清空 微任务
console.log("12");
// 1, 2, 8, 9, 12, 3, 10, 13, 7, 6, undefined, 11
// 第二个是 promise
// 1, 2, 8, 9, 12, 3, 10, 13, 4, 5, 6, undefined, 11
9、手写深拷贝
function deepCopy(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj //原始值
if (obj instanceof Date) return new Date(obj) //日期值
if (obj instanceof RegExp) return new RegExp(obj) //正则
if (cache.has(obj)) return cache.get(obj) //防止循环引用情况
let copyObj = new obj.constructor() //创建一个和obj类型一样的对象
cache.set(obj, copyObj) //放入缓存中
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copyObj[key] = deepCopy(obj[key], cache)
}
}
return copyObj
}
const obj = {
name: 'Jack',
address: {
x: 100,
y: 200
}
}
obj.a = obj
let copyObj = deepCopy(obj)
console.log(copyObj)
console.log(copyObj.address === obj.address) //false
// 简单的深拷贝, 不能拷贝函数
const deepClone = (origin) => {
if (typeof origin === "object" && origin !== null) {
let target = Array.isArray(origin) ? [] : {};
for (let prop in origin) {
target[prop] = deepClone(origin[prop]);
}
return target;
} else {
return origin;
}
};
10、vue和react的区别
1. 核心思想不同
Vue早期开发就尤雨溪大佬,所以定位就是尽可能的降低前端开发的门槛,让更多的人能够更快地上手开发。这就有了vue的主要特点:灵活易用的渐进式框架,进行数据拦截/代理,它对侦测数据的变化更敏感、更精确。
React 从一开始的定位就是提出 UI 开发的新思路。背靠大公司Facebook 的React,从开始起就不缺关注和用户,而且React想要做的是用更好的方式去颠覆前端开发方式。所以React推崇函数式编程(纯组件),数据不可变以及单向数据流,当然需要双向的地方也可以手动实现, 比如借助onChange和setState来实现。
由于两者核心思想的不同,所以导致Vue和React在后续设计产生了许多的差异。
2. 组件写法差异
React推荐的做法是JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中,即 all in js; Vue 推荐的做法是 template 的单文件组件格式(简单易懂,从传统前端转过来易于理解),即 html,css,JS 写在同一个文件(vue也支持JSX写法)
这个差异一定程度上也是由于二者核心思想不同而导致的。
3. diff算法不同
11、vue 和react 传值的不同方式
# Vue
* props
* 事件总线
* 自定义方法
* vuex
# React
* props
* redux
* 自定义方法
12、说出es5和es6数组方法并筛选出纯函数。
相同的输入总会得到相同的输出
const arr = [1,2,3,4]; arr.slice(0,3)重复执行得到的结果是相同的const arr = [1,2,3,4]; arr.splice(0,1)重复执行的结果不一致
push() 从队尾添加,改变原数组
pop() 移除数组末尾最后一项,返回移除的项
shift() 删除数组第一项,返回删除元素的值,如果数组为空返回undefined
unshift() 添加头部,改变原数组
sort() 数组排序,参数为一个匿名函数,如果匿名函数返回正值,则升序排列,反之相反
reverse() 翻转数组项的顺序 原数组改变
concat() 将参数添加到原数组,将参数添加到数组的末尾,并返回一个新数组,不改变原数组
slice() 返回原数组中指定开始下标到结束下标之间的项组成的新数组,slice接受两个参数,如果致谢一个参数,slice方法返回从该参数到数组末尾的所有项,如果有两个参数,该方法返回起始位置和结束位置之间的项,但不包括结束位置的项
splice() 可以实现删除,插入,替换 删除(可以删除任意属相的项,只需要指定2个参数,要删除的第一项的位置和要删除的项) 插入,替换(可以向指定位置插入任意数量的项,只需提供3个参数:起始位置,0(要删除的项),插入的项),splice()方法始终都会返回一个数组,数组中包括从原数组中删除的项,如果没有删除任何项则返回一个空数组
some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就返回true
every() 判断数组中每一项都是否满足条件,只有所有选项都满足条件,才会返回true
filter() 过滤功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组
forEach() 对数组进行循环遍历,对数组中的每一项运行给定函数,这个方法没有返回值,参数都是function类型,默认有传参功能,参数分别是,便利的数组内容,对应的索引,数组本身
indexOf() 接受两个参数,要查找的项和表示查找起点位置的索引,返回查找的项在数组的位置,没找到的情况下返回-1
13、vue2和vue3区别?
#### 一、响应式原理
响应式作为vue关键的特性,vue3在vue2上也有很多提升。
vue2:Vue2 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。
Vue2是使用Object.defineProperty,它只能劫持对象的属性,所以它需要深度遍历data中的每个属性,这种方式对于数组很不友好,而且对象观测后,新增的属性就不是响应式的,不过可以用Vue.set()来添加新的属性;
vue3:是使用Proxy,Proxy可以劫持整个data对象,然后递归返回属性的值的代理即可实现响应式;代理对象和反射对象要相互配合来实现响应式。
vue3其实实现了深层检测
#### 二:定义区别
在vue2中定义数据变量是data(){},创建的方法要在methods:{}中。(但其实在企业的项目中都是vue2结合ts,都是直接定义变量和函数,是不需要书写到data(){}内部的。
而在vue3中直接在setup(){}中,在这里面定义的变量和方法因为最终要在模板中使用,所以最后都得return。如果没有return该变量,是无法使用的。
#### 三、生命周期不同
* vue2中的生命周期
* beforeCreate 组件创建之前
* created 组件创建之后
* beforeMount 组价挂载到页面之前执行
* mounted 组件挂载到页面之后执行
* beforeUpdate 组件更新之前
* updated 组件更新之后
* vue3中的生命周期
* setup 开始创建组件
* onBeforeMount 组价挂载到页面之前执行
* onMounted 组件挂载到页面之后执行
* onBeforeUpdate 组件更新之前
* onUpdated 组件更新之后