关于javascript:2022我的前端面题试整理

8次阅读

共计 12075 个字符,预计需要花费 31 分钟才能阅读完成。

扩大运算符的作用及应用场景

(1)对象扩大运算符

对象的扩大运算符 (…) 用于取出参数对象中的所有可遍历属性,拷贝到以后对象之中。

let bar = {a: 1, b: 2};
let baz = {...bar}; // {a: 1, b: 2}

上述办法实际上等价于:

let bar = {a: 1, b: 2};
let baz = Object.assign({}, bar); // {a: 1, b: 2}

Object.assign办法用于对象的合并,将源对象 (source) 的所有可枚举属性,复制到指标对象 (target)Object.assign 办法的第一个参数是指标对象,前面的参数都是源对象。(如果指标对象与源对象有同名属性,或多个源对象有同名属性,则前面的属性会笼罩后面的属性)。

同样,如果用户自定义的属性,放在扩大运算符前面,则扩大运算符外部的同名属性会被笼罩掉。

let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}};  // {a: 2, b: 4}

利用上述个性就能够很不便的批改对象的局部属性。在 redux 中的 reducer 函数规定必须是 一个纯函数 reducer 中的 state 对象要求不能间接批改,能够通过扩大运算符把批改门路的对象都复制一遍,而后产生一个新的对象返回。

须要留神:扩大运算符对对象实例的拷贝属于浅拷贝

(2)数组扩大运算符

数组的扩大运算符能够将一个数组转为用逗号分隔的参数序列,且每次只能开展一层数组。

console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
// 1 [2, 3, 4] 5

上面是数组的扩大运算符的利用:

  • 将数组转换为参数序列
function add(x, y) {return x + y;}
const numbers = [1, 2];
add(...numbers) // 3
  • 复制数组
const arr1 = [1, 2];
const arr2 = [...arr1];

要记住:扩大运算符 (…) 用于取出参数对象中的所有可遍历属性,拷贝到以后对象之中,这里参数对象是个数组,数组外面的所有对象都是根底数据类型,将所有根底数据类型从新拷贝到新的数组中。

  • 合并数组

如果想在数组内合并数组,能够这样:

const arr1 = ['two', 'three'];const arr2 = ['one', ...arr1, 'four', 'five'];// ["one", "two", "three", "four", "five"]
  • 扩大运算符与解构赋值联合起来,用于生成数组
const [first, ...rest] = [1, 2, 3, 4, 5];first // 1rest  // [2, 3, 4, 5]

须要留神:如果将扩大运算符用于数组赋值,只能放在参数的最初一位,否则会报错。

const [...rest, last] = [1, 2, 3, 4, 5];         // 报错 const [first, ...rest, last] = [1, 2, 3, 4, 5];  // 报错
  • 将字符串转为真正的数组
[...'hello']    // ["h", "e", "l", "l", "o"]
  • 任何 Iterator 接口的对象,都能够用扩大运算符转为真正的数组

比拟常见的利用是能够将某些数据结构转为数组:

// arguments 对象
function foo() {const args = [...arguments];
}

用于替换 es5 中的 Array.prototype.slice.call(arguments) 写法。

  • 应用 Math 函数获取数组中特定的值
const numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Math.max(...numbers); // 9

选择器权重计算形式

!important > 内联款式 = 外联款式 > ID 选择器 > 类选择器 = 伪类选择器 = 属性选择器 > 元素选择器 = 伪元素选择器 > 通配选择器 = 后辈选择器 = 兄弟选择器

  1. 属性前面加 !import 会笼罩页面内任何地位定义的元素款式
  2. 作为 style 属性写在元素内的款式
  3. id选择器
  4. 类选择器
  5. 标签选择器
  6. 通配符选择器(*
  7. 浏览器自定义或继承

同一级别:后写的会笼罩先写的

css 选择器的解析准则:选择器定位 DOM 元素是从右往左的方向,这样能够尽早的过滤掉一些不必要的款式规定和元素

判断数组的形式有哪些

  • 通过 Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
  • 通过原型链做判断
obj.__proto__ === Array.prototype;
  • 通过 ES6 的 Array.isArray()做判断
Array.isArrray(obj);
  • 通过 instanceof 做判断
obj instanceof Array
  • 通过 Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)

line-height 的了解及其赋值形式

(1)line-height 的概念:

  • line-height 指一行文本的高度,蕴含了字间距,实际上是下一行基线到上一行基线间隔;
  • 如果一个标签没有定义 height 属性,那么其最终体现的高度由 line-height 决定;
  • 一个容器没有设置高度,那么撑开容器高度的是 line-height,而不是容器内的文本内容;
  • 把 line-height 值设置为 height 一样大小的值能够实现单行文字的垂直居中;
  • line-height 和 height 都能撑开一个高度;

(2)line-height 的赋值形式:

  • 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算本身的行高
  • 纯数字:会把比例传递给后辈。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px
  • 百分比:将计算后的值传递给后辈

::before 和 :after 的双冒号和单冒号有什么区别?

(1)冒号 (:) 用于 CSS3 伪类,双冒号 (::) 用于 CSS3 伪元素。
(2)::before就是以一个子元素的存在,定义在元素主体内容之前的一个伪元素。并不存在于 dom 之中,只存在在页面之中。

留神: :before:after 这两个伪元素,是在 CSS2.1 里新呈现的。起初,伪元素的前缀应用的是单冒号语法,但随着 Web 的进化,在 CSS3 的标准里,伪元素的语法被批改成应用双冒号,成为::before::after

伪元素和伪类的区别和作用?

  • 伪元素:在内容元素的前后插入额定的元素或款式,然而这些元素实际上并不在文档中生成。它们只在内部显示可见,但不会在文档的源代码中找到它们,因而,称为“伪”元素。例如:
p::before {content:"第一章:";}
p::after {content:"Hot!";}
p::first-line {background:red;}
p::first-letter {font-size:30px;}
  • 伪类:将非凡的成果增加到特定选择器上。它是已有元素上增加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}
p:first-child {color: red}

总结: 伪类是通过在元素选择器上加⼊伪类扭转元素状态,⽽伪元素通过对元素的操作进⾏对元素的扭转。

Compositon api

Composition API也叫组合式 API,是 Vue3.x 的新个性。

通过创立 Vue 组件,咱们能够将接口的可重复部分及其性能提取到可重用的代码段中。仅此一项就能够使咱们的应用程序在可维护性和灵活性方面走得更远。然而,咱们的教训曾经证实,光靠这一点可能是不够的,尤其是当你的应用程序变得十分大的时候——想想几百个组件。在解决如此大的应用程序时,共享和重用代码变得尤为重要

  • Vue2.0 中,随着性能的减少,组件变得越来越简单,越来越难保护,而难以保护的根本原因是 Vue 的 API 设计迫使开发者应用 watch,computed,methods 选项组织代码,而不是理论的业务逻辑。
  • 另外 Vue2.0 短少一种较为简洁的低成本的机制来实现逻辑复用,尽管能够 minxis 实现逻辑复用,然而当 mixin 变多的时候,会使得难以找到对应的 data、computed 或者 method 来源于哪个mixin,使得类型推断难以进行。
  • 所以 Composition API 的呈现,次要是也是为了解决 Option API 带来的问题,第一个是代码组织问题,Compostion API能够让开发者依据业务逻辑组织本人的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他本人写的代码时,他能够更好的利用代码的组织反推出理论的业务逻辑,或者依据业务逻辑更好的了解代码。
  • 第二个是实现代码的逻辑提取与复用,当然 mixin 也能够实现逻辑提取与复用,然而像后面所说的,多个 mixin 作用在同一个组件时,很难看出 property 是来源于哪个 mixin,起源不分明,另外,多个mixinproperty存在变量命名抵触的危险。而 Composition API 刚好解决了这两个问题。

艰深的讲:

没有 Composition API 之前 vue 相干业务的代码须要配置到 option 的特定的区域,中小型我的项目是没有问题的,然而在大型项目中会导致前期的维护性比较复杂,同时代码可复用性不高。Vue3.x 中的 composition-api 就是为了解决这个问题而生的

compositon api 提供了以下几个函数:

  • setup
  • ref
  • reactive
  • watchEffect
  • watch
  • computed
  • toRefs
  • 生命周期的hooks

都说 Composition API 与 React Hook 很像,说说区别

从 React Hook 的实现角度看,React Hook 是依据 useState 调用的程序来确定下一次重渲染时的 state 是来源于哪个 useState,所以呈现了以下限度

  • 不能在循环、条件、嵌套函数中调用 Hook
  • 必须确保总是在你的 React 函数的顶层调用 Hook
  • useEffect、useMemo等函数必须手动确定依赖关系

而 Composition API 是基于 Vue 的响应式零碎实现的,与 React Hook 的相比

  • 申明在 setup 函数内,一次组件实例化只调用一次setup,而 React Hook 每次重渲染都须要调用 Hook,使得 React 的 GC 比 Vue 更有压力,性能也绝对于 Vue 来说也较慢
  • Compositon API的调用不须要顾虑调用程序,也能够在循环、条件、嵌套函数中应用
  • 响应式零碎主动实现了依赖收集,进而组件的局部的性能优化由 Vue 外部本人实现,而 React Hook 须要手动传入依赖,而且必须必须保障依赖的程序,让 useEffectuseMemo 等函数正确的捕捉依赖变量,否则会因为依赖不正确使得组件性能降落。

尽管 Compositon API 看起来比 React Hook 好用,然而其设计思维也是借鉴 React Hook 的。

参考:前端进阶面试题具体解答

层叠上下文

元素晋升为一个比拟非凡的图层,在三维空间中 (z 轴) 高出一般元素一等。

触发条件

  • 根层叠上下文(html)
  • position
  • css3属性

    • flex
    • transform
    • opacity
    • filter
    • will-change
    • webkit-overflow-scrolling

层叠等级:层叠上下文在 z 轴上的排序

  • 在同一层叠上下文中,层叠等级才有意义
  • z-index的优先级最高

数组有哪些原生办法?

  • 数组和字符串的转换方法:toString()、toLocalString()、join() 其中 join() 办法能够指定转换为字符串时的分隔符。
  • 数组尾部操作的办法 pop() 和 push(),push 办法能够传入多个参数。
  • 数组首部操作的办法 shift() 和 unshift() 重排序的办法 reverse() 和 sort(),sort() 办法能够传入一个函数来进行比拟,传入前后两个值,如果返回值为负数,则替换两个参数的地位。
  • 数组连贯的办法 concat(),返回的是拼接好的数组,不影响原数组。
  • 数组截取方法 slice(),用于截取数组中的一部分返回,不影响原数组。
  • 数组插入方法 splice(),影响原数组查找特定项的索引的办法,indexOf() 和 lastIndexOf() 迭代办法 every()、some()、filter()、map() 和 forEach() 办法
  • 数组归并办法 reduce() 和 reduceRight() 办法

对 Flex 布局的了解及其应用场景

Flex 是 FlexibleBox 的缩写,意为 ” 弹性布局 ”,用来为盒状模型提供最大的灵活性。任何一个容器都能够指定为 Flex 布局。行内元素也能够应用 Flex 布局。留神,设为 Flex 布局当前,子元素的 float、clear 和 vertical-align 属性将生效。采纳 Flex 布局的元素,称为 Flex 容器(flex container),简称 ” 容器 ”。它的所有子元素主动成为容器成员,称为 Flex 我的项目(flex item),简称 ” 我的项目 ”。容器默认存在两根轴:程度的主轴(main axis)和垂直的穿插轴(cross axis),我的项目默认沿程度主轴排列。

以下 6 个属性设置在 容器上

  • flex-direction 属性决定主轴的方向(即我的项目的排列方向)。
  • flex-wrap 属性定义,如果一条轴线排不下,如何换行。
  • flex-flow 属性是 flex-direction 属性和 flex-wrap 属性的简写模式,默认值为 row nowrap。
  • justify-content 属性定义了我的项目在主轴上的对齐形式。
  • align-items 属性定义我的项目在穿插轴上如何对齐。
  • align-content 属性定义了多根轴线的对齐形式。如果我的项目只有一根轴线,该属性不起作用。

以下 6 个属性设置在 我的项目上

  • order 属性定义我的项目的排列程序。数值越小,排列越靠前,默认为 0。
  • flex-grow 属性定义我的项目的放大比例,默认为 0,即如果存在残余空间,也不放大。
  • flex-shrink 属性定义了我的项目的放大比例,默认为 1,即如果空间有余,该我的项目将放大。
  • flex-basis 属性定义了在调配多余空间之前,我的项目占据的主轴空间。浏览器依据这个属性,计算主轴是否有多余空间。它的默认值为 auto,即我的项目的原本大小。
  • flex 属性是 flex-grow,flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。
  • align-self 属性容许单个我的项目有与其余我的项目不一样的对齐形式,可笼罩 align-items 属性。默认值为 auto,示意继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch。

简略来说: flex 布局是 CSS3 新增的一种布局形式,能够通过将一个元素的 display 属性值设置为 flex 从而使它成为一个 flex 容器,它的所有子元素都会成为它的我的项目。一个容器默认有两条轴:一个是程度的主轴,一个是与主轴垂直的穿插轴。能够应用 flex-direction 来指定主轴的方向。能够应用 justify-content 来指定元素在主轴上的排列形式,应用 align-items 来指定元素在穿插轴上的排列形式。还能够应用 flex-wrap 来规定当一行排列不下时的换行形式。对于容器中的我的项目,能够应用 order 属性来指定我的项目的排列程序,还能够应用 flex-grow 来指定当排列空间有残余的时候,我的项目的放大比例,还能够应用 flex-shrink 来指定当排列空间有余时,我的项目的放大比例。

use strict 是什么意思 ? 应用它区别是什么?

use strict 是一种 ECMAscript5 增加的(严格模式)运行模式,这种模式使得 Javascript 在更严格的条件下运行。设立严格模式的目标如下:

  • 打消 Javascript 语法的不合理、不谨严之处,缩小怪异行为;
  • 打消代码运行的不平安之处,保障代码运行的平安;
  • 进步编译器效率,减少运行速度;
  • 为将来新版本的 Javascript 做好铺垫。

区别:

  • 禁止应用 with 语句。
  • 禁止 this 关键字指向全局对象。
  • 对象不能有重名的属性。

nextTick

nextTick 能够让咱们在下次 DOM 更新循环完结之后执行提早回调,用于取得更新后的 DOM

nextTick次要应用了宏工作和微工作。依据执行环境别离尝试采纳

  • Promise
  • MutationObserver
  • setImmediate
  • 如果以上都不行则采纳setTimeout

定义了一个异步办法,屡次调用 nextTick 会将办法存入队列中,通过这个异步办法清空以后队列

什么是 DOM 和 BOM?

  • DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象次要定义了解决网页内容的办法和接口。
  • BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来看待,这个对象次要定义了与浏览器进行交互的法和接口。BOM 的外围是 window,而 window 对象具备双重角色,它既是通过 js 拜访浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者办法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最基本的对象 document 对象也是 BOM 的 window 对象的子对象。

革除浮动

  1. 在浮动元素前面增加 clear:both的空 div 元素
<div class="container">
    <div class="left"></div>
    <div class="right"></div>
    <div style="clear:both"></div>
</div>
  1. 给父元素增加 overflow:hidden 或者 auto 款式,触发BFC
<div class="container">
    <div class="left"></div>
    <div class="right"></div>
</div>
.container{
    width: 300px;
    background-color: #aaa;
    overflow:hidden;
    zoom:1;   /*IE6*/
}
  1. 应用伪元素,也是在元素开端增加一个点并带有 clear: both 属性的元素实现的。
<div class="container clearfix">
    <div class="left"></div>
    <div class="right"></div>
</div>
.clearfix{zoom: 1; /*IE6*/}
.clearfix:after{
    content: ".";
    height: 0;
    clear: both;
    display: block;
    visibility: hidden;
}

举荐应用第三种办法,不会在页面新增 div,文档构造更加清晰

左右两边定宽,两头自适应

float,float + calc, 圣杯布局(设置 BFC,margin 负值法),flex

.wrap {
  width: 100%;
  height: 200px;
}
.wrap > div {height: 100%;}
/* 计划 1 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {margin: 0 120px;}
/* 计划 2 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {width: calc(100% - 240px);
  margin-left: 120px;
}
/* 计划 3 */
.wrap {display: flex;}
.left {width: 120px;}
.right {width: 120px;}
.center {flex: 1;}

对对象与数组的解构的了解

解构是 ES6 提供的一种新的提取数据的模式,这种模式可能从对象或数组里有针对性地拿到想要的数值。1)数组的解构 在解构数组时,以元素的地位为匹配条件来提取想要的数据的:

const [a, b, c] = [1, 2, 3]

最终,a、b、c 别离被赋予了数组第 0、1、2 个索引位的值:

数组里的 0、1、2 索引位的元素值,精准地被映射到了左侧的第 0、1、2 个变量里去,这就是数组解构的工作模式。还能够通过给左侧变量数组设置空占位的形式,实现对数组中某几个元素的精准提取:

const [a,,c] = [1,2,3]

通过把两头位留空,能够顺利地把数组第一位和最初一位的值赋给 a、c 两个变量:

2)对象的解构 对象解构比数组构造略微简单一些,也更显弱小。在解构对象时,是以属性的名称为匹配条件,来提取想要的数据的。当初定义一个对象:

const stu = {
  name: 'Bob',
  age: 24
}

如果想要解构它的两个自有属性,能够这样:

const {name, age} = stu

这样就失去了 name 和 age 两个和 stu 平级的变量:

留神,对象解构严格以属性名作为定位根据,所以就算调换了 name 和 age 的地位,后果也是一样的:

const {age, name} = stu

vue 实现双向数据绑定原理是什么?

<!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>
  <body>
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
    <!-- 引入 vue 文件 -->
    <div id="box">
      <new-input v-bind:name.sync="name"></new-input>
      {{name}}
      <!-- 小胡子语法 -->
      <input type="text" v-model="name" />
    </div>
    <script>
      Vue.component("new-input", {        props: ["name"],        data: function () {          return {            newName: this.name,};        },        template: `<label><input type="text" @keyup="changgeName"        v-model="newName" /> 你的名字:</label>`,        // 模板字符串
        methods: {changgeName: function () {this.$emit("update:name", this.newName);          },        },        watch: {name: function (v) {this.newName = v;},        },        //    监听
      });      new Vue({        el: "#box",        // 挂载实例
        data: {name: "nick",},        // 赋初始值
      });    </script>
  </body>
</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>
  <body>
    <input type="text" v-mode="msg" />
    <p v-mode="msg"></p>
    <script>
      const data = {msg: "你好",};      const input = document.querySelector("input");      const p = document.querySelector("p");      input.value = data.msg;      p.innerHTML = data.msg;      // 视图变数据跟着变
      input.addEventListener("input", function () {data.msg = input.value;});      // 数据变视图变
      let temp = data.msg;      Object.defineProperty(data, "msg", {        get() {return temp;},        set(value) {          temp = value;          // 视图批改
          input.value = temp;          p.innerHTML = temp;        },      });      data.msg = "小李";    </script>
  </body>
</html>

八股文我不想写了本人百度去

箭头函数和一般函数有啥区别?箭头函数能当构造函数吗?

  • 一般函数通过 function 关键字定义,this 无奈联合词法作用域应用,在运行时绑定,只取决于函数的调用形式,在哪里被调用,调用地位。(取决于调用者,和是否独立运行)
  • 箭头函数应用被称为“胖箭头”的操作 => 定义,箭头函数不利用一般函数 this 绑定的四种规定,而是依据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无奈被批改(new 也不行)。

    • 箭头函数罕用于回调函数中,包含事件处理器或定时器
    • 箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
    • 没有原型、没有 this、没有 super,没有 arguments,没有 new.target
    • 不能通过 new 关键字调用

      • 一个函数外部有两个办法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 办法,创立一个实例对象,而后再执行这个函数体,将函数的 this 绑定在这个实例对象上
      • 当间接调用时,执行 [[Call]] 办法,间接执行函数体
      • 箭头函数没有 [[Construct]] 办法,不能被用作结构函数调用,当应用 new 进行函数调用时会报错。
function foo() {return (a) => {console.log(this.a);
  }
}

var obj1 = {a: 2}

var obj2 = {a: 3}

var bar = foo.call(obj1);
bar.call(obj2);

Object.is 实现

题目形容:

Object.is 不会转换被比拟的两个值的类型,这点和 === 更为类似,他们之间也存在一些区别。1. NaN 在 === 中是不相等的,而在 Object.is 中是相等的
    2. + 0 和 - 0 在 === 中是相等的,而在 Object.is 中是不相等的

实现代码如下:

Object.is = function (x, y) {if (x === y) {
    // 当前情况下,只有一种状况是非凡的,即 +0 -0
    // 如果 x !== 0,则返回 true
    // 如果 x === 0,则须要判断 + 0 和 -0,则能够间接应用 1/+0 === Infinity 和 1/-0 === -Infinity 来进行判断
    return x !== 0 || 1 / x === 1 / y;
  }

  // x !== y 的状况下,只须要判断是否为 NaN,如果 x!==x,则阐明 x 是 NaN,同理 y 也一样
  // x 和 y 同时为 NaN 时,返回 true
  return x !== x && y !== y;
};

垃圾回收

  • 对于在 JavaScript 中的字符串,对象,数组是没有固定大小的,只有当对他们进行动态分配存储时,解释器就会分配内存来存储这些数据,当 JavaScript 的解释器耗费完零碎中所有可用的内存时,就会造成零碎解体。
  • 内存透露,在某些状况下,不再应用到的变量所占用内存没有及时开释,导致程序运行中,内存越占越大,极其状况下能够导致系统解体,服务器宕机。
  • JavaScript 有本人的一套垃圾回收机制,JavaScript 的解释器能够检测到什么时候程序不再应用这个对象了(数据),就会把它所占用的内存开释掉。
  • 针对 JavaScript 的来及回收机制有以下两种办法(罕用):标记革除,援用计数
  • 标记革除

v8 的垃圾回收机制基于分代回收机制,这个机制又基于世代假说,这个假说有两个特点,一是新生的对象容易早死,另一个是不死的对象会活得更久。基于这个假说,v8 引擎将内存分为了新生代和老生代。

  • 新创建的对象或者只经验过一次的垃圾回收的对象被称为新生代。经验过屡次垃圾回收的对象被称为老生代。
  • 新生代被分为 From 和 To 两个空间,To 个别是闲置的。当 From 空间满了的时候会执行 Scavenge 算法进行垃圾回收。当咱们执行垃圾回收算法的时候应用逻辑将会进行,等垃圾回收完结后再继续执行。

这个算法分为三步:

  • 首先查看 From 空间的存活对象,如果对象存活则判断对象是否满足降职到老生代的条件,如果满足条件则降职到老生代。如果不满足条件则挪动 To 空间。
  • 如果对象不存活,则开释对象的空间。
  • 最初将 From 空间和 To 空间角色进行替换。

新生代对象降职到老生代有两个条件:

  • 第一个是判断是对象否曾经通过一次 Scavenge 回收。若经验过,则将对象从 From 空间复制到老生代中;若没有经验,则复制到 To 空间。
  • 第二个是 To 空间的内存应用占比是否超过限度。当对象从 From 空间复制到 To 空间时,若 To 空间应用超过 25%,则对象间接降职到老生代中。设置 25% 的起因次要是因为算法完结后,两个空间完结后会替换地位,如果 To 空间的内存太小,会影响后续的内存调配。

老生代采纳了标记革除法和标记压缩法。标记革除法首先会对内存中存活的对象进行标记,标记完结后革除掉那些没有标记的对象。因为标记革除后会造成很多的内存碎片,不便于前面的内存调配。所以了解决内存碎片的问题引入了标记压缩法。

因为在进行垃圾回收的时候会暂停利用的逻辑,对于新生代办法因为内存小,每次进展的工夫不会太长,但对于老生代来说每次垃圾回收的工夫长,进展会造成很大的影响。为了解决这个问题 V8 引入了增量标记的办法,将一次进展进行的过程分为了多步,每次执行完一小步就让运行逻辑执行一会,就这样交替运行

正文完
 0