基础

Posted by Chouvel on November 19, 2024

防抖: slice. 手写一个深拷贝:

HTMl-CSS

HTML 的标签有哪些,行内,块有哪些,区别。

h5 新特性的作者| h5 新特性

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 下面有那些属性或者方法

  1. dom(document,文档对象模型)
  2. 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 的嵌套,编译得到的选择器,是

  1. 后代选择器(#box div),选择 id 为 box 元素内部所有的 div 元素
  2. 子选择器(.one>one_1),选择父元素为.one 的所有.one_1 的元素。这个只选择一层,不会深入

Css预编译语言有这几个重要的特性:、

  1. 变量
  2. 混入(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 都是弱引用 弱引用是不能确保其引用的对象不会被垃圾回收器回收的引用,而强引用是确保其引用的对象不会被垃圾回收器回收的引用。

  1. 其他

对数组的遍历大家最常用的就是 for 循环,ES5 的话也可以使用 forEach,ES5 具有遍历数组功能的还有 map、filter、some、every、reduce、reduceRight 等,只不过他们的返回结果不一样。但是使用 foreach 遍历数组的话,使用 break 不能中断循环,使用 return 也不能返回到外层函数。

项目优化

  1. 封装了那些组件,实现了那些功能

Vue

vue 的典型特征是

  1. 数据驱动
  2. 组件化
  3. 指令
  • 没有指令之前,我们操作 dom 是先使用 document 来获取 dom,再进行后续操作。
  • 有了指令以后,就可以直接在标签上写对应的方法了 v-on(@),以及绑定对应的响应式数据 v-bind(:)
  • 条件渲染指令  v-if
  • 列表渲染指令 v-for,在  v-for  的时候,建议设置 key值,并且保证每个 key值是独一无二的,这便于 diff算法进行优化

c1:vue3 和 vue2 的区别。

  1. vue3:更快,更小。更好的 typescript 支持,使用 proxy 代替 vue2 的 Object.defineProperty。
  2. 引入了组合式 api,仍然支持选项式 api。
  3. 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 是面向无连接,数据传输前后不连接连接,发送端只负责将数据发送到网络,接收端从消息队列读取。

UDPTCP两者的都位于传输层

性质层面

tcp 是可靠的,udp 不可靠。

tcp 是面向连接的,需要三次握手。

tcp 是全双工的,udp 则可以一对一,一对多,多对一,对对多等等。

tcp 的报文头是 20 个字节,而 udp 只有 8 个字节,传输开销小。

应用层面

TCP 应用场景适用于对效率要求低,对准确性要求高。

udp 可以在直播,视频里面使用。

讲一下 tcp 三次握手

上述每一次握手的作用如下:

  • 第一次握手:客户端发送网络包,服务端收到了 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  • 第二次握手:服务端发包,客户端收到了 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常
  • 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常

通过三次握手,就能确定双方的接收和发送能力是正常的。之后就可以正常通信了

为什么不是两次握手?

如果是两次握手,发送端可以确定自己发送的信息能对方能收到,也能确定对方发的包自己能收到,但接收端只能确定对方发的包自己能收到 无法确定自己发的包对方能收到

并且两次握手的话, 客户端有可能因为网络阻塞等原因会发送多个请求报文,延时到达的请求又会与服务器建立连接,浪费掉许多服务器的资源

get 和 post 的区别

  1. get 和 post 最主要的区别是 get 的请求体为空。post 通常使用来客户端发送数据给服务端(我的浅薄理解)。
  2. get 是幂等的,post 是非幂等的。

JavaScript

实现数组去重

  1. 利用 set 的特性,不重复来实现。
1
2
3
const arr = [1, 2, 3, 1, 2, 3, 1, 1];
const newArr = [...new Set(arr)];
console.log(newArr);
  1. 使用 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;
});
  1. 不使用数据结构以及 js 特有的 api 实现去重。
1
2
3
4
5
6
7
8
9
10
11
12
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 遍历数组。

数组的方法

增删改差等操作

  1. push,unshift,splice(粘合),concat
  2. pop,shift,splice,slice
  3. splice
  4. indexOf,inclulds,find ;排序
  5. reverse,sort ;转换
  6. join ,迭代的等。
  7. forEach,map,sort,filter,every,some

隐式转化/显示转换

显示转换,即我们很清楚可以看到这里发生了类型的转变,常见的方法有:

  • Number()
  • parseInt()
  • String()
  • Boolean()

在隐式转换中,我们可能最大的疑惑是 :何时发生隐式转换?

我们这里可以归纳为两种情况发生隐式转换的场景:

  • 比较运算(==!=><)、ifwhile需要布尔值地方
  • 算术运算(+-*/%

除了上面的场景,还要求运算符两边的操作数不是同一类型

自动转换为布尔值

在需要布尔值的地方,就会将非布尔值的参数自动转为布尔值,系统内部会调用 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 遵循的就是词法作用域,也叫静态作用域。

实现水平居中的方式

  1. 利用 flexbox 的方法,父元素创建 flexbox;
  2. 子元素的 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;


}

判断数据类型

  1. typeof 判断基本数据类型
  2. instanceof 判断复杂数据类型;这种方法是利用左边对象的 propotype
  3. Object.propotype.toString.call()判断所有。 4.

事件和事件流,冒泡,捕获

事件流有多种形式,例如冒泡。 事件流分为 3 个阶段:

  1. 事件捕获
  2. 事件触发
  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 事件循环的执行顺序可以概括为:

  1. 执行所有同步代码。
  2. 执行完同步代码后,检查微任务队列,如果有微任务,按顺序执行所有微任务。
  3. 检查宏任务队列,取出队首的宏任务执行。
  4. 宏任务执行完毕后,再次检查微任务队列,如果有微任务,再次执行所有微任务。
  5. 重复步骤 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 它采用的是静态作用域:函数能访问哪些东西,在你定义的时候就确定好了 创建一个函数的时候,这个一个函数能够记住它创建时的词法作用域,即使该函数在其原始作用域之外被执行。

使用场景:

  1. 数据封装和隐私: 闭包可以用来创建私有变量,这些变量不能从外部函数直接访问。
  2. 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的值在函数被调用时确定,它取决于函数是如何被调用的,而不是在哪里定义的。

  1. 全局上下文:在全局函数中,this通常指向全局对象(在浏览器中是 window对象)。
  2. 方法调用:当函数作为对象的方法调用时,this指向调用该方法的对象。
  3. 构造函数:在构造函数中,this指向新创建的对象。
  4. 事件处理:在事件处理函数中,this指向触发事件的对象。
  5. 箭头函数:箭头函数不绑定自己的 this,它会捕获其所在上下文的 this值。

在 JavaScript 中,this关键字指的是当前上下文环境中的一个对象。this的值在函数被调用时确定,它取决于函数是如何被调用的,而不是在哪里定义的。

  1. 构造函数: 在构造函数中,this 指向新创建的对象实例。

    1
    2
    3
    4
    5
    
    function Person(name) {
      this.name = name;
    }
    const person = new Person("Kimi");
    console.log(person.name); // 输出 "Kimi"
    
  2. 箭头函数: 箭头函数不绑定自己的 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

浏览器

浏览器渲染原理。

  1. 解析 HTML,生成 DOM 树,解析 CSS,生成 CSSOM 树
  2. 将 DOM 树和 CSSOM 树结合,生成渲染树(Render Tree)
  3. Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
  4. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  5. Display:将像素发送给 GPU,展示在页面上。
  6. 如图:

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-一些概念

回流和重绘 分片加载,瀑布加载,虚拟列表。