防抖: slice. 手写一个深拷贝:
HTMl-CSS
HTML的标签有哪些,行内,块有哪些,区别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1、标题:h1~h6
2、段落:p
3、HTML 文本格式化标签:b,strong,i,em,s,del,u,sup,sub,hr,行内
4、HTML 中的特殊符号:`<`,`>`,` `,`©`,`™`,`®`
5、区:div(块) 和 span(行内)
6、列表:ol + li,ul + li,dl + dt + dd
7、图片:img,行内
8、超链接:a,行内
9、HTML 表格:table,caption,th,tr,td
10、HTML 表单:form,input,label,select + option,button
11、框架 iframe
12. 语义化标签:增加了一套新的语义化元素
13. audio和ideo标签
windows下面有那些属性或者方法
- dom(document,文档对象模型)
- bom(browser object model)浏览器对象模型
- window.open,window.close()
- location
- history;length,back,forward,go
- screen
- navigator(浏览器的信息,各种方法)
- frames
- settimeout,setinterval
- addEventListener,removeEvenListener
css的布局知道哪些,flexbox。
flexbox:给元素设置display:flex,则可以将盒子转变成flexbox。可以通过flex-direction改变指向,flex-warp:warp确定是否换行,flex属性有三个参数,分别是flex-grow,flex-shrink,flex-base。还可以通过order属性来控制每个flexitem的显示。
在子元素上可以使用flex来设置浮动的 display:flex。
css的选择器有哪些
id,类,标签 我会使用scss这个css框架进行开发,这类sass的语言写法支持css 的嵌套,编译得到的选择器,是
- 后代选择器(#box div),选择id为box元素内部所有的div元素
- 子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素。这个只选择一层,不会深入
Css
预编译语言有这几个重要的特性:、
- 变量
- 混入(mixin)
Sass
声明mixins
时需要使用@mixinn
,后面紧跟mixin
的名,也可以设置参数,参数名为变量$
声明的形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
高级技巧。
WeakSet和WeakMap都是弱引用 弱引用是不能确保其引用的对象不会被垃圾回收器回收的引用,而强引用是确保其引用的对象不会被垃圾回收器回收的引用。
- 其他
对数组的遍历大家最常用的就是for循环,ES5的话也可以使用forEach,ES5具有遍历数组功能的还有map、filter、some、every、reduce、reduceRight等,只不过他们的返回结果不一样。但是使用foreach遍历数组的话,使用break不能中断循环,使用return也不能返回到外层函数。
项目优化
- 封装了那些组件,实现了那些功能
- 对
Vue
vue的典型特征是
- 数据驱动
- 组件化
- 指令
- 没有指令之前,我们操作dom是先使用document来获取dom,再进行后续操作。
- 有了指令以后,就可以直接在标签上写对应的方法了v-on(@),以及绑定对应的响应式数据v-bind(:)
- 条件渲染指令
v-if
- 列表渲染指令
v-for
,在v-for
的时候,建议设置key
值,并且保证每个key
值是独一无二的,这便于diff
算法进行优化
c1:vue3和vue2 的区别。
- vue3:更快,更小。更好的typescript支持,使用proxy代替vue2的Object.defineProperty。
- 引入了组合式api,仍然支持选项式api。
- v-for的优先级高于v-if。
c2:watch和computed的区别:
watch
watch
是观察者,它允许你指定一个选项来监听Vue实例上的数据或计算属性。当被监听的数据发生变化时,可以执行一些操作。watch
的特性如下:
- 非缓存性:每次被监听的数据变化时,都会执行对应的函数。
- 异步性:在Vue 3中,
watch
的默认行为是异步的,这意味着监听的数据变化不会立即触发回调函数,而是在下一个微任务中执行。
computed
computed
是计算属性,它们是依赖于Vue实例的数据的。当依赖的数据发生变化时,计算属性会自动重新计算。computed
的特性如下:
- 缓存性:只有当依赖的响应式数据发生变化时,计算属性才会重新计算。这意味着如果计算属性的依赖没有变化,访问计算属性将立即返回之前的计算结果,而不必再次执行计算。
- 响应式:计算属性是基于它们的依赖进行缓存的。如果依赖项之一发生变化,计算属性将重新计算。
- 依赖收集:对于
computed
属性,Vue会遍历它们并为每个属性创建一个依赖收集器(Dep
)实例。依赖收集器负责管理该属性的依赖关系。
vue的响应式原理
vue在为data设置响应式,通过Onject.definePropoty(vue2.x)或者Proxy(vue3.x)。之后,为computer中依赖的数据添加监听。
vue的NextTick这个api
nexttick这个api是用来实现在
计算机网络
http和https的区别,tcp和udp的区别。
TCP 是面向连接的协议,建立连接3次握手、断开连接四次挥手,UDP是面向无连接,数据传输前后不连接连接,发送端只负责将数据发送到网络,接收端从消息队列读取。
UDP
与 TCP
两者的都位于传输层
性质层面
tcp是可靠的,udp不可靠。
tcp是面向连接的,需要三次握手。
tcp是全双工的,udp则可以一对一,一对多,多对一,对对多等等。
tcp的报文头是20个字节,而udp只有8个字节,传输开销小。
应用层面
TCP 应用场景适用于对效率要求低,对准确性要求高。
udp可以在直播,视频里面使用。
讲一下tcp三次握手
上述每一次握手的作用如下:
- 第一次握手:客户端发送网络包,服务端收到了 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手:服务端发包,客户端收到了 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常
- 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常
通过三次握手,就能确定双方的接收和发送能力是正常的。之后就可以正常通信了
为什么不是两次握手?
如果是两次握手,发送端可以确定自己发送的信息能对方能收到,也能确定对方发的包自己能收到,但接收端只能确定对方发的包自己能收到 无法确定自己发的包对方能收到
并且两次握手的话, 客户端有可能因为网络阻塞等原因会发送多个请求报文,延时到达的请求又会与服务器建立连接,浪费掉许多服务器的资源
get和post的区别
- get和post最主要的区别是get的请求体为空。post通常使用来客户端发送数据给服务端(我的浅薄理解)。
- get是幂等的,post是非幂等的。
JavaScript
实现数组去重
- 利用set的特性,不重复来实现。
1
2
3
const arr = [1, 2, 3, 1, 2, 3, 1, 1]
const newArr = [...new Set(arr)]
console.log(newArr);
- 使用indexOf返回的下标来去重。
1
2
3
4
5
const arr = [1,2,3,3,3,3,4]
const newArr = []
newArr.filter((item,index) => {
return arr.indexOf(item) === index
})
- 不使用数据结构以及js特有的api实现去重。
1
2
3
4
5
6
7
8
9
10
let i; let j; let len = arr.length
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
len--
j--
}
}
}
for. of 和for . in 的区别
for in 应用于数组循环返回的是数组的下标 、属性和原型上的方法和属性,而for in应用于对象循环返回的是对象的属性名和原型中的方法和属性。
for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。 所以for in更适合遍历对象,不要使用for in遍历数组。
数组的方法
增删改差等操作
- push,unshift,splice(粘合),concat
- pop,shift,splice,slice
- splice
- indexOf,inclulds,find ;排序
- reverse,sort ;转换
- join ,迭代的等。
- forEach,map,sort,filter,every,some
隐式转化/显示转换
显示转换,即我们很清楚可以看到这里发生了类型的转变,常见的方法有:
- Number()
- parseInt()
- String()
- Boolean()
在隐式转换中,我们可能最大的疑惑是 :何时发生隐式转换?
我们这里可以归纳为两种情况发生隐式转换的场景:
- 比较运算(
==
、!=
、>
、<
)、if
、while
需要布尔值地方 - 算术运算(
+
、-
、*
、/
、%
)
除了上面的场景,还要求运算符两边的操作数不是同一类型
自动转换为布尔值
在需要布尔值的地方,就会将非布尔值的参数自动转为布尔值,系统内部会调用 Boolean
函数
可以得出个小结:
- undefined
- null
- false
- +0
- -0
- NaN
- ""
除了上面几种会被转化成 false
,其他都会被转化成 true
原型链
面试官又追问, var a = new A(),a 和 A 的关系,A 和 Function 的关系
a 是 A 的一个实例对象,a 的
__proto__
指向 A 的prototype
,A 的__proto__
指向 Function 的prototype
。
作用域
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合
换句话说,作用域决定了代码区块中变量和其他资源的可见性 我们一般将作用域分成:
- 全局作用域
- 函数作用域
- 块级作用域
我们写好代码时它的作用域就确定了,JavaScript
遵循的就是词法作用域,也叫静态作用域。
实现水平居中的方式
- 利用flexbox的方法,父元素创建flexbox;
- 子元素的height = lineheight。
实现对给定对象数组,找到其中id为1的所有元素。
1
2
3
4
5
6
arr = [{id:1,code:23},{id:2,code:989}]
function(arr){
if(arr instanceofof Array === false) return;
}
判断数据类型
- typeof 判断基本数据类型
- instanceof 判断复杂数据类型;这种方法是利用左边对象的propotype
- Object.propotype.toString.call()判断所有。
事件和事件流,冒泡,捕获
事件流有多种形式,例如冒泡。 事件流分为3个阶段:
- 事件捕获
- 事件触发
- 事件冒泡 事件代理(事件委托)可以通过对父元素设置监听,批量对子元素进行监听。 优点:使用事件委托存在两大优点:
- 减少整个页面所需的内存,提升整体性能
- 动态绑定,减少重复工作 适合对click进行事件监听
Ajax
实现 Ajax
异步交互需要服务器逻辑进行配合,需要完成以下步骤:
- 创建
Ajax
的核心对象XMLHttpRequest
对象 - 通过
XMLHttpRequest
对象的open()
方法与服务端建立连接 - 构建请求所需的数据内容,并通过
XMLHttpRequest
对象的send()
方法发送给服务器端 - 设置实例对象的一个方法,这个方法有一个特性:每次进入一个新的传输阶段的时候,都会执行这个方法;知道最后传入的code变成4后,表示收到了服务服务端的回答,可以对status进行判断,在[200,300]之间表示正常,400则打印错误内容。
dom操作
document.createElement('li')
element.appendChild(element)
document.queryselect(css选择器)。
document.querySelectAll(css选择器)
js的事件循环
** 事件循环是实现js异步编程的核心方法,通过监听任务队列以及执行任务队列中的任务来实现的。 **
事件循环中的执行顺序
JavaScript 事件循环的执行顺序可以概括为:
- 执行所有同步代码。
- 执行完同步代码后,检查微任务队列,如果有微任务,按顺序执行所有微任务。
- 检查宏任务队列,取出队首的宏任务执行。
- 宏任务执行完毕后,再次检查微任务队列,如果有微任务,再次执行所有微任务。
- 重复步骤3和4,直到宏任务队列为空。
js的原型
在JavaScript中,每个对象都有一个内部属性([[Prototype]]
)
类似于其他编程语言,例如c#,java中的继承。它们实现继承通过类,我们通过原型链。
浏览器里面通过__proto__来修改原型,在实例身上。
对象的属性和方法查找会沿着原型链向上进行。
js原型是js中实现继承和属性共享的一个js对象。
面试官又追问, var a = new A(),a 和 A 的关系,A 和 Function 的关系
a 是 A 的一个实例对象,a 的
__proto__
指向 A 的prototype
,A 的__proto__
指向 Function 的prototype
。
逐字稿:
"JavaScript是一种基于原型的语言,这意味着每个对象在创建时都会关联到一个原型对象。这个原型对象可以包含属性和方法,而所有引用了这个原型的对象都会共享这些属性和方法。这种机制允许我们创建可复用和可扩展的代码。
在JavaScript中,每个对象都有一个内部属性 [[Prototype]]
,它指向其原型。当我们尝试访问一个对象的属性或方法时,如果该属性或方法在对象本身上不存在,JavaScript引擎就会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的末端。
开发者可以通过 __proto__
属性或者 Object.getPrototypeOf()
方法来访问一个对象的原型。同样,我们可以使用 Object.setPrototypeOf()
方法来修改一个对象的原型。
例如,当你创建一个数组并调用 .push
方法时,这个方法实际上定义在数组的原型上。这就是原型链的威力,它允许我们在整个对象类型中共享方法。"
js的闭包
注意:这里需要结合静态作用域来描述 js它采用的是静态作用域:函数能访问哪些东西,在你定义的时候就确定好了 创建一个函数的时候,这个一个函数能够记住它创建时的词法作用域,即使该函数在其原始作用域之外被执行。
使用场景:
- 数据封装和隐私: 闭包可以用来创建私有变量,这些变量不能从外部函数直接访问。
- vue的响应式原理利用到了闭包
几个大的概念:静态作用域(词法作用域)js采用,动态作用域
每一个函数创建之初,都会创建一个闭包。
柯里化函数
柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用
1
2
3
4
5
6
7
8
9
10
11
12
13
// 我们可以使用闭包柯里化这个计算面积的函数
function getArea(width) {
return height => {
return width * height
}
}
const getTenWidthArea = getArea(10)
// 之后碰到宽度为10的长方形就可以这样计算面积
const area1 = getTenWidthArea(20)
// 而且如果遇到宽度偶尔变化也可以轻松复用
const getTwentyWidthArea = getArea(20)
从代码中可以发现,箭头函数同样存在闭包。
逐字稿:
"闭包是一个函数和其周围的状态(词法环境)的组合。在JavaScript中,函数总是能够访问它们在哪里被创建的作用域,即使它们在那个作用域之外被调用。这就是所谓的词法作用域,它是在函数定义时决定的。
闭包的主要特点是它们可以捕获外部函数的变量,即使外部函数已经执行完毕。这意味着闭包可以存储和操作那些在函数外部定义的变量,这为数据封装和创建私有变量提供了一种机制。
例如,当我们在函数内部定义另一个函数,并在外部函数执行完毕后返回这个内部函数时,就创建了一个闭包。这个内部函数可以访问外部函数的变量,即使外部函数已经不在其作用域内。
闭包在许多现代JavaScript应用程序中都有广泛的应用,包括数据封装、模块模式实现、和一些库和框架的核心机制,比如Vue.js的响应式系统。"
js中的this
JavaScript 中的 this
在JavaScript中,this
关键字指的是当前上下文环境中的一个对象。this
的值在函数被调用时确定,它取决于函数是如何被调用的,而不是在哪里定义的。
- 全局上下文:在全局函数中,
this
通常指向全局对象(在浏览器中是window
对象)。 - 方法调用:当函数作为对象的方法调用时,
this
指向调用该方法的对象。 - 构造函数:在构造函数中,
this
指向新创建的对象。 - 事件处理:在事件处理函数中,
this
指向触发事件的对象。 - 箭头函数:箭头函数不绑定自己的
this
,它会捕获其所在上下文的this
值。
在JavaScript中,this
关键字指的是当前上下文环境中的一个对象。this
的值在函数被调用时确定,它取决于函数是如何被调用的,而不是在哪里定义的。
-
构造函数: 在构造函数中,
this
指向新创建的对象实例。1 2 3 4 5
function Person(name) { this.name = name; } const person = new Person('Kimi'); console.log(person.name); // 输出 "Kimi"
-
箭头函数: 箭头函数不绑定自己的
this
,它会捕获其所在上下文的this
值,即它引用的是封闭作用域中的this
。1 2 3 4 5 6 7
const obj = { name: 'Kimi', greet: () => { console.log(`Hello, my name is ${this.name}!`); } }; obj.greet(); // 输出 "Hello, my name is undefined!",因为箭头函数中的 this 指向全局对象
事件委托和事件冒泡。
浏览器的时间默认是在事件冒泡的时候执行。 可以在addEventLislen方法的第三个参数传入false来实现在事件捕获的时候执行。 https://vue3js.cn/interview/JavaScript/event_agent.html#%E4%BA%8C%E3%80%81%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF
浏览器
浏览器渲染原理。
- 解析HTML,生成DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送给GPU,展示在页面上。
- 如图:
promise使用以及一些异步任务的处理
上一次面试的问题:
js的三大(this,原型链,闭包),任务队列
1,HTML的标签有哪些,行内,快。 2,css的元素选择器知道哪些,布局:flexbox。 css选择器有哪些; 显示和隐藏一个元素的方法。,回流和重绘 https://vue3js.cn/interview/css/layout_painting.html#%E4%BA%8C%E3%80%81%E5%A6%82%E4%BD%95%E8%A7%A6%E5%8F%91
3,http和https的区别,tcp和udp的区别。 问原生。 4,
4-一些概念
回流和重绘 分片加载,瀑布加载,虚拟列表。