Skip to content

常见小综合 ​

一. css ​

1. css的盒模型 ​

在HTML页面中的所有元素都可以看作成一个盒子

盒子组成:内容content、外边距margin、内边距padding、边框border

盒模型的类型:

​ 标准盒模型:margin + border + padding + content

​ IE盒模型: margin + content(border + padding)

​ 控制盒模型的模式: box-sizing:content-box(默认值,标准盒模型)、border-box(IE盒模型)

2. css选择器的优先级 ​

css的特性:继承性、层叠性、优先级

  • 优先级:写css样式的时候,会给同一个元素添加多个样式,此时谁的权重高就显示谁的样式

    标签、类/伪类/属性、全局、行内、id、!important

    !important > 行内 > id > 类/伪类/属性 > 标签 > 全局

3. 隐藏元素的方法有哪些 ​

  • display: none

    元素在页面上消失,不占据空间

  • opacity: 0

    设置元素透明度为0,元素不可见,占据空间位置

  • visibility:hidden

    让元素消失,占据空间位置,一种不可见的状态

  • position:absolute

  • clip-path

4. px 和 rem 的区别 ​

px 是像素,显示器上给我们呈现画面的像素,每个像素的大小都一样,绝对单位长度

rem, 相对单位,相对于 html 根节点的font-size的值,直接给html节点的 font-size:62.5%

1 rem = 10px (16px*62.5%=10px)

5. 重绘重排有什么区别 ​

重排(回流):布局引擎会根据所有的样式计算出盒模型在页面位置上的大小

重绘:计算好盒模型位置、大小和其他的一些属性之后,浏览器就会根据每个盒模型的特性进行绘制

浏览器渲染机制:

对DOM的大小、位置进行修改后,浏览器需要重新计算元素的这些几何属性,就叫重排

对DOM的样式进行修改,比如color和background-color,浏览器不需要重新计算任何属性的时候,直接绘制了该元素的新样式,那么这里就发生了重绘

重排一定会触发重绘(因为位置变了,必然要重新画),但重绘不一定会触发重排(改个颜色,位置没动)。

6. 让一个元素水平垂直居中的方式 ​

  1. 定位 + margin
  2. 定位 + translate
  3. flex 布局
  4. gird 布局
  5. table 布局

7. css哪些属性可以继承?哪些不可以继承 ​

css的三大特性:继承、层叠、优先级

子元素可以继承父类元素样式

  1. 字体的一些属性:font
  2. 文本的一些属性:line-height
  3. 元素可见性:visibility:hidden
  4. 表格布局属性:border-spacing
  5. 列表属性:list-style
  6. 页面样式属性:page
  7. 声音的样式属性

8. 有没有用过预处理器 ​

预处理语言增加了变量、函数、混入等强大的功能

SASS LESS

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .box {
    width: 100px;
    height: 100px;
    background-color: red;
  }

  p {
    color: blue;
  }

  @global: #000;

  .box {
    color: @global;
  }
</style>

<body>
  <div class="box">
    <span></span>
  </div>
  <p></p>
</body>

</html>

二. JavaScript ​

1. js由哪三部分组成 ​

  • ECMAscript:js 的核心内容,描述了语言的基础语法,比如var,for,数据类型(数组、字符串)
  • 文档对象模型 (DOM):DOM把整个HTML页面规划为元素构成的文档
  • 浏览器对象模型 (BOM):对浏览器窗口进行访问和操作

2. js 有哪些内置对象 ​

String Boolean Number Array Object Function Math Date RegExp...

Math

​ abs() 绝对值 sqrt() 平方 max() min()

Date

​ new Date() getYear()

Array

​

Sting

​ contact() length slice() split()

3. 操作数组的方法有哪些 ​

push() pop() sort() splice() unshift() reverse() contact() join()

map() filter() every() some() reduce() isArray() findIndex()

哪些方法会改变数组

​ push() pop() unshift() shift() sort() reverse() splice()

1. 改变原数组(会修改调用它的数组)——口诀:“增删改排反” ​

  • push():在末尾添加一个或多个元素。

    javascript

    const arr = [1, 2];
    arr.push(3, 4); // 结果:arr 变成 [1, 2, 3, 4]
  • pop():删除末尾最后一个元素,并返回它。

    javascript

    const last = arr.pop(); // last = 4,arr 变成 [1, 2, 3]
  • unshift():在开头添加一个或多个元素。

    javascript

    arr.unshift(0); // arr 变成 [0, 1, 2, 3]
  • shift():删除开头第一个元素,并返回它。

    javascript

    const first = arr.shift(); // first = 0,arr 变成 [1, 2, 3]
  • splice():万能增删改(删除/替换/插入)。参数:(起始索引, 删除个数, 要插入的元素...)

    javascript

    arr.splice(1, 1, 100); // 从索引1开始,删除1个,然后插入100 -> arr 变成 [1, 100, 3]
  • sort():排序(默认按字符串排序,数字排序要传比较函数)。

    javascript

    arr.sort((a, b) => a - b); // 升序排序
  • reverse():颠倒顺序。

    javascript

    arr.reverse(); // arr 变成 [3, 100, 1]

2. 不改变原数组(返回新数组或某个值)——口诀:“拼切连,找遍查” ​

  • concat():拼接多个数组。

    javascript

    const newArr = arr.concat([4, 5]); // newArr = [3, 100, 1, 4, 5],arr不变
  • slice():切片提取,参数 (开始索引, 结束索引)(不包含结束)。

    javascript

    const sliced = arr.slice(1, 3); // 提取索引1到2的元素 -> [100, 1]
  • join():连接成字符串。

    javascript

    const str = arr.join('-'); // str = "3-100-1"
  • indexOf() / lastIndexOf():找某个元素的索引。

  • includes():查看是否包含某个元素(返回布尔值)。


3. 遍历和归并(ES6+高频使用)——口诀:“过映还,某滤归” ​

这类方法都接收一个函数作为参数,对每个元素执行。

  • forEach():过一遍,单纯做点事(比如打印),没有返回值。

    javascript

    arr.forEach(item => console.log(item * 2)); // 打印 6, 200, 2
  • map():映射,对每个元素处理,返回等长的新数组。

    javascript

    const doubled = arr.map(item => item * 2); // [6, 200, 2]
  • filter():过滤,返回符合条件的元素组成的新数组(可能会变短)。

    javascript

    const filtered = arr.filter(item => item > 5); // [100] (3和1被筛掉)
  • some():看是否有某一个元素满足条件(返回布尔值)。

    javascript

    const hasHundred = arr.some(item => item === 100); // true
  • every():看是否所有元素都满足条件(返回布尔值)。

    javascript

    const allPositive = arr.every(item => item > 0); // true
  • reduce():归纳汇总,将数组“累加”成单个值(可以求和、求积、甚至拼对象)。

    javascript

    const sum = arr.reduce((total, current) => total + current, 0); // sum = 104

4. js 对数据类检测方式有哪些 ​

​ typeof()

​ instanceof()

​ constructor

​ object.prototype.toString.call()

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<script>
  // typeof()  对于基本数据类型没问题,遇到引用数据类型就不管用
  console.log(typeof 1); // number
  console.log(typeof '1'); // string
  console.log(typeof [1, 2, 3]); // object
  // 这里 typeof 对于数组返回的是 object,无法区分数组和对象

  // instanceof()  只能判断引用数据类型 不能判断基本数据类型
  console.log([1, 2, 3] instanceof Array); // true
  console.log({} instanceof Object); // true
  console.log(1 instanceof Number); // false
  //  这里 instanceof 对于基本数据类型返回的是 false,无法区分基本数据类型

  // constructor  几乎可以判断基本数据类型和引用数据类型,但是有些特殊情况无法判断
  console.log((1).constructor === Number); // true
  console.log('1'.constructor === String); // true
  console.log([1, 2, 3].constructor === Array); // true

  // object.prototype.toString.call()   可以判断基本数据类型和引用数据类型
  const opt = Object.prototype.toString;
  console.log(opt.call(1)); // [object Number]
  console.log(opt.call('1')); // [object String]
</script>

<body>

</body>

</html>
  • typeof() 对于基本数据类型没问题,遇到引用数据类型就不管用
  • instanceof() 只能判断引用数据类型 不能判断基本数据类型
  • constructor 几乎可以判断基本数据类型和引用数据类型,但是有些特殊情况无法判断( 因为可以随便修改函数指定 )
  • object.prototype.toString.call() 可以判断基本数据类型和引用数据类型

5. 说一下什么是闭包 闭包有什么特点 ​

​ 闭包:函数嵌套函数,内部函数被外部函数返回并保存下来,就会产生闭包

​ 特点:可以重复利用变量,并且这个变量不会污染全局的一种机制;这个变量是一直保存在内存中,不会被垃圾回收机制回收

​ 缺点:闭包较多的时候,会消耗内存,导致页面的性能下降,在 IE 浏览器中会造成内存泄漏

​ 使用场景:防抖、节流、函数嵌套函数避免全局污染

6. 前端的内存泄露怎么理解 ​

​ js里已经分配内存地址的对象,但是由于长时间没有释放或者没办法清除,造成长期占用内存的现象,会让内存资源

7. 事件委托 ​

​ 原理利用了事件冒泡的机制来实现,也就是说把子元素的事件绑定到了父元素的身上

​ 如果子元素阻止了事件冒泡,那么委托也将不成立了

​ 阻止事件冒泡: event.stopPropagation()

​ addEventListener('click', 函数名, true/false ) 默认是false(事件冒泡),true(事件捕获)

​ 好处:提高性能,减少事件的绑定,也减少内存的占用

常见的是我在一个小卡片上有一个删除按钮,小卡片和删除按钮分别有两个点击事件,在点击按钮的过程中,也会触发点击卡片的事件,为了不让事件冒泡,加上阻止事件冒泡的代码,点击删除按钮就是只是删除

8. 基本数据类型和引用数据类型的区别 ​

​ 基本数据类型:String Number Boolean Undefined null

​ 基本数据类型保存在栈当中,保存的就是一个具体的值

​ 引用数据类型(复杂数据类型)Object Array Function

​ 引用数据类型是保存在堆 内存当中 ,声明一个引用类型的变量,它保存的引用数据类型的地址

​ 假如声明两个引用类型同时指向一个地址的时候,修改其中一个,那么另外一个就会改变

9. 说一下原型链 ​

​ 原型就是一个普通的对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象

​ 使用prototype方法,可以把方法挂在原型上,内存只保存一份

​ proto 可以理解为指针,实例对象中的属性,指向了构造函数的原型(prototype)

例如 小写的 =student.__proto__ = Student.prototype

  1. 每个对象都有 proto 属性,但只有函数对象才有 prototype 属性。proto 指向创建该对象的构造函数的 prototype。

  2. 当试图访问一个对象的某个属性时,JavaScript 会首先在该对象自身的属性中查找。如果没有找到,它就会沿着原型链往上查找,直到找到为止。如果整个原型链上都没有找到这个属性,那么返回 undefined。

10. new操作符具体做了什么 ​

  1. 先创建一个空对象
  2. 把空对象和构造函数通过原型链进行链接
  3. 把构造函数的this绑定到新的空对象里面
  4. 根据构建函数返回的类型判断,如果是值的类型,则返回对象,如果是引用类型,就要返回这个引用类型
js
<script>
  function newFun(Fun, ...args) {
    // 1. 先创建一个空对象
    let newObj = {};
    // 2. 把空对象和构造函数通过原型链进行链接
    newObj.__proto__ = Fun.prototype;
    // 3. 把构造函数的this绑定到新的空对象里面
    const result = Fun.apply(newObj, args);
    // 4. 根据构建函数返回的类型判断,如果是值的类型,则返回对象,如果是引用类型,就要返回这个引用类型
    return result instanceof Object ? result : newObj;
  }

  function Person(name, age) {
    this.name = name;
    this.age = age;
  }
  Person.prototype.say = function () {
    console.log(`My name is ${this.name}, I am ${this.age} years old.`);
  };
  const p1 = newFun(Person, 'Alice', 30);
  p1.say();
  console.log(p1);
</script>

11. js如何实现继承 ​

  1. 原型链继承
  2. 借用构造函数继承
  3. 组合式继承
  4. Es6和class继承

12. js的设计原理是什么 ​

​ js引擎 运行上下文 调用栈 事件循环 回调

13. js中 this 的指向问题 ​

  1. 全局对象中指向的是window

  2. 全局作用域或者普通函数中的 this 执行全局 window

  3. this 永远指向最后调用它的那个对象 (在不是箭头函数的情况下)

  4. new 关键词改变了 this 的指向

  5. apply、call、bind 可以改变 this 的指向,不是箭头函数

  6. 箭头函数的 this,它的指向在定义的时候就已经确定,箭头函数它没有 this ,

    有就是外层函数的 this,没有就是window

  7. 匿名函数中的 this 永远指向window,匿名函数的执行环境具有全局性,因此 this 指向 window

调用方式this 指向示例
默认绑定(独立函数调用)window(严格模式下为 undefined)fn() → this === window
隐式绑定(作为对象方法调用)调用该方法的对象obj.fn() → this === obj
显式绑定(call / apply / bind)传入的第一个参数fn.call(obj) → this === obj
构造函数调用(new)新创建的实例对象new Fn() → this === 实例
箭头函数定义时外层作用域的 this(无法改变)看外层,call/bind 无效
DOM 事件处理绑定事件的 DOM 元素btn.onclick = fn → this === btn
定时器(setTimeout / setInterval)window(箭头函数除外)setTimeout(fn, 1000) → this === window

14. script标签里的async和defer有什么区别 ​

  • 当没有async和defer这两个属性脚本的时候,

    浏览器会立即加载并执行指定脚本

  • 有 async

    加载和渲染后面元素的过程将和script的加载和执行并行进行(异步)

  • 有defer

    加载和渲染后面元素的过程将和script的加载并行进行(异步),但是它的执行事件要等所有元素解析完成之后才执行

    属性加载执行顺序使用场景
    无同步阻塞加载完立即执行按顺序必须立即执行的脚本
    async异步(不阻塞)加载完立即执行不保证顺序独立脚本(统计、广告)
    defer异步(不阻塞)HTML解析完执行保证顺序操作DOM、有依赖的脚本

15. setTimeout最小执行时间是多少? ​

​ setTimeout最小执行时间是 4ms

​ setInterval最小执行时间是 10ms

18. call,apply,bind三者有什么区别 ​

  • 都是改变 this 指向和函数的调用,call 和 apply 的功能相似,只是传参形式不同

  • call 传的是一个参数列表

  • apply 传递是一个数组

  • bind 传参之后不会立刻执行,会返回一个改变 this 指向的函数,这个函数还是可以传参的,bind()()

  • call 方法的性能要比 apply 要更好,所以 call 用的更多一点

“call、apply 和 bind 都是用来改变函数内部 this 指向的。

相同点:它们三个的第一个参数,都是要绑定的 this 对象。

不同点:

  1. 传参方式不同:call 是一个一个传(fn.call(obj, a, b)),apply 是通过数组传(fn.apply(obj, [a, b]))。
  2. 执行时机不同:call 和 apply 是立即执行函数;而 bind 是返回一个新函数,不会立即执行,需要手动调用。
  3. 性能上:call 在传参少的时候比 apply 性能略好,因为不用解析数组,所以日常开发中 call 用得多一些。

19. 用递归的时候有没有遇到什么问题 ​

​ 如果一个函数内可以调用函数本身,那么这个函数就是递归函数

​ 函数内部调用自己

​ (特别注意:写递归必须要有退出条件 return )

20. 如何实现一个深拷贝 ​

​ 深拷贝就是完全拷贝一个新的对象,会在堆内存中开辟一个新的空间,拷贝的对象被修改后,原对象不受影响

​ 主要针对的是引用数据类型

1. 扩展运算符
1. JSON.parse(JSON.stringify())
1. 利用递归函数实现

浅拷贝:拷贝后的对象和原对象,里面的引用数据类型(对象、数组)指向同一个内存地址,所以改了其中一个,另一个也跟着变

深拷贝:完全新的一片内存空间,完全新的数据

js
function exten(origin,deep) {
    let obj = {}
    obj = origin instanceof Array ? [] : {};
    for(let key in origin) {
        let value = origin[key]
       obj[key] = (!!deep && typeof value ==='object'&& value!==null)
       ? exten(value,deep)
       :value
    }
    return obj
}

Powered by VitePress & Vue 3