合集:2023年最全前端面试题考点HTML5+CSS3+JS+Vue3+React18+八股文+手写+项目+笔试_参宿7的博客-CSDN博客

本章内容为一面基础面

为了简洁,相关文章参考链接在标题里

目录

HTML5

语义化标签的好处⭐⭐

Web标准和W3C标准⭐

网页组成

浏览器的渲染过程⭐⭐⭐

回流(重排)和重绘⭐⭐

常用手写⭐

获取标签

js中插入标签

获取第n个标签

常用触发事件​​​​​​​

获取宽高

系统屏幕(window.screen.availHeight,height)

浏览器(window.outerHeight,innerHeight)

元素(clientHeight,offsetHeight,scrollHeight)

相对距离或位置(offsetTop,scrollTop,getBoundingClientRect)

CSS3

盒模型⭐⭐⭐

content-box 内容盒模型(W3C盒)  和 border-box 边框盒模型(IE 盒)

实现梯形,三角形,扇形,圆形,半圆(⭐手写)

盒子充满屏幕 (⭐手写)

选择器

ID选择器、类选择器、标签选择器(按优先级高到低排序)⭐⭐

特殊符号选择器(>,+,~,空格,逗号)

属性选择器

伪类和伪元素选择器(⭐手写)伪类和伪元素选择器

优先级⭐⭐⭐

样式方式(按优先级高到低排序)⭐⭐

内联样式表(在标签内设置元素的样式)

嵌入样式表(在head标签内)

外部样式表(在head标签内)

transform旋转,缩放,平移⭐⭐

position关键字⭐⭐⭐

水平 & 垂直对齐 (⭐手写)

水平居中

水平垂直居中

transform:translate

flex(强烈推荐)

flex布局⭐⭐⭐

align-items和justify-content的区别

flex:1

BFC规范⭐⭐⭐

问题

常见触发条件

规则

overflow: hidden示例

*浮动

三栏布局 :左右固定,中间自适应(⭐手写)

flex布局(强烈推荐)

grid布局

margin负值法

自身浮动

绝对定位

圣杯布局 (⭐手写)

单位⭐⭐⭐

px转rem

px转vw

opacity: 0、visibility: hidden、display: none⭐⭐⭐

img的 title 和 alt 有什么区别⭐

行内素、块级元素和行内块元素⭐⭐⭐

溢出转省略 (⭐手写)⭐⭐

单行

多行

布局

静态布局

响应式布局⭐⭐

自适应和响应式区别

弹性布局(flex布局)

流式布局

媒体查询@media(css3)

媒体类型

逻辑运算符(logical operators)

媒体功能

其他加载方式

style标签上加载

@import 使用时加载

标签

JavaScript

语言区别

BOM,DOM,文档,对象,模型

ES6新增

数据类型

基本数据类型

引用数据类型

声明和定义

Null,NaN,Undefined

toString,valueOf

==,===,Object.is()

判断数据类型:typeof运算符,instance of运算符,isPrototypeOf() 方法,constructor,Object prototype

instance of (⭐手写)

new (⭐手写)

类型转换

转换为布尔值

type of null

事件

DOM事件流(event flow )

事件委托/代理(⭐手写)

发布订阅模式(⭐手写)

观察者模式(⭐手写)

封装事件绑定

执行上下文/作用域和作用链

this

JS预解析(变量提升)

var,let 和 const关键字

原型链

寄生组合式继承(⭐手写)

Iterator,for in,for of,forEach,map循环遍历

Iterator

for of

for in

forEach

map

匿名函数、箭头函数、构造函数

匿名函数

箭头函数

构造函数

this

call、apply、bind改变this

call (⭐手写)

apply(⭐手写)

bind(⭐手写)

闭包(closure)

正则表达式Regular Expression(RegExp)

常用修饰符

常用字符

合法的URL (⭐手写)

函数

函数的length属性

函数声明与函数表达式的区别

立即执行函数(iife)

常用方法

异或运算^

Math

Number

特殊值

科学计数法

Map

Set

set判断值相等的机制

数组去重 (⭐手写)

Array

Array.filter(⭐手写)

Array.map(⭐手写)

Array.reduce(⭐手写)

String

Class

类声明

类表达式

使用 super 调用超类

private

static 关键字

创建对象的方式

Object

Object.create (⭐手写)

Object.freeze (⭐手写)

indexOf (⭐手写)

高阶函数和函数的珂里化Currying

Arguments对象

深浅拷贝

深拷贝(⭐手写)

严格模式

防抖 (⭐手写)

节流(⭐手写)

防抖、节流应用

垃圾回收(GC)

内存分配

回收策略

内存泄漏

宏任务、微任务、Event-Loop

setImmediate与setTimeout的区别

JS延迟加载的方式

HTML5

HTML5的设计目的是为了在移动设备上支持多媒体。

在HTML5出来之前,我们习惯于用没有语义的div来表示不同模块。

在HTML5中加入了一些语义化标签,来更清晰的表达文档结构

语义化标签的好处⭐⭐

  1. 用户:提高体验,比如:title,alt用于解释名词和图片信息
  2. 非技术人员:能看懂代码,很好的呈现内容结构、代码结构
  3. 技术人员:便于团队开发与维护语义化更具有可读性
  4. 搜索引擎:利于SEO。语义化能和搜索引擎建立更好的联系,优化搜索

Web标准和W3C标准⭐

网页组成

web标准

  • 结构(骨架):HTML用于描述页面的结构
  • 表现(皮肤):CSS用于控制页面中元素的样式
  • 行为(交互):JavaScript用于响应用户操作
  • W3C:World Wide Web(万维网) Consortium,对web标准提出了代码规范的要求
  • 结构的要求

    1、标签字母要小写

    2、标签要闭合

  • 行为的要求

    1、建议使用外链CSS和js脚本,实现结构与表现分离结构与行为分离,能提高页面的渲染效率,更快地显示网页内容

浏览器的渲染过程⭐⭐⭐

1.解析HTML的所有标签,深度遍历生成DOM Tree

2.解析CSS,构建层叠样式表模型CSSOM(CSS Object Model)

2.5.JS脚本加载

a. 普通js/sync
文档解析的过程中,如果遇到script脚本,就会停止页面的解析进行下载,当脚本都执行完毕后,才会继续解析页面。

(因为JS可以操作DOM和CSS,可能会改动DOM和CSS,所以继续解析会造成浪费)。

如果脚本是外部的,会等待脚本下载完毕,再继续解析文档。

所以常见的做法是将js放到页脚部分。

b. async(异步:HTML加载和解析,js加载)
async脚本会在加载完毕后执行

<script type="text/javascript" src="x.min.js" async="async"></script>
async脚本的加载不计入DOMContentLoaded事件统计,也就是说下图两种情况都是有可能发生的:
HTML 还没有被解析完的时候,async脚本已经加载完了,那么 HTML 停止解析,去执行脚本,脚本执行完毕后触发DOMContentLoaded事件。

HTML 解析完了之后,async脚本才加载完,然后再执行脚本,那么在HTML解析完毕、async脚本还没加载完的时候就触发DOMContentLoaded事件

c. defer(推迟)
文档解析时,遇到设置了defer的脚本,就会在后台进行下载,但是并不会阻止文档的渲染,当页面解析和渲染完毕后,会等到所有的defer脚本加载完毕并按照顺序执行完毕才会触发

<script type="text/javascript" src="x.min.js" defer="defer"></script>

DOMContentLoaded事件,也就是说下图两种情况都是有可能发生的:
HTML 还没有被解析完的时候,defer脚本已经加载完了,那么 等待HTML 解析完成后执行脚本,脚本执行完毕后触发DOMContentLoaded事件。

HTML 解析完了之后,defer脚本才加载完,然后再执行脚本,脚本执行完毕后触发DOMContentLoaded事件。

defer是“渲染完再执行”:依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖

async是“下载完就执行”:并不关心页面中的DOM元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。

3.构建Render Tree(渲染树)

DOM和CSSOM根据一定的规则组合起来生成了Render Tree

4.布局(Layout)

确定各个元素的位置,以及大小。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。

5.绘制(Painting)

浏览器会遍历Render Tree渲染树,调用“paint”方法,将渲染树的各个节点绘制到屏幕上。

回流(重排)和重绘⭐⭐

回流(重排)

元素改变 尺寸,宽高,边框,内容,位置 都会引起重排,导致需要重新构建页面的时候

  • 增删可见的 DOM 元素的时候
  • 元素的位置发生改变
  • 元素的尺寸发生改变
  • 内容改变
  • 页面第一次渲染的时候

重绘

外观发生改变,但没有改变布局

列举一些相关的 CSS 样式:color、background、background-size、visibility、box-shadow

常用手写⭐

获取标签

<html><head><meta charset=utf-8><style type="text/css">div{color:#ff0000;font-size:20px;}.green{color:#008000;}#black{color:#000000;}</style></head><body><div>红色</div><div class='green'>绿色</div><div id='black'>黑色</div></body>
</html>
document.getElementById('id')//全局唯一
document.getElementByClassName('className')//获得数组
document.getElementByTagName('div')//获得数组

js中插入标签

let head = document.head;
let style = document.createElement("style");
style.type = "text/css";
style.innerHTML = "p {color: rgb(255,0,0);}";
head.appendChild(style);

获取第n个标签

let pArr = document.getElementsByTagName('p')
for(let i = 0; i < pArr.length; i++){if(i===n-1){
...
}
}
<html><head><meta charset=utf-8><style type="text/css">ul li:nth-child(2) {background-color: rgb(255,0,0);}</style></head><body><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul></body>
</html>

常用触发事件​​​​​​​

<input type="text" onkeyup="myFunction()">
//不用 "on" 前缀。例如,使用 "click" 来取代 "onclick"。
//true - 事件在捕获阶段执行
//false- 默认。事件在冒泡阶段执行
document.addEventListener(event, function[, useCapture])

鼠标事件

属性 描述 DOM
onclick 当用户点击某个对象时调用的事件句柄。 2
ondblclick 当用户双击某个对象时调用的事件句柄。 2
onmousedown 鼠标按钮被按下。 2
onmousemove 鼠标被移动。 2
onmouseover 鼠标移到某元素之上。 2
onmouseout 鼠标从某元素移开。 2
onmouseup 鼠标按键被松开。 2

键盘事件

属性 描述 DOM
onkeydown 某个键盘按键被按下。 2
onkeypress 某个键盘按键被按下并松开。 2
onkeyup 某个键盘按键被松开。

表单事件

属性 描述 DOM
onchange 该事件在表单元素的内容改变时触发( <input>, <keygen>, <select>, 和 <textarea>) 2
onfocus 元素获取焦点时触发 2
onfocusin 元素即将获取焦点时触发 2
onfocusout 元素即将失去焦点时触发 2
oninput 元素获取用户输入时触发 3
onreset 表单重置时触发 2
onsearch 用户向搜索域输入文本时触发 ( <input="search">)
onselect 用户选取文本时触发 ( <input> 和 <textarea>) 2
onsubmit 表单提交时触发 2

获取宽高

系统屏幕(window.screen.availHeight,height

  • window.screen.height

这个是设备显示屏的高度,各个机型的显示屏高度都不一样,可以在系统设置中看

  • window.screen.availHeight

屏幕的可用高度,一般是显示屏高度减去显示屏任务栏的高度

screen.availHeight = screen.height - 任务栏高度

注; 更改显示器的缩放倍数,会影响到获取的值,比如屏幕放大125%,则原本1080高度的值,读取后为864。即1080 / 1.25 = 864

浏览器(window.outerHeight,innerHeight

  • window.outerHeight

    浏览器的高度,高度改变,会改变值的大小

  • window.innerHeight

    浏览器的可用高度 = 浏览器高度 - 顶部工具栏

    若有调试面板还会再减去调度面板的高度,最后得出的才是可用高度

元素(clientHeight,offsetHeight,scrollHeight

获取body的高(不含边框)

element.clientHeight :body的高度
clientHeight = padding + height

获取body的高(含边框)

element.offsetHeight :body的高度(包含border)
offsetHeight = padding + height + border

element.scrollHeight,为可见高度加上未显示的高度(滚动条未显示部分)。

相对距离或位置(offsetTop,scrollTop,getBoundingClientRect

  • 获取到顶部或左部的距离element.offsetTop, element.offsetLeft

offsetTop:元素到offsetParent顶部的距离

offsetParent:距离元素最近的一个具有定位的父元素relative,absolute,fixed),

父元素都不符合条件,offsetParent为body

  1. 注意:只有元素show(渲染完成)才会计算入offsetTop,若是中间有元素数据需要异步获取,会导致最终获取的offsetTop值偏小
  • 获取滚动条到top,left的距离:element.scrollTop,element.scrollLeft
  • 获取相对于视窗的位置集合element.getBoundingClientRect()

集合中有top, right, bottom, left等属性。

  • rectObject.top:元素上边到视窗上边的距离;
  • rectObject.right:元素右边到视窗左边的距离;
  • rectObject.bottom:元素下边到视窗上边的距离;
  • rectObject.left:元素左边到视窗左边的距离;

CSS3

盒模型⭐⭐⭐

内容(content)、内边距/填充(padding)、外边距/边界(margin)、 边框(border);

content-box 内容盒模型(W3C盒)  和 border-box 边框盒模型(IE 盒)

width = content宽度

width = content宽度 + padding + border

<div class="content-box"></div>
<div class="border-box"></div>

实现梯形,三角形,扇形,圆形,半圆(⭐手写)

/* HTML CODE: <div class="square">正方形</div>*//* CSS CODE */.square {width: 100px;height: 100px;border-top: 50px solid red;<!--solid: 定义实线边框-->border-right: 50px solid green;border-bottom: 50px solid orangered;border-left: 50px solid blue;}

关键:

border: 50px solid transparent;         border-color设置为【透明】

border-radius: 50%;

border-top-left-radius: 50px;

详情:

CSS实现各种图形 -- 梯形,三角形,扇形,圆形,半圆 - 掘金

盒子充满屏幕 (⭐手写)

相对当前屏幕高度

div.test
{background-color:red;width:100vw;height:100vh;
}

选择器

ID选择器、类选择器、标签选择器(按优先级高到低排序)⭐⭐

<html><head><meta charset=utf-8><style type="text/css">div{color:#ff0000;font-size:20px;}.green{color:#008000;}#black{color:#000000;}</style></head><body><div>红色</div><div class='green'>绿色</div><div id='black'>黑色</div></body>
</html>

特殊符号选择器(>,+,~,空格,逗号)

群组选择器(’,’)

/* 表示同时选择h1,h2 */
h1, h2 {...
}

子元素选择器(空格)

/* 表示选择 h1 下面的所有 span 元素,不管是否以 h1 为直接父元素 */
h1 span {...
}

直接子元素选择器(’>’)

/* 表示 h1 下面的所有以 h1 为直接父元素的 span 元素,注意与空格的区别*/
h1 > span {...
}

相邻兄弟选择器(’+’)

/* 表示选择紧跟在 h1 后的首个兄弟 span 元素,h1 和 span 必须有相同的父元素,即二者必须是同一级元素 */
h1 + span {...
}

兄弟选择器(’~’)

/* 表示选择 h1 后的所有兄弟 span 元素,h1 和 span 必须有相同的父元素,即二者必须是同一级元素。注意与 + 的区别,+ 必须是紧跟着的兄弟元素,而 ~ 不要求紧跟,是所有兄弟元素 */
h1 ~ span {...
}

属性选择器

属性选择元素

[title]
{color:blue;
}

伪类和伪元素选择器(⭐手写)伪类和伪元素选择器

伪类选择器逻辑选择元素

selector:pseudo-class {property:value;}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
a:link {color:#000000;}      /* 未访问链接*/
a:visited {color:#00FF00;}  /* 已访问链接 */
a:hover {color:#FF00FF;}  /* 鼠标移动到链接上 */
a:active {color:#0000FF;}  /* 鼠标点击时 */
</style>
</head>
<body>
<p><b><a href="/css/" target="_blank">这是一个链接</a></b></p>
<p><b>注意:</b> a:hover 必须在 a:link 和 a:visited 之后,需要严格按顺序才能看到效果。</p>
<p><b>注意:</b> a:active 必须在 a:hover 之后。</p>
</body>
</html>
  • nth-child(n)

nth-child(n)匹配属于其父元素的第n个子元素,不论元素类型,n可以是数字、关键词、或公式。关键词odd和even是可用于匹配下标是奇数或偶数的子元素的关键词(第一个子元素的下标是 1)

<html><head><meta charset=utf-8><style type="text/css">ul li:nth-child(even) {background-color: rgb(255,0,0);}</style></head><body><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul></body>
</html>

  • 伪元素
<head><meta charset=utf-8><style type="text/css">div::after{content:"";width: 20px;height: 20px;background-color: rgb(255,0,0);display: block;}</style>
</head>
<body>
<div></div>
</body>
</html>

html模块的div元素加一个后伪元素

  • 伪类只能使用“”,伪元素既可以使用“:”,也可以使用“::
  • 伪元素其实相当于伪造了一个元素,伪类没有伪造元素,例如first-child只是给子元素添加样式而已。(本质区别就是是否抽象创造了新元素

优先级⭐⭐⭐

  • 在同一层级下:权值由高到低
  1. !important  (会覆盖CSS的任何声明,其实与优先级毫无关系)   权值
  2. 内联样式(style=“ ”)                                                                    1000
  3. ID选择器(id=" “)                                                                      100
  4. 伪类选择器(如:hover)
  5. 属性选择器[title]{color:blue;})
  6. Class类选择器(class=” ")                                                              10
  7. HTML标签选择器 (p{})                                                                   1
  8. 通用选择器(*)                                                                            0
  • 不同层级下:

正常来说权重值越高的优先级越高,但是一直以来没有具体的权重值划分,所以目前大多数开发中层级越深的优先级越高

样式方式(按优先级高到低排序)⭐⭐

内联样式表(在标签内设置元素的样式)

写一次只能设置一个

<p style="background:red"></p>

嵌入样式表(在head标签内)

<head><title></title><style type="text/css">p{background-color:yellow;}</style></head>

外部样式表(在head标签内)

rel=relationshiphref=hypertext Reference<head><title></title><link href="xxx.css" rel="stylesheet" type="text/css"/></head>

通过 link 进行对外部CSS样式文件的引用,也可以引用网上别人写好的样式

transform旋转,缩放,平移⭐⭐

修改 CSS 坐标空间,实现旋转,缩放,倾斜或平移

默认相对元素的中心点

Css3 Transform 各种变形旋转 | 菜鸟工具

position关键字⭐⭐⭐

  • static(默认)

该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 toprightbottomleft 和 z-index 属性无效。

z-index 属性指定一个元素的堆叠顺序

拥有更堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面

  • inherit

父元素继承 position 属性的值。

  • relative

相对于其正常位置进行定位。

元素先放置未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。

  • absolute

相对于 static 定位以外第一个父元素进行定位。

元素会被移出正常文档流,并不为元素预留空间。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并

  • fixed:相对于浏览器窗口进行定位。在屏幕滚动时不会改变
  • sticky(CSS3新增) :基于用户滚动的位置,屏幕滚出时会粘住

水平 & 垂直对齐 (⭐手写)

水平居中

指在水平方向上处于中间的位置。

  • 元素/图片:

margin: auto;

行内元素会占整行,看不出来水平居中,所以需要:width: 50%;

  • 文本:

文本标签除了<p>都是行内元素,text-align=center

垂直居中

  • 文本:

line-height = height

  • 图片:

vertical-align: middle;

水平垂直居中

transform:translate

top: 50%;left: 50%;, 是以元素左上角为原点,故不处于中心位置,

加上transform:translate(-50%,-50%) ,元素原点(中心点)往上(x轴),左(y轴)移动自身长宽的 50%,

flex(强烈推荐)

只需要设置 align-items:center; 属性

.wrap {width: 300px;height: 300px;border: 1px solid red;display:flex;justify-content:center;align-items:center;
}.box {height: 100px;width: 100px;border: 1px solid blue;
}

flex布局⭐⭐⭐

布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。

关键是flex布局能触发BFC规范

Flexible box设置或检索弹性盒模型对象的子元素如何分配空间

align-items和justify-content的区别

水平的主轴(main axis)和垂直的交叉轴(cross axis)

flex-direction 属性决定主轴的方向(也就是排列方向)。有4个属性值可以设置。

  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。
  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。

  • align-items 属性定义项目在交叉轴上如何对齐。

baseline

元素位于容器的基线上。

如弹性盒子元素的行内轴与侧轴为同一条,则该值与'flex-start'等效。其它情况下,该值将参与基线对齐。

stretch

默认值。元素被拉伸以适应容器。

如果指定侧轴大小的属性值为'auto',则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照'min/max-width/height'属性的限制。

  • justify-content 属性定义了项目在主轴上的对齐方式。

space-between 均匀排列每个元素,首个元素放置于起点末尾元素放置于终点
space-evenly 均匀排列每个元素,每个元素之间的间隔相等
space-around 均匀排列每个元素,每个元素周围分配相同的空间

flex:1

flex 属性是 flex-grow, flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。后两个属性可选。

flex 属性属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

/* 一个值,width/height: flex-basis */
flex: 10em;
flex: 30px;
flex: min-content;/* 两个值:flex-grow | flex-basis */
flex: 1 30px;/* 两个值:flex-grow | flex-shrink */
flex: 2 2;/* 三个值:flex-grow | flex-shrink | flex-basis */
flex: 2 2 10%;

flex-grow 属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小

BFC规范⭐⭐⭐

问题

  • 外边距重叠:

块的上外边距margin-top和下外边距margin-bottom会合并为单个边距(为单个边距的最大值)

  • 浮动导致父高度塌陷:

  • 不浮动的元素被浮动元素覆盖:

BFC块级格式化上下文(Block Fromatting Context)

决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用

独立布局,盒子内子元素样式不会影响到外面的元素。

常见触发条件

  • overflow: hidden
  • display: flex | inline-block | table-cell
  • position: absolute | fixed

规则

  • BFC就是一个块级元素,块级元素会在垂直方向一个接一个的排列
  • BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签
  • 垂直方向的距离margin决定, 属于同一个BFC的两个相邻的标签外边距会发生重叠
  • 计算BFC的高度时,浮动元素也参与计算

overflow: hidden示例

overflow属性指定如果内容溢出一个元素的框,会发生什么

描述
visible 默认值。内容不会被修剪,会呈现在元素框之外。
hidden 内容会被修剪,并且其余内容是不可见的。
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit 规定应该从父元素继承 overflow 属性的值。

overflow:hidden

  • 避免外边距重叠

  • 清除浮动

  • 阻止元素被浮动元素覆盖:

*浮动

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>float实现浮动</title>
</head>
<style>.z1{height: 200px;width: 200px;float: left;text-align: center;line-height: 200px;background: skyblue;}.fu {width: 400px;}
</style>
<body>
<div class="fu clearfix"><div class="z1">设置了float为left的图片</div><div class="z2">你看,我没有被浮动哥哥挡住哦,这是一段神奇旅行,一天我遇上了白雪公主</div>
</div>
</body>
</html>

即使图片浮动了,破坏了文档流,也覆盖在没有浮动的元素上了,但是其并没有将文本内容也覆盖掉 ,证明了被设计出来的主要目的:实现文字环绕图片排版功能

absolute的容器,才是意义上的完全脱离文档流。覆盖在当前位置上的所有容器和文本内容之上。

absolutefloat都不会去覆盖掉在他们之前的正常文档流,这应该和浏览器渲染机制有关系,会从上到下依次渲染内容,渲染成功后,就不会因为后续元素浮动而使其被覆盖住(不考虑使用fix等强行覆盖的情况)。

三栏布局 :左右固定,中间自适应(⭐手写)

​​​​​​​

flex布局(强烈推荐)

  • 基础巩固

flex 属性用于设置或检索弹性盒模型对象的子元素如何分配空间。

flex 属性是 flex-grow、flex-shrink 和 flex-basis 属性的简写属性。

注意:如果元素不是弹性盒模型对象的子元素,则 flex 属性不起作用。

  • 实现方法

左右两栏设置宽度,中间栏设置 flex:1,占满余下部分

<!DOCTYPE html>
<html lang="en"><head><title>flex布局</title><style>.main{height: 60px;display: flex;}.left,.right{height: 100%;width: 200px;background-color: #ccc;}.content{flex: 1;background-color: #eee;}</style>
</head><body><div class="main"><div class="left"></div><div class="content"></div><div class="right"></div></div>
</body></html>

grid布局

  • 基础巩固

grid:CSS 所有网格容器的简写属性

grid-template-rows / grid-template-columns :设置列和行的尺寸。

  • 实现方法

左右两栏设置宽度,中间栏宽度auto

<!DOCTYPE html>
<html lang="en"><head><title>grid布局</title><style>body {display: grid;grid-template-columns: 200px auto 200px;grid-template-rows: 60px;}.left,.right {background-color: #ccc;}.content {background-color: #eee;}</style>
</head><body><div class="left"></div><div class="content"></div><div class="right"></div>
</body></html>

margin负值法

  • 原理解释
  • 实现方法:

左右两栏均左浮动,外层盒子左浮动,

中间栏设置左右两栏宽度的margin值,

左栏设置margin -100%(向左移动整个屏幕的距离),

右栏设置 margin值为负的盒子宽度。

<!DOCTYPE html>
<html lang="en"><head><title>margin负值</title><style>.left,.right {float: left;width: 200px;height: 60px;background-color: #eee;}.left {margin-left: -100%;}.right {margin-left: -200px;}.main {width: 100%;float: left;height: 60px;}.content {height: 60px;margin: 0 200px;background-color: #ccc;}</style>
</head><body><div class="main"><div class="content"></div></div><div class="left"></div><div class="right"></div>
</body></html>

自身浮动

<!DOCTYPE html>
<html lang="en"><head><title>自身浮动法</title><style>.left,.right {height: 60px;width: 200px;background-color: #eee;}.left {float: left;}.right {float: right;}.content{height: 60px;background-color: #ccc;margin: 0 200px;}</style>
</head><body><div class="left"></div><div class="right"></div><div class="content"></div>
</body></html>

绝对定位

左右两栏绝对定位,分别定位到盒子的两侧,中间栏采用margin值撑开盒子

注意:采用定位时,浏览器默认的padding或margin值会影响布局,需要初始化样式 margin:0;padding:0;

圣杯布局 (⭐手写)

两边固定,中间自适应,且中间栏放在文档流的前面,率先渲染

基本的dom结构(注意center需要排在第一个位置)

<div class="header">header</div><div class="container"><div class="center column">center</div><div class="left column" >left</div><div class="right column" >right</div></div>
<div class="footer">footer</div>

或者

<section class="container"><article class="center"><br /><br /><br /></article><article class="left"><br /><br /><br /></article><article class="right"><br /><br /><br /></article></section>

<br> 标签插入一个简单的换行符

  • 定位+浮动
<!DOCTYPE html>
<html><head><meta charset=utf-8><style type="text/css">* {margin: 0;padding: 0;}.container {border: 1px solid black;/* 防止容器盒子高度塌陷和给之后的左、右浮动元素预留位置 */overflow: hidden;padding: 0px 100px;min-width: 100px;}.left {background-color: greenyellow;/* 保证之后的"margin-left"属性可以将自身拉到上一行 */float: left;/* 固定宽度 */width: 100px;/* 将元素向左移动属性值的单位,100%相对于父容器计算 */margin-left: -100%;/* 相对定位,需要将自身再向左移动自身的宽度,进入容器的"padding-left"区域 */position: relative;/* 自身的宽度,刚好进入容器的"padding-left"区域 */left: -100px;}.center {background-color: darkorange;float: left;width: 100%;}.right {background-color: darkgreen;float: left;width: 100px;margin-left: -100px;position: relative;left: 100px;}</style></head><body><section class="container"><article class="center"><br /><br /><br /></article><article class="left"><br /><br /><br /></article><article class="right"><br /><br /><br /></article></section></body>
</html>

magin-left:-100%

这个百分比是以父元素内容长度的百分比,该父元素内容长度需要去除padding magin border。由于长度设置为了100%,需要一整行的宽度补偿margin,则移到最左边。

magin-left:-100px

margin负值会改变元素占据的空间,及移到父元素的最左边,并且该子元素width即为100px

单位⭐⭐⭐

  1. 绝对长度单位:px  像素
  2. 百分比: %
  3. 相对元素字体大小单位: em
  4. 相对于元素字体大小的单位: rem(默认16px
  5. 相对于视口*宽度的百分比(100vw即视窗宽度的100%): vw
  6. 相对于视口*高度的百分比(100vh即视窗高度的100%): vh

px转rem

相对于元素字体大小的单位: rem(默认16px)

PostCss是一个用JavaScript工具和插件转换CSS代码的工具。postcss-pxtorem

px转vw

网页宽度=1920px 网页高度=1080px

1920px = 100vw

1080px = 100vh

宽 300px 和 200px 的 div ,其所占的宽高,以 vw 和 vh 为单位

vwDiv = (300px / 1920px ) * 100vw

vhDiv = (200px / 1080px ) * 100vh

当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕

 可自定义scss函数。

$vm_base: 1920;
$vh_base: 1080;@function vw($px) {
@return ($px / $vm_base) * 100vw;
}
@function vh($px) {
@return ($px / $vh_base) * 100vh;
}.head{
font-size:vh(100);
}

opacity: 0、visibility: hidden、display: none⭐⭐⭐

区别 opacity: 0 visibility: hidden display: none
页面布局 不改变 不改变 改变
触发事件 能触发 不能触发 不能触发

img的 title 和 alt 有什么区别⭐

  • 通常当鼠标滑动到元素上的时候显示
  • alt(alternative) 是<img> 的特有属性,是图片内容的等价描述,用于图片无法加载显示、读屏器阅读图片。可提图片高可访问性,除了纯装饰图片外都必须设置有意义的值,搜索引擎会重点分析。

行内素、块级元素和行内块元素⭐⭐⭐

display:inline;// 转换为行内元素
display:block;// 转换为块级元素
display:inline-block// 转换为行内块元素

从 HTML 的角度来讲,标签分为:

  • 文本级标签pspanabiuem
  • 容器级标签divh系列lidtdd

行内元素:除了p之外,所有的文本级标签,都是行内元素,p是个文本级,但是是个块级元素

块级元素:所有的容器级标签都是块级元素,还有p标签

块标签:div、h1~h6、ul、li、table、p、br、form。
特征:独占一行,换行显示,可以设置宽高,可以嵌套块和行

行标签:span、a、img、textarea、select、option、input。
特征:只有在行内显示,不会自动进行换行,内容撑开宽、高,不可以设置宽、高(img、input、textarea等除外)。(设置float后可以设置宽、高)

对 margin 仅设置左右方向有效,上下无效,padding 设置上下左右都有效

溢出转省略 (⭐手写)⭐⭐

单行多行,都要overflow: hidden;

单行

定元素内的空白处理white-space:nowrap; 文本不进行换行;默认值normal

overflow: hidden;
text-overflow:ellipsis;  //ellipsis;省略
white-space: nowrap;  //nowrap 不换行

多行

1.-webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:
2.display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
3.-webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。

 IE不兼容

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
.text2{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
</style> </head>
<body><div class="text2">这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话这是一句话
</div></body>
</html>

布局

静态布局

  • 描述:就是设定好的长和宽,大小不会改变,不管你多大的屏幕它都是那么大,分辨率是不会改变的
  • 优点:这个对于开发者来说是最简单的一种布局方式,没有什么兼容性的问题
  • 缺点:窗口的大小比显示的内容小。,会展现出滚动条
  • 场景:传统web网站

响应式布局⭐⭐

  • 使用媒体查询(@media)
  • 使用flex弹性布局
  • 使用百分比单位:rem单位,VH、HW单位

自适应和响应式区别

pc端(>1024)一套适配,平板(768-1024)一套适配,手机端(<768)

自适应设计(AWD):

  • 需要开发多套界面;
  • 通过检测视口分辨率,来判断当前访问的设备是:pc端、平板、手机,
  • 从而请求服务层,返回不同的页面;

响应式设计(RWD):

  • 只需开发一套界面。
  • 通过检测视口分辨率,
  • 针对不同客户端在客户端做代码处理,通过CSS Media Query,Content - Based Breakpoint等技术展现不同的布局和内容。

弹性布局(flex布局)

  • 描述:目前比较流行的一种布局,使用传统布局难以实现一些复杂的布局,使用flex布局实现就变得非常容易
  • 优点:简便、完整、响应式地实现各种页面布局
  • 缺点:只兼容IE10+的浏览器
  • 场景:三栏式布局、垂直水平居中布局

流式布局

  • 描述:页面元素的宽度按照屏幕分辨率进行适配调整,但整体布局不变。主要特征是像瀑布一样往下流,有规律的无限遍历模块
  • 优点:灵活,充分利用浏览器的空间
  • 缺点:宽度按照屏幕进行适配调整,对于大屏幕来说用户体验并不是特别好,有些布局元素会显得很长
  • 场景:类似抖音视频、微博消息、微信朋友圈等布局

媒体查询@media(css3)

@media可以针对不同的屏幕尺寸设置不同的样式。 例如,可以缩小小型设备上的字体大小

@media 规则可置于代码的顶层或位于其它任何@条件规则组内

/* 在 screen 类型 大于560px 小于 700px 加载 */@media screen and (min-width: 560px) and (max-width: 700px) {.box1 {background-color: burlywood;}}

媒体类型

① all,适用于所有设备。默认使用该值。

② print,适用于在打印预览模式下在屏幕上查看的分页材料和文档。

③ screen,主要屏幕设备,例如电脑屏幕,平板电脑,智能手机等。

④ speech,主要用于语音合成器。

逻辑运算符(logical operators)

not, and, 似于逻辑或or运算符),only

逗号分隔多个媒体查询来将它们合并为一个规则

/* 在 screen 类型 大于560px 或 小于240px 加载  */@media screen and (min-width: 560px), (max-width: 240px) {.box {background-color: red;}}/* 在 screen 类型 小于 240px 或 大于360px 小于 700px 加载 */@media screen and (max-width: 240px), (min-width: 360px) and (max-width: 700px) {.box1 {background-color: burlywood;}}

媒体功能

  • height 输出设备中的页面可见区域高度。
  • width 输出设备中的页面可见区域宽度。
  • max-aspect-ratio 输出设备的页面可见宽度与高度的最大比率。
  • max-device-aspect-ratio 输出设备的屏幕可见宽度与高度的最大比率。
  • max-device-height 输出设备的屏幕可见的最大高度。
  • max-device-width 输出设备的屏幕最大可见宽度。
  • max-height 输出设备中的页面最大可见区域高度。
  • max-width 输出设备中的页面最大可见区域宽度。
  • min-height 输出设备中的页面最小可见区域高度。
  • min-width 输出设备中的页面最小可见区域宽度。

其他加载方式

style标签上加载

<style media="(min-width: 500px)">.box {background-color: red;}
</style>
<style media="(max-width: 500px">.box {background-color: burlywood;}
</style>
  • 根据media属性定义的媒体查询判断加载那个样式。

@import 使用时加载

@import url(./index.css) (min-width:350px);
@import url(./home.css) (max-width:750px);
  • 在加载最后添加()定义媒体查询判断加载那个样式。

<picture>标签

<picture><source media="(min-width: 650px)" srcset="demo1.jpg"><source media="(min-width: 465px)" srcset="demo2.jpg"><img src="img_girl.jpg">
</picture>
  • 根据屏幕匹配的不同尺寸显示不同图片,如果没有匹配到或浏览器不支持 picture 属性则使用 img 元素

JavaScript

语言区别

  • 面向过程:通过函数一步一步实现这些步骤,接着依次调用即可

优点:性能上它是优于面向对象的,因为类在调用的时候需要实例化,开销过大。

缺点:不易维护、复用、扩展

用途:单片机、嵌入式开发、Linux/Unix等对性能要求较高的地方

  • 面向对象:将数据与函数绑定到一起,进行封装减少了重复代码的重写过程

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 。

缺点:性能比面向过程低

(多态:同类不同对象)

  • 基于原型的面向对象:js
  • 比喻:原型(原始吸血鬼),被传染的吸血鬼

前端,追求灵活性,

  • 基于类的面向对象:c++,Java,Python

类是模具,对象是实体

多用于服务端,更追求稳定性

比喻:量产的机器人

BOM,DOM,文档,对象,模型

BOM,

Browser Object Model浏览器对象模型,是JavaScript的组成之一,它提供了独立于内容与浏览器窗口进行交互的对象,使用浏览器对象模型可以实现与HTML的交互。它的作用是将相关的元素组织包装起来,提供给程序设计人员使用,从而降低开发人员的劳动量,提高设计Web页面的能力。

window : alert() , prompt() , confirm() , setInterval() , clearInterval() , setTimeout() , clearTimeout() ;

history : go(参数) , back() , foward() ;

location : herf属性.

1、window.location.href = '你所要跳转到的页面'; 2、window.open('你所要跳转到的页面’); 2、window.history.back(-1):返回上一页 4、window.history.go(-1/1):返回上一页或下一页五、 3、history.go("baidu.com");
4、window.print() 直接掉用打印窗口可以用来拔面试题。

DOM,全称Document Object Model 文档对象模型。JS中通过DOM来对HTML文档进行操作
文档是整个的HTML网页文档
将网页中的每一个部分都转换为了一个对象
使用模型来表示对象之间的关系,方便获取对象

ES6新增

  1. 数据类型:基本数据类型Symbol,引用数据类型Set ,Map
  2. 运算符:变量的解构赋值,对象和数组新增了扩展运算符
  3. 字符串方法:${ },需要配合单反引号好完成字符串拼接的功能,eg:`http://localhost:3000/search/users?q=${keyWord}`
  4. 块级作用域:let,const
  5. 原生提供 Proxy 构造函数,用来生成 Proxy 实例
  6. 定义类的语法糖(class)
  7. 模块化import/export
  8. 生成器(Generator)和遍历器(Iterator)

数据类型

基本数据类型

ES5:Null,Undefined,Number,String,Boolean

ES6新增:Symbol(仅有目的:作为对象属性的标识符,表示唯一的值)

var obj = {};obj[Symbol("a")] = "a";//会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,
//如果找到了,则返回它,
//否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
Symbol.for(key);Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol

ES10新增:BigInt(表示任意的大整数)

let bnum=1684424684321231561n  //方式1:数组后加n
bunm=BigInt("1684424684321231561")//方式2:调用BigInt

存储在栈(大小固定,先进后出)

引用数据类型

Object,function,Array,Date,RegExp,ES6新增:Set,MAP

地址存储在栈,内容存储在堆(树形结构,队列,先进先出)

声明和定义

变量声明不开辟内存,只是告诉编译器,要声明的部分存在,要预留部分的空间。var i;

变量定义开辟内存。 var i=123;

Null,NaN,Undefined

  • null:空对象,一般作为对象的初值
  • Nan:浮点数中表示未定义或不可表示的值,例如0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞
  • undefined:未定义,声明但未定义,例如,形参未传参,获取return的函数返回,对象属性名不存在

toString,valueOf

javascript中所有数据类型都拥有valueOf和toString这两个方法,null和undefined除外

  • valueOf偏向于运算,toString偏向于显示

对象字面量表达式是加 ():({}).toString()

  • valueOf:除了Date其他的都是返回数据本身

==,===,Object.is()

  • ==:自动数据类型转换

强制转换规则

  1. string和number,string->number,
  2. 其他类型和boolean,bool->number
  3. 对象和非对象,对象先调用 ToPrimitive 抽象操作(调用valueOf()或toString()
  4. null==undefined值转为Boolean值false
  5. NaN!=NaN
  • ===:严格模式,不进行自动数据类型转换,比较的是栈中值(即基本数据类型的值,或者引用数据类型的地址)
  • Object.is():在===基础上特别处理了NaN,-0,+0,保证-0与+0不相等,但NaN与NaN相等

Object.is(+0,-0) //false

Object.is(NaN,NaN) //true

判断数据类型:typeof运算符,instance of运算符,isPrototypeOf() 方法,constructor,Object prototype

  • typeof:判断 基本数据类型
  • instance of:判断 引用数据类型,在其原型链中能否找到该类型的原型
  • isPrototypeOf() :在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。
Foo.prototype.isPrototypeOf(baz)
  • constructor:判断 所有数据类型不包含继承引用数据类型的自定义类型

(数据).constructor === 数据类型

  • Object.prototype.toString.call():Object 对象的原型方法 toString 来判断数据类型:

instance of (⭐手写)

第一个实例参数是否在第二个函数参数的原型链上

  1. 获取首个对象参数的原型对象
  2. 获取Fn函数的原型对象
  3. 进入死循环,当两个参数的原型对象相等时返回true
  4. 当两个参数的原型对象不相等时获取首个对象参数原型的原型并且循环该步骤直到null时返回false
const _instanceof = (target, Fn) => {let proto = target.__proto__let prototype = Fn.prototypewhile(true) {if(proto === Fn.prototype) return trueif(proto === null) return falseproto = proto.__proto__}
}const _instanceof = (target, Fn) => {return Fn.prototype.isPrototypeOf(target);}

new (⭐手写)

"_new"函数,该函数会返回一个对象,

该对象的构造函数为函数参数、原型对象为函数参数的原型,核心步骤有:

  1. 创建一个新对象
  2. 获取函数参数
  3. 将新对象的原型对象和函数参数的原型连接起来
  4. 将新对象和参数传给构造器执行
  5. 如果构造器返回的不是对象,那么就返回第一个新对象
const _new = function() {const object1 = {}const Fn = [...arguments].shift()object1.__proto__ = Fn.prototypeconst object2 = Fn.apply(object1, arguments)return object2 instanceof Object ? object2 : object1
}

类型转换

  • 转换为数字:

Number():可以把任意值转换成数字,如果要转换的字符串中有不是数字的值,则会返回NaN

parseInt(string,radix):解析一个字符串并返回指定基数的十进制整数,radix是2-36之间的整数,表示被解析字符串的基数。

parseFloat(string):解析一个参数并返回一个浮点数

隐式转换:

  1. let str = '123'

  2. let res = str - 1 //122

  3. str+1 // '1231'

  4. +str+1 // 124

  • 转换为字符串

.toString()  ⚠️注意:null,undefined不能调用

String() 都能转

隐式转换:当+两边有一个是字符串,另一个是其它类型时,会先把其它类型转换为字符串再进行字符串拼接,返回字符串

转换为布尔值

Boolean():0, ''(空字符串), null, undefined, NaN会转成false,其它都是true

隐式转换 !!

type of null

typeof null 的结果是Object。

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits)

000: object   - 当前存储的数据指向一个对象。

null 的值是机器码 NULL 指针(null 指针的值全是 0)

那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。

事件

文档和浏览器窗口中发生的特定交互

DOM事件流(event flow )

先捕获再冒泡。存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

  • 事件捕获:由外往内,从事件发生的根节点开始,逐级往下查找,一直到目标元素。
  • 事件冒泡:由内往外,从具体的目标元素触发,逐级向上传递,直到根节点
element.addEventListener(event, function[, useCapture]);
//useCapture 默认为false,即冒泡阶段调用事件处理函数,
//为ture时,在事件捕获阶段调用处理函数

事件委托/代理(⭐手写)

事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。

应用

1000button注册点击事件。如果循环给每个按钮添加点击事件,那么会增加内存损耗,影响性能

好处:

  1. 替代循环绑定事件的操作,减少内存消耗,提高性能。比如:ul上代理所有liclick事件。

  2. 简化了dom节点更新时,相应事件的更新。比如:

    • 不用在新添加的li绑定click事件。
    • 当删除某个li时,不用解绑上面的click事件。

缺点

  1. 事件委托基于冒泡,对于不冒泡的事件不支持。
  2. 层级过多,冒泡过程中,可能会被某层阻止掉
  3. 理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td

阻止事件冒泡:event.stopPropagation() .stop修饰符

1. 给"ul"标签添加点击事件
2. 当点击某"li"标签时,该标签内容拼接"."符号。如:某"li"标签被点击时,该标签内容为".."
注意:
1. 必须使用DOM0级标准事件(onclick)target表示当前触发事件的元素
currentTarget是绑定处理函数的元素
只有当事件处理函数绑定在自身的时候,target才会和currentTarget一样<ul><li>.</li><li>.</li><li>.</li>
</ul><script type="text/javascript">document.querySelector('ul').onclick=event=>{event.target.innerText+='.'}
</script>

发布订阅模式(⭐手写)

完成"EventEmitter"类实现发布订阅模式。
1. 同一名称事件可能有多个不同的执行函数:构造函数中创建”events“对象变量存放所有的事件
2. 通过"on"函数添加事件:订阅事件。当总事件中不存在此事件时创建新事件数组,当存在时将”fn“函数添加在该事件对应数组中
3. 通过"emit"函数触发事件:发布事件,遍历该事件下的函数数组全部执行

class EventEmitter {constructor() {this.events = {}//二维,events' funcs}//添加事件:订阅事件on(event, fn) {if(!this.events[event]) {//当总事件中不存在此事件时创建新的事件数组this.events[event] = [fn]} else {                 //当存在时将”fn“函数添加在该事件对应数组中this.events[event].push(fn)}}//触发事件:发布事件emit(event) {if(this.events[event]) {//遍历该事件下的函数数组并全部执行this.events[event].forEach(callback => callback())}}
}

观察者模式(⭐手写)

"Observerd"类实现观察者模式。要求如下:
"Observer"为观察者,"Observerd"为被观察者

  1. 被观察者构造函数声明三个属性分别为"name"用于保存被观察者姓名、"state"用于保存被观察者状态、"observers"用于保存观察者们
  2. 被观察者创建"setObserver"函数,用于保存观察者们,该函数通过数组的push函数将观察者参数传入"observers"数组中
  3. 被观察者创建"setState"函数,设置该观察者"state"并且通知所有观察者,该函数首先通过参数修改被观察者的"state"属性,然后通过遍历"observers"数组分别调用各个观察者的"update"函数并且将该被观察者作为参数传入
  4. 观察者创建"update"函数,用于被观察者进行消息通知,该函数需要打印(console.log)数据,数据格式为:小明正在走路。其中"小明"为被观察者的"name"属性,"走路"为被观察者的"state"属性
//被观察者
class Observerd {constructor(name) {this.name = namethis.state = '走路'this.observers = []}setObserver(observer) {this.observers.push(observer)}setState(state) {this.state = statethis.observers.forEach(observer => observer.update(this))}
}
//观察者
class Observer {constructor() {}update(observerd) {console.log(observerd.name + '正在' + observerd.state)}
}

封装事件绑定

绑定事件的元素.addEventListener(事件类型,执行函数,true/false) 默认值为false(即 使用事件冒泡)true 事件捕获

document.addEventListener("click", function(){document.getElementById("demo").innerHTML = "Hello World";
});

执行上下文/作用域和作用链

作用域就是一个变量可以使用的范围

C/C++中有块级作用域,变量在声明它们的代码段之外是不可见的

javascript的作用域是相对函数而言的,可以称为函数作用域

全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象。

函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文。

 js为每一个执行环境关联了一个变量对象。环境中 定义的 所有变量和函数 都保存在这个对象中。
全局执行环境被认为是window对象

这样由多个执行上下文的变量对象构成的链表就叫做作用域链,从某种意义上很类似原型和原型链。

当前作用域外的变量都是自由变量,一个变量在当前作用域没有定义,但是被使用了,就会向上级作用域

作用域链和原型继承查找时的区别:

查找一个普通对象的属性,但是在当前对象和其原型中都找不到时,会返回undefined
查找的属性在作用域链中不存在的话就会抛出ReferenceError

this

若是在全局环境(例如,普通函数,匿名函数)中,则this指向window;( 严格模式下this会指向 undefined)

对象里调用的this,指向调用函数的那个对象,

JS预解析(变量提升)

预编译/解析:JS代码在执行前,浏览器会对js代码进行扫描,默认的把所有带var和function声明的变量进行定义,创建执行上下文,初始化一些代码执行时需要用到的对象。

var,let 和 const关键字

在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量

ES6新增,块级作用域(由大括号包裹,比如:if(){},for(){}等)

  • var:可以跨块访问, 不能跨函数访问,允许重复声明,变量提升
  • let、const:只能在块作用域里访问,不允许在相同作用域中重复声明,不存在变量提升
  • const :声明一个只读的常量,使用时必须初始化(即必须赋值),一旦声明,常量的值就不能改变,(即,栈中的值不能变,引用类型,内存地址不能修改,可以修改里面的值。)。

原型链

console.log(Person.prototype);
// {constructor: ƒ}
//      constructor: ƒ Person()
//          arguments: null
//          caller: null
//          length: 0
//          name: "Person"
//          prototype: {constructor: ƒ}
//          __proto__: ƒ ()
//          [[FunctionLocation]]: 09-原型对象.html:8
//          [[Scopes]]: Scopes[1]
//      __proto__: Object

(引用类型统称为object类型)

所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
所有函数  都有一个prototype(原型)  属性,属性值是一个普通的对象

构造函数和类同名

_ _ proto _ _

person.prototype.isPrototypeOf(stu)
只要调用对象在传入对象的原型链上都会返回true


首先,fn的构造函数是Foo()。所以:
fn._ _ proto _ _=== Foo.prototype
又因为Foo.prototype是一个普通的对象,它的构造函数是Object,

Foo.prototype=object

所以:
Foo.prototype._ _ proto _ _=== Object.prototype

【原型和原型链】什么是原型和原型链_TowYingWang的博客-CSDN博客_原型和原型链

寄生组合式继承(⭐手写)

通过寄生组合式继承使"Chinese"构造函数继承于"Human"构造函数。要求如下:
1. 给"Human"构造函数的原型上添加"getName"函数,该函数返回调用该函数对象的"name"属性
2. 给"Chinese"构造函数的原型上添加"getAge"函数,该函数返回调用该函数对象的"age"属性

  1. 在"Human"构造函数的原型上添加"getName"函数
  2. 在”Chinese“构造函数中通过call函数借助”Human“的构造器来获得通用属性
  3. Object.create函数返回一个对象,该对象的__proto__属性为对象参数的原型。此时将”Chinese“构造函数的原型和通过Object.create返回的实例对象联系起来
  4. 最后修复"Chinese"构造函数的原型链,即自身的"constructor"属性需要指向自身
  5. 在”Chinese“构造函数的原型上添加”getAge“函数
function Human(name) {this.name = namethis.kingdom = 'animal'this.color = ['yellow', 'white', 'brown', 'black']
}
Human.prototype.getName = function() {return this.name
}function Chinese(name,age) {Human.call(this,name)//call函数借助”Human“的构造器来获得通用属性this.age = agethis.color = 'yellow'
}//返回的对象__proto__属性为对象参数的原型
Chinese.prototype = Object.create(Human.prototype)//使用现有的对象来作为新创建对象的原型
//修复"Chinese"构造函数的原型链,即自身的"constructor"属性需要指向自身
Chinese.prototype.constructor = ChineseChinese.prototype.getAge = function() {return this.age
}

【原型和原型链】什么是原型和原型链_TowYingWang的博客-CSDN博客_原型和原型链

Iterator,for in,for of,forEach,map循环遍历

Iterator

一种接口,为各种不同的数据结构提供统一的访问机制

例如Array.prototype[@@iterator]()

Array 对象的 @@iterator 方法实现了迭代协议,并允许数组被大多数期望可迭代的语法所使用,例如展开语法和 for...of 循环。它返回一个迭代器,生成数组中每个索引的值。

for of

["a", "b", "c", "d"];for…of 循环读取键值// a b c d

支持迭代协议的数据结构(数组、字符串、Set、Map 等),不包括对象

对于字符串,类数组,类型数组的迭代,循环内部调用的是数据结构的Symbol.iterator方法。

for...of 不能循环普通的对象,需要通过和 Object.keys()搭配使用

const object1 = {a: 'somestring',b: 42,c: false
};console.log(Object.keys(object1));
// Expected output: Array ["a", "b", "c"]

for in

["a", "b", "c", "d"];for…in 循环读取键名 // 0 1 2 3

适用于遍历对象公有 可枚举属性,无法遍历 symbol 属性

hasOwnProperty() 方法来判断属性是否来自对象本身,并避免遍历原型链上的属性。

var triangle = {a: 1, b: 2, c: 3};function ColoredTriangle() {this.color = 'red';
}ColoredTriangle.prototype = triangle;var obj = new ColoredTriangle();for (var prop in obj) {if (obj.hasOwnProperty(prop)) {console.log(`obj.${prop} = ${obj[prop]}`);}
}// Output:
// "obj.color = red"

forEach

arr.forEach(value[,index,默认隐藏参数arr])

适用于需要知道索引值数组遍历,但是不能中断( break 和 return

如果需要跳出循环可以使用 some() 或 every() 方法


const isBelowThreshold = (currentValue) => currentValue < 30;const array1 = [1, 30, 39, 29, 10, 13];array1.forEach(element => console.log(element));console.log(array1.every(isBelowThreshold));
// Expected output: false//是不是至少有 1 个元素
console.log(array1.some(isBelowThreshold));//空数组,则返回false。
// Expected output: true

map

map 方法,基本用法与 forEach 一致

  1. forEach()方法不会返回执行结果,而是undefined
  2. map()方法会得到一个新的数组并返回
  3. 同样的一组数组,map()的执行速度优于 forEach()(map() 底层做了深度优化

匿名函数、箭头函数、构造函数

匿名函数

关键词 function没有函数名

//声明匿名函数
let  myFun = function( a,b ){console.info( a+b);
};
//执行
myFun( 10,30 );//等同于  立即执行匿名函数(function(a,b){console.info( a+b );
})(10,30);

箭头函数

连function都没有的匿名函数,箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this

箭头函数不绑定arguments,取而代之用rest参数解决

不可以使用yield,因此箭头函数不能用作Generator函数。

没有原型prototype,没有super用于访问原型属性。

//传递给getVal函数内的this并不是调用者自身,而是外部的this,即window
this.val = 2;
var obj = {val: 1,getVal: () => {console.log(this.val);}
}obj.getVal(); // 2

构造函数

function Person(name,id)
{this.name=name;this.id=id;this.sayHi=function() {alert("Hi")}} var  p= new Person('参宿','7');     
  • 习惯上首字母大写
  • 使用new关键字进行调用

this

普通函数的this在运行时创建,匿名函数this指向window,箭头函数的this是定义时确定。

箭头函数不能用作构造函数:

因为构造函数的this指向实例对象,但是箭头函数无法对创建出来的实例进行this绑定

也不能使用call()、apply()、bind() 去改变this的指向。

call、apply、bind改变this

call()和apply()唯一区别:

call()接受的是一个参数列表

apply() 方法接受的是一个包含多个参数的数组

var obj1 = {name: 1,getName: function (num = '') {return this.name + num;}
};var obj2 = {name: 2,
};
// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数
console.log(obj1.getName()); // 1
console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4

bind:语法和call一样,区别在于call立即执行,bind等待执行,bind不兼容IE6~8

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用

call (⭐手写)

    // 给function的原型上面添加一个 _call 方法Function.prototype._call = function (context) {//  判断调用者是否是一个函数  this 就是调用者if (typeof this !== 'function') {throw new TypeError('what is to be a function')}// 如果有 context 传参就是传参者 没有就是windowcontext = context || window// 保存当前调用的函数context._this = this   // 截取传过来的参数/*argumentsa: 1fn: ƒ fns()*/// 通过 slice 来截取传过来的参数const local = [...arguments].slice(1)// 传入参数调用函数let result = context._this(...local)// 删属性delete context._thisreturn result}let obj = { a: 1 }function fns(a, b) {console.log(a, b);console.log(this)}fns._call(obj, 23, 555)

apply(⭐手写)

    // 给function的原型上面添加一个 _apply 方法Function.prototype._apply= function (context) {//  判断调用者是否是一个函数  this 就是调用者if (typeof this !== 'function') {throw new TypeError('what is to be a function')}// 如果有 context 传参就是传参者 没有就是windowcontext = context || window// 保存当前调用的函数context._this = this   // 截取传过来的参数/*argumentsa: 1fn: ƒ fns()*///!!!!!!!!!!!!!!与call的唯一区别!!!!!!!!!!!// 这里开始判断传入的参数是否存在,此时参数是一个数组形式[thisArg,[传参]]// 那么如果arguments[1]即传参存在的时候,就是需要传参调用保存的函数// 如果不存在就直接调用函数if (arguments[1]) {result = context._this(...arguments[1])//!!!!将数组展开!!!!} else {result = context._this()}//!!!!!!!!!!!!!!与call的唯一区别!!!!!!!!!!!// 删属性delete context._thisreturn result}let obj = { a: 1 }function fns(a, b) {console.log(a, b);console.log(this)}fns._call(obj, 23, 555)

bind(⭐手写)

Function.prototype._bind = function (context) {if (typeof this !== 'function') {throw new TypeError('what is to be a function')}var _this = this; // 保存调用bind的函数var context = context || window; // 确定被指向的this,如果context为空,执行作用域的this就需要顶上喽return function(){return _this.apply(context, [...arguments].slice(1)); // 如果只传context,则[...arguments].slice(1)为空数组}
};var obj = {name: 1,getName: function(){console.log(this.name)}
};var func = function(){console.log(this.name);
}._bind(obj);func(); // 1

闭包(closure)

类比背包,当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包。背包中是函数声明时作用域内的所有变量

var name = '余光';function foo() {console.log(name); // 余光
}(function (func) {var name = '老王';func()
})(foo); // 余光

因为js作用域生命周期在于内部脚本是否全部执行完毕才会销毁,并且不会带到父级作用域

函数内部返回一个函数,子函数没在父级作用域内完成整个生命周期的话,父级函数是没办法完成一整个生命周期的,闭包正是利用这一点卡住了父级函数的作用域。

因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。

面试的时候,直接回答函数嵌套函数,且内部函数调用父级作用域的变量就可以称之为闭包了。

 1: function createCounter() {2:   let counter = 03:   const myFunction = function() {4:     counter = counter + 15:     return counter6:   }7:   return myFunction8: }9: const increment = createCounter()
10: const c1 = increment()
11: const c2 = increment()
12: const c3 = increment()
13: console.log('example increment', c1, c2, c3)
  • 闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
  • 滥用闭包容易内存泄漏
  • 使用场景 : 防抖、节流函数套函数避免全局污染

正则表达式Regular Expression(RegExp)

字符串搜索模式

/正则表达式主体/修饰符(可选)

RegExp 对象是一个预定义了属性和方法的正则表达式对象

regexp.test(str)返回Bool

regexp.exec(str)返回匹配的子串 或者 null

常用修饰符

i ignoreCase  执行对大小写不敏感的匹配。
g global  执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。

常用字符

\标记下一个字符是特殊字符或文字。例如,"n”和字符"n”匹配。"\n"则和换行字符匹配。

^匹配输入的开头.
$匹配输入的末尾

·匹配除换行字符外的任何单个字符
*匹配前一个字符零或多次。例如,"zo*”与"z”或"zoo”匹配。
+匹配前一个字符一次或多次。例如,"zo+"与"zoo”匹配,但和"z”不匹配。
?匹配前一个字符零或一次。例如,"a?ve?”和"never"中的“"ve”匹配。
x|y 匹配x或y
{n}匹配n次。n是非负整数
{n,} n是一个非负整数。至少匹配n次。例如,"o{2,)"和"Bob”中的"o”不匹配,但和"foooood"中的所有o匹配。"o{1}”与"o+”等效。"o{0,}”和"o*”等效。
{n,m}m和n是非负整数。至少匹配n次而至多匹配 m次。例如,"o{1,3]"和"fooooood”中的前三个o匹配。"o{0,1}”和“o?”等效。
[xyz]匹配括号内的任一字符。例如,"[abc]"和"plain”中的"a”匹配。

[^xyz]匹配非括号内的任何字符。例如,"[^abc]"和“plain”中的"p”匹配。
[a-z]字符范围。和指定范围内的任一字符匹配。例如,"[a-z]”匹配"a"到"z"范围内的任一小写的字母表字符。
[^m-z]否定字符范围。匹配不在指定范围内的任何字符。例如,"[m-z]”匹配不在"m"到"z"范围内的任何字符。

助记:digital

\d匹配数字字符。等价于[0-9]。
\D匹配非数字字符。等价于[^0-9]。

助记:space

\s匹配任何空白,包括空格、制表、换页等。与"[ \fn\rlt\v]”等效。
\S匹配任何非空白字符。与"[^ \fn\rlt\v]”等效。

\w匹配包括下划线在内的任何字字符。与"[A-Za-z0-9_]”等效。

\W匹配任何非字字符。与"[^A-Za-z0-9_]”等效。

合法的URL (⭐手写)

URL结构一般包括协议、主机名、主机端口、路径、请求信息、哈希

  1. 首先必须是以http(s)开头并且可以不包含协议头部信息
  2. 主机名可以使用"-"符号,所以两种情况都要判断,包含"-"或不包含"-"
  3. 顶级域名很多,直接判断"."之后是否为字母即可
  4. 最后判断端口、路径和哈希,这些参数可有可无

 域名中只能包含以下字符
  1. 26个英文字母
  2. "0,1,2,3,4,5,6,7,8,9"十个数字
  3. "-"(英文中的连词号,但不能是第一个字符)

https://www.bilibili.com/video/BV1F54y1N74E/?spm_id_from=333.337.search-card.all.click&vd_source=6fd32175adc98c97cd87300d3aed81ea
//开始:                     ^
//协议:                     http(s)?:/\/\
//域名:                     [A-z0-9]+-[A-z0-9]+|[A-z0-9]+
//顶级域名 如com cn,2-6位:   [A-z]{2,6}
//端口 数字:                (\d+)?
//路径 任意字符 如 /login:   (\/.+)?
//哈希 ? 和 # ,如?age=1:    (\?.+)?(#.+)?
//结束:                      $
//     https://           www.bilibili                com    /video/BV1F54y1N74E  ?spm..
/^(http(s)?:\/\/)?(([a-zA-Z0-9]+-[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)+([a-zA-Z]{2,6})(:\d+)?(\/.+)?(\?.+)?(#.+)?$/.test(url)

函数

函数的length属性

将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

function fun(a = 1, b, c, d) { }
​
console.log(fun.length) // 0

函数声明与函数表达式的区别

函数声明会将那个函数提升到最前面(即使你写代码的时候在代码块最后才写这个函数),成为全局函数。

函数声明要指定函数名,而函数表达式不用,可以用作匿名函数。

立即执行函数(iife)

( function( ){ })( )

原理:括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(), 然后碰到function关键字

就会自动将()里面的代码识别为函数表达式而不是函数声明

作用:立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量。

常用方法

异或运算^

按位异或,相同为0,不同为1

运算法则:

1.交换律(随便换像乘一样):a ^ b ^ c  === a ^ c ^ b

2.任何数于0异或为任何数 0 ^ n === n

3.相同的数异或为0: n ^ n === 0

Math

//e=2.718281828459045
Math.E;//绝对值
Math.abs()//基数(base)的指数(exponent)次幂,即 base^exponent。
Math.pow(base, exponent)//max,min不支持传递数组
Math.max(value0, value1, /* … ,*/ valueN)
Math.max.apply(null,array)
apply会将一个数组装换为一个参数接一个参数
null是因为没有对象去调用这个方法,只需要用这个方法运算//取整
Math.floor()  向下取一个整数(floor地板)
Math.ceil(x)  向上取一个整数(ceil天花板)Math.round() 返回一个四舍五入的值Math.trunc() 直接去除小数点后面的值

Number

0B,0OES6新增

  • 二进制:有前缀0b(或0B)的数值,出现0,1以外的数字会报错(b:binary)
  • 八进制:有前缀0o(或0O)的数值,或者是以0后面再跟一个数字(0-7)。如果超出了前面所述的数值范围,则会忽略第一个数字0,视为十进制数(o:octonary)
  • 注意:八进制字面量在严格模式下是无效的,会导致支持该模式的JavaScript引擎抛出错误
  • 十六进制:有前缀0x,后跟任何十六进制数字(0~9及A~F),字母大小写都可以,超出范围会报错

特殊值

  • Number.MIN_VALUE:5e-324
  • Number.MAX_VALUE:1.7976931348623157e+308
  • Infinity ,代表无穷大,如果数字超过最大值,js会返回Infinity,这称为正向溢出(overflow);
  • -Infinity ,代表无穷小,小于任何数值,如果等于或超过最小负值-1023(即非常接近0),js会直接把这个数转为0,这称为负向溢出(underflow)
  • NaN ,Not a number,代表一个非数值
  • isNaN():用来判断一个变量是否为非数字的类型,如果是数字返回false;如果不是数字返回true。
  • isFinite():数值是不是有穷的
var result = Number.MAX_VALUE + Number.MAX_VALUE;console.log(isFinite(result)); //false
  • typeof NaN // 'number'  ---NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number
  • NaN === NaN // false   ---NaN不等于任何值,包括它本身
  • (1 / +0) === (1 / -0) // false  ---除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的

科学计数法

对于那些极大极小的数值,可以用e表示法(即科学计数法)表示的浮点数值表示。

等于e前面的数值乘以10的指数次幂

numObj.toFixed(digits)//用定点表示法来格式化一个数值function financial(x) {return Number.parseFloat(x).toFixed(2);
}console.log(financial(123.456));
// Expected output: "123.46"console.log(financial(0.004));
// Expected output: "0.00"console.log(financial('1.23e+5'));
// Expected output: "123000.00"

取余是数学中的概念,

取模是计算机中的概念,

两者都是求两数相除的余数

1.当两数符号相同时,结果相同,比如:7%4 与 7 Mod 4 结果都是3

2.当两数符号不同时,结果不同,比如   (-7)%4=-3和(-7)Mod4=1

取余运算,求商采用fix 函数,向0方向舍入,取 -1。因此 (-7) % 4 商 -1 余数为 -3
取模运算,求商采用 floor 函数,向无穷小方向舍入,取 -2。因此 (-7) Mod 4 商 -2 余数为 1

key:((n % m) + m) % m;

Number.prototype.mod = function(n) {return ((this % n) + n) % n;
}
// 或
function mod(n, m) {return ((n % m) + m) % m;
}

Map

保存键值对,任何值(对象或者基本类型)都可以作为一个键或一个值。

Map的键可以是任意值,包括函数、对象或任意基本类型。
object的键必须是一个String或是Symbol 。

const contacts = new Map()
contacts.set('Jessie', {phone: "213-555-1234", address: "123 N 1st Ave"})
contacts.has('Jessie') // true
contacts.get('Hilary') // undefined
contacts.delete('Jessie') // true
console.log(contacts.size) // 1function logMapElements(value, key, map) {console.log(`m[${key}] = ${value}`);
}new Map([['foo', 3], ['bar', {}], ['baz', undefined]]).forEach(logMapElements);// Expected output: "m[foo] = 3"
// Expected output: "m[bar] = [object Object]"
// Expected output: "m[baz] = undefined"

Set

值的集合,且值唯一

虽然NaN !== NaN,但set中NaN 被认为是相同的

let setPos = new Set();
setPos.add(value);//Boolean
setPos.has(value);
setPos.delete(value);function logSetElements(value1, value2, set) {console.log(`s[${value1}] = ${value2}`);
}new Set(['foo', 'bar', undefined]).forEach(logSetElements);// Expected output: "s[foo] = foo"
// Expected output: "s[bar] = bar"
// Expected output: "s[undefined] = undefined"

set判断值相等的机制

//Set用===判断是否相等
const set= new Set();
const obj1={ x: 10, y: 20 },obj2={ x: 10, y: 20 }
set.add(obj1).add(obj2);console.log(obj1===obj2);//false
console.log(set.size);// 2set.add(obj1);
console.log(obj1===obj1);//true
console.log(set.size);//3

数组去重 (⭐手写)

// Use to remove duplicate elements from the array
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)])
// [2, 3, 4, 5, 6, 7, 32]

Array

//创建字符串
//join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串
//如果数组只有一个元素,那么将返回该元素而不使用分隔符。
Array.join()
Array.join(separator)//################创建数组:
//伪数组转成数组
Array.from(arrayLike, mapFn)
console.log(Array.from('foo'));
// Expected output: Array ["f", "o", "o"]console.log(Array.from([1, 2, 3], x => x + x));
// Expected output: Array [2, 4, 6]console.log( Array.from({length:3},(item, index)=> index) );// 列的位置
// Expected output:Array [0, 1, 2]//################原数组会改变:arr.reverse()//返回翻转后的数组// 无函数
arr.sort()//默认排序顺序是在将元素转换为字符串,然后比较它们的 UTF-16
// 比较函数
arr.sort(compareFn)
function compareFn(a, b) {if (在某些排序规则中,a 小于 b) {return -1;}if (在这一排序规则下,a 大于 b) {return 1;}// a 一定等于 breturn 0;
}
//升序
function compareNumbers(a, b) {return a - b;
}//固定值填充
arr.fill(value)
arr.fill(value, start)
arr.fill(value, start, end)//去除
array.shift() //从数组中删除第一个元素,并返回该元素的值。array.pop() //从数组中删除最后一个元素,并返回该元素的值。此方法会更改数组的长度。
array.push() //将一个或多个元素添加到数组的末尾,并返回该数组的新长度//unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度
array.unshift(element0, element1, /* … ,*/ elementN)//粘接,通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1)
array.splice(start, deleteCount, item1, item2...itemN)//################原数组不会改变://切片,浅拷贝(包括 begin,不包括end)。
array.slice()
array.slice(start)
array.slice(start, end)//展平,按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
array.flat()//不写参数默认一维
array.flat(depth)//过滤器,函数体 为 条件语句
// 箭头函数
filter((element) => { /* … */ } )
filter((element, index) => { /* … */ } )
filter((element, index, array) => { /* … */ } )
array.filter(str => str .length > 6) //遍历数组处理
// 箭头函数
map((element) => { /* … */ })
map((element, index) => { /* … */ })
map((element, index, array) => { /* … */ })
array.map(el => Math.pow(el,2))
//map和filter同参//接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
// 箭头函数
reduce((previousValue, currentValue) => { /* … */ } )
reduce((previousValue, currentValue, currentIndex) => { /* … */ } )
reduce((previousValue, currentValue, currentIndex, array) => { /* … */ } )
reduce((previousValue, currentValue) => { /* … */ } , initialValue)
reduce((previousValue, currentValue, currentIndex) => { /* … */ } , initialValue)
array.reduce((previousValue, currentValue, currentIndex, array) => { /* … */ }, initialValue)//一个“reducer”函数,包含四个参数:
//previousValue:上一次调用 callbackFn 时的返回值。
//在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,
//否则为数组索引为 0 的元素 array[0]。//currentValue:数组中正在处理的元素。
//在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],
//否则为 array[1]。//currentIndex:数组中正在处理的元素的索引。
//若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。//array:用于遍历的数组。//initialValue 可选
//作为第一次调用 callback 函数时参数 previousValue 的值。
//若指定了初始值 initialValue,则 currentValue 则将使用数组第一个元素;
//否则 previousValue 将使用数组第一个元素,而 currentValue 将使用数组第二个元素。
const array1 = [1, 2, 3, 4];// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce((accumulator, currentValue) => accumulator + currentValue,initialValue
);console.log(sumWithInitial);
// Expected output: 10

Array.filter(⭐手写)

Array.prototype._filter = function(Fn) {if (typeof Fn !== 'function') returnconst array = thisconst newArray = []for (let i=0; i<array.length; i++) {const result = Fn.call(null, array[i], i, array)result && newArray.push(array[i])}
return newArray}

Array.map(⭐手写)

Array.prototype._map = function(Fn) {if (typeof Fn !== 'function') returnconst array = thisconst newArray = []for (let i=0; i<array.length; i++) {const result = Fn.call(null, array[i], i, array)//##########与filter的唯一不同newArray.push(result)}
return newArray}

Array.reduce(⭐手写)


Array.prototype._reduce = function(fn,initialValue = 0){if(typeof fn !== 'function') return;let res = initialValuethis.forEach((value,index,arr)=>{res = fn(res,value,index,arr)})return res
}

String

str.charAt(index)//获取第n位字符
str.charCodeAt(n)//获取第n位UTF-16字符编码 (Unicode)A是65,a是97
String.fromCharCode(num1[, ...[, numN]])//根据UTF编码创建字符串String.fromCharCode('a'.charCodeAt(0))='a'str.trim()//返回去掉首尾的空白字符后的新字符串str.split(separator)//返回一个以指定分隔符出现位置分隔而成的一个数组,数组元素不包含分隔符const str = 'The quick brown fox jumps over the lazy dog.';const words = str.split(' ');
console.log(words[3]);
// Expected output: "fox"str.toLowerCase( )//字符串转小写;
str.toUpperCase( )//字符串转大写;str.concat(str2, [, ...strN])str.substring(indexStart[, indexEnd])  //提取从 indexStart 到 indexEnd(不包括)之间的字符。
str.substr(start[, length]) //没有严格被废弃 (as in "removed from the Web standards"), 但它被认作是遗留的函数并且可以的话应该避免使用。它并非 JavaScript 核心语言的一部分,未来将可能会被移除掉。str.indexOf(searchString[, position]) //在大于或等于position索引处的第一次出现。
str.match(regexp)//找到一个或多个正则表达式的匹配。
const paragraph = 'The quick brown fox jumps over the lazy dog. It barked.';
let regex = /[A-Z]/g;
let found = paragraph.match(regex);
console.log(found);
// Expected output: Array ["T", "I"]
regex = /[A-Z]/;
found = paragraph.match(regex);
console.log(found);
// Expected output: Array ["T"]//match类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
var str = '123123000'
str.match(/\w{3}/g).join(',') // 123,123,000str.search(regexp)//如果匹配成功,则 search() 返回正则表达式在字符串中首次匹配项的索引;否则,返回 -1
const paragraph = '? The quick';// Any character that is not a word character or whitespace
const regex = /[^\w\s]/g;console.log(paragraph.search(regex));
// Expected output: 0str.repeat(count)//返回副本
str.replace(regexp|substr, newSubStr|function)//返回一个由替换值(replacement)替换部分或所有的模式(pattern)匹配项后的新字符串。
const p = 'lazy dog.Dog lazy';//如果pattern是字符串,则仅替换第一个匹配项。
console.log(p.replace('dog', 'monkey'));
// "lazy monkey.Dog lazy"let regex = /dog/i;//如果非全局匹配,则仅替换第一个匹配项
console.log(p.replace(regex, 'ferret'));
//"lazy ferret.Dog lazy"regex = /d|Dog/g;
console.log(p.replace(regex, 'ferret'));
//"lazy ferretog.ferret lazy"//当使用一个 regex 时,您必须设置全局(“g”)标志, 否则,它将引发 TypeError:“必须使用全局 RegExp 调用 replaceAll”。
const p = 'lazy dog.dog lazy';//如果pattern是字符串,则仅替换第一个匹配项。
console.log(p.replaceAll('dog', 'monkey'));
// "lazy monkey.monkey lazy"let regex = /dog/g;//如果非全局匹配,则仅替换第一个匹配项
console.log(p.replaceAll(regex, 'ferret'));
//"lazy ferret.ferret lazy"

Class

类声明

class Rectangle {constructor(height, width) {this.height = height;this.width = width;}
}

类表达式

// 未命名/匿名类
let Rectangle = class {constructor(height, width) {this.height = height;this.width = width;}
};
console.log(Rectangle.name);
// output: "Rectangle"// 命名类
let Rectangle = class Rectangle2 {constructor(height, width) {this.height = height;this.width = width;}
};
console.log(Rectangle.name);
// 输出:"Rectangle2"

使用 super 调用超类

super 关键字用于调用对象的父对象上的函数。

class Cat {constructor(name) {this.name = name;}speak() {console.log(this.name + ' makes a noise.');}
}class Lion extends Cat {constructor(name,id) {super(name);this.id = id;}speak() {super.speak();console.log(this.name + ' roars.');}
}

private

类属性在默认情况下是公有的,但可以使用增加哈希前缀 # 的方法来定义私有类字段

从类外部引用私有字段是错误的。它们只能在类里面中读取或写入。

class ClassWithPrivateField {#privateField;
}class ClassWithPrivateMethod {#privateMethod() {return 'hello world';}
}class ClassWithPrivateStaticField {static #PRIVATE_STATIC_FIELD;
}class ClassWithPrivateStaticMethod {static #privateStaticMethod() {return 'hello world';}
}

static 关键字

定义静态方法和值。不能在类的实例上调用静态方法,而应该通过类本身调用

静态方法调用同一个类中的其他静态方法,可使用 this 关键字

class StaticMethodCall {static staticMethod() {return 'Static method has been called';}static anotherStaticMethod() {return this.staticMethod() + ' from another static method';}
}
StaticMethodCall.staticMethod();
// 'Static method has been called'StaticMethodCall.anotherStaticMethod();
// 'Static method has been called from another static method'

非静态方法中,不能直接使用 this 关键字来访问静态方法。

而是要用类名来调用:CLASSNAME.STATIC_METHOD_NAME() ,

或者用构造函数的属性来调用该方法: this.constructor.STATIC_METHOD_NAME().

class StaticMethodCall {constructor() {console.log(StaticMethodCall.staticMethod());// 'static method has been called.'console.log(this.constructor.staticMethod());// 'static method has been called.'}static staticMethod() {return 'static method has been called.';}
}

创建对象的方式

1、{}
2、new Object()

    /**使用{}创建对象,等同于 new Object();**/var o = {};

3、使用字面量

var person = {name: 'zhang', age:20}

4、工厂模式

        'use strict';// 使用工厂模式创建对象// 定义一个工厂方法function createObject(name){var o = new Object();o.name = name;o.sayName = function(){alert(this.name);};return o;}var o1 = createObject('zhang');var o2 = createObject('li');//缺点:调用的还是不同的方法//优点:解决了前面的代码重复的问题alert(o1.sayName===o2.sayName);//false

5、构造函数模式(constructor)

 <script>'use strict';/***  构造函数模式创建对象**/function Person(name){this.name = name;this.sayName = function(){alert(this.name);};}var p1 = new Person('zhang');var p2 = new Person('li');p1.sayName();p2.sayName();alert(p1.constructor === p2.constructor);//truealert(p1.constructor === Person);//truealert(typeof(p1));//objectalert(p1 instanceof Object); //truealert(p2 instanceof Object); //truebalert(p1.sayName===p2.sayName);//false</script>


6、原型模式(prototype)

  <script>'use strict';/**  原型模式创建对象*/function Animal() { }Animal.prototype.name = 'animal';Animal.prototype.sayName = function () { alert(this.name); };var a1 = new Animal();var a2 = new Animal();a1.sayName();alert(a1.sayName === a2.sayName);//truealert(Animal.prototype.constructor);//function Animal(){}alert(Animal.prototype.constructor==Animal);//true</script>

如果往新建的对象中加入属性,那么这个属性是放在对象中,如果存在与原型同名的属性,也不会改变原型的值。但是访问这个属性,拿到的是对象的值。

访问的顺序:对象本身>构造函数的prototype

如果对象中没有该属性,则去访问prototype,如果prototype中没有,继续访问父类,直到Object,如果都没有找到,返回undefined

 <script>'use strict';/**  原型模式创建对象*/function Animal() { }Animal.prototype.name = 'animal';Animal.prototype.sayName = function () { alert(this.name); };var a1 = new Animal();var a2 = new Animal();a1.sayName();alert(a1.sayName === a2.sayName);//truealert(Animal.prototype.constructor);//function Animal(){}//修改a2.name,a1的name不会变a2.name = 'dog';a2.sayName();//doga1.sayName();//animal</script>

假如原型中包含有引用类型的属性,那么如果某个对象修改了该属性的值,所有的该原型创建的对象访问的值都会改变。

 <script>'use strict';//原型模式2//存在的问题:如果原型中含有引用类型function Animal (){}Animal.prototype = {name: 'animal',friends: ['dog','cat'],sayName: function(){alert(this.name);}};var a1 = new Animal();var a2 = new Animal();a2.friends.push('snake');alert(a2.friends);//[dog,cat,snake]alert(a1.friends);//[dog,cat,snake]</script>


7、构造函数+原型模式

 <script>'use strict';function Animal(name){this.name = name;this.friends = ['dog','cat'];}Animal.prototype.sayName = function(){alert(this.name);};var a1 = new Animal('d');var a2 = new Animal('c');a1.friends.push('snake');alert(a1.friends);//[dog,cat,snake]alert(a2.friends);//[dog,cat]</script>

Object

//创建的新对象.prototype=proto(参数对象)
Object.create(proto[, propertiesObject])

propertiesObject 可选
如果该参数被指定且不为 undefined,则该传入对象的自有 可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。这些属性对应于 Object.defineProperties() 的第二个参数。

描述符

  • 拥有布尔值的键 configurableenumerable 和 writable 的默认值都是 false
  • 属性值和函数的键 valueget 和 set 字段的默认值为 undefined

数据描述符

configurable

true 时,描述符才能够被改变,同时该属性也能从对应的对象上被删除

enumerable 属性

定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

value

该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。

writable

当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。

存取描述符

get

属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。

set

属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。

描述符可拥有的键值

configurable enumerable value writable get set
数据描述符 可以 可以 可以 可以 不可以 不可以
存取描述符 可以 可以 不可以 不可以 可以 可以

如果一个描述符不具有 valuewritableget 和 set 中的任意一个键,那么它将被认为是一个数据描述符。

如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常

function Archiver() {var temperature = null;var archive = [];Object.defineProperty(this, 'temperature', {get: function() {console.log('get!');return temperature;},set: function(value) {temperature = value;archive.push({ val: temperature });}});this.getArchive = function() { return archive; };
}var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]//在一个对象上定义一个新的属性或修改现有属性,并返回该对象
Object.defineProperty(obj, prop, descriptor)const object1 = {};Object.defineProperty(object1, 'property1', {value: 42,writable: false
});
//用 Symbol 类型的值来做对象的 key 与常规的定义或修改不同//Object.defineProperty 是定义 key 为 Symbol 的属性的方法之一。
Object.defineProperty(o, Symbol.for('e'), {value: 5,enumerable: true
});//在一个对象上定义新的属性或修改现有属性,并返回该对象
Object.defineProperties(obj, props) var obj = {};
Object.defineProperties(obj, {'property1': {value: true,writable: true},'property2': {value: 'Hello',writable: false}// etc. etc.
});//Object.prototype.hasOwnProperty()指示对象自身属性中是否具有指定的属性
const object1 = {};
object1.property1 = 42;console.log(object1.hasOwnProperty('property1'));
// Expected output: trueconsole.log(object1.hasOwnProperty('hasOwnProperty'));
// Expected output: false//Object.getPrototypeOf(object)返回对象原型const prototype1 = {};
const object1 = Object.create(prototype1);console.log(Object.getPrototypeOf(object1) === prototype1);
// Expected output: true//Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。const object1 = {a: 'somestring',b: 42,c: false
};console.log(Object.keys(object1));
// Expected output: Array ["a", "b", "c"]//Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for...in 循环的顺序相同(区别在于 for-in 循环枚举原型链中的属性)。
var obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]// non-object argument will be coerced to an object
console.log(Object.values('foo')); // ['f', 'o', 'o']

Object.create (⭐手写)

该函数创建一个新对象,使用现有的对象来提供新创建的对象的proto,核心步骤有:

  1. 创建一个临时函数
  2. 将该临时函数的原型指向对象参数
  3. 返回该临时对象的实例

Object.create法创建一个新对象,使用现有的对象来提供新创建的对象的proto。

const _objectCreate = proto => {if(typeof proto !== 'object' || proto === null) returnconst fn = function() {}fn.prototype = protoreturn new fn()
}

Object.freeze (⭐手写)

Object.freeze = writable: false + Object.seal = writable: false + Object.preventExtensions + configable: false

  • Symbol 类型作为 key 值的情况,也要冻结
  • 只冻结对象自有的属性(使用 for ... in 会把原型链上的可枚举属性遍历出来)。
  • 注意不可扩展性(不能添加新属性,使用 Object.preventExtensions() 或 Object.seal() 实现,同时也相当于把原型链冻结)。

key:

  1. Object.getOwnPropertyNames/Symbol
  2. forEach
  3. Object.defineProperty:configurable,writable
  4. Object.preventExtensions(object)
const _objectFreeze = object => {if(typeof object !== 'object' || object === null) {throw new TypeError(`the ${object} is not a object`)}const keys = Object.getOwnPropertyNames(object);const symbols = Object.getOwnPropertySymbols(object);[...keys, ...symbols].forEach(key => {Object.defineProperty(object, key, {configurable: false,writable: false,})})Object.preventExtensions(object)
}

indexOf (⭐手写)

在函数前加上波浪号,其作用是把函数声明转换为表达式,这样就可以直接运行

~function sayHello(){console.log('hello');
}()//Expected output: hello
    ~ function () {function myIndexOf(searchStr) {// 这个也可以正则实现 下面代码// let reg = new RegExp(searchStr)// res = reg.exec(this)// return res === null ? -1 : res.indexlet len = this.lengthlet searchLen=searchStr.lengthif (searchLen > len) return -1// 如果输入的字符串大于要检测的字符串直接 -1for (var i = 0; i <= len-searchLen; i++) {if (this.substring(i,searchLen+i) === searchStr) {return i}}return -1}String.prototype.myIndexOf = myIndexOf}()let str = 'dwanlghMappaw'let searchStr= 'hM'console.log(str.myIndexOf(searchStr));

高阶函数和函数的珂里化Currying

高阶函数参数 或者 返回值为函数

函数柯里化返回值为函数,实现多次接收参数最后统一处理的函数编码

作用:能进行部分传值,而传统函数调用则需要预先确定所有实参。如果你在代码某一处只获取了部分实参,然后在另一处确定另一部分实参

用途:延迟计算、参数复用、动态生成函数(都是闭包的用途)。

function sum(a){return(b)=>{return (c)=>{return a+b+c}}
}

Arguments对象

是所有(非箭头)函数中都可用的局部变量。类似于Array,但除了 length 属性和索引元素之外没有任何Array属性。

function add() {var sum =0,len = arguments.length;for(var i=0; i<len; i++){sum += arguments[i];}return sum;
}
add()                           // 0
add(1)                          // 1
add(1,2,3,4);                   // 10

深浅拷贝

基本类型:内存区域存储的是值,不存在深拷贝和浅拷贝

引用类型:内存区域存储的是地址,浅拷贝只拷贝一层(内存地址),而深拷贝是层层拷贝(拷贝内容,新开辟内存)。

深拷贝(⭐手写)

 function cloneDeep(arr = {}) {// 终止递归 判断如果传进来的数据不是 object 或者 传进来的是一个 null 直接返回if (!arr || typeof arr != 'object' || arr == null) return arr// 用 instanceof 判断原型链上是否有该类型的原型 是 Array => [] ! Arrays =>{}let result=arr instanceof Array ?  [] :  {}// forin 循环对象的key值for (const key in arr) {//  对象 key 赋值 resultresult[key] = cloneDeep(arr[key])}return result}

严格模式

严格模式通过抛出错误来消除了一些原有静默错误

  • 严格模式下,不允许给未声明的变量赋值

严格模式修复了一些导致 JavaScript 引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快

严格模式禁用了在 ECMAScript 的未来版本中可能会定义的一些语法。

防抖 (⭐手写)

触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,会重计算函数执行时间。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
</head>
<body>防抖: <input id="input" type="text">
</body>
<script>// 防抖的核心代码function debounce(fun,time) {let flag // 定义状态return function () {clearTimeout(flag)// 在执行之前 清除 定时器的 flag 不让他执行flag = setTimeout(() => {fun.call(this,arguments)//拿到正确的this对象,即事件发生的dom}, time)}}let val = debounce(function (val) {console.log(val)},1000)// 监听拿到input输入的值input.addEventListener('input', function (e) {val(e.target.value)})</script>
</html>

节流(⭐手写)

连续触发事件但是在 n 秒中只执行一次函数。两种方式可以实现,分别是时间戳版和定时器版。

<body><button id="button">1秒执行一次</button>
</body>
<script>/*定时器版本的fns 回调函数time 间隔时间function throttle(fun, time) {let flag // 定义一个空状态return function () { // 内部函数访问外部函数形成闭包if (!flag) { // 状态为空执行flag = setTimeout(() => {fns.apply(this, arguments) // 改变this指向 把 event 事件对象传出去flag = null}, time)}}}*/function throttle(fun, time) {let last = 0return function () {let now = Date.now()// 当前的值 减去上一次的值 >= 传过来的事件 执行if (now - last >= time) {fun.apply(this, arguments)last = now}}}button.onclick = throttle((e) => {console.log(e)}, 1000)
</script>

防抖、节流应用

防止某一时间频繁触发

  • 防抖debounce:time内只执行一次

    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
  • 节流throttle: 间隔time执行
    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

垃圾回收(GC)

GC 即 Garbage Collection

浏览器的js具有自动垃圾回收机制,垃圾回收机制也就是自动内存管理机制,垃圾收集器会定期的找出不可访问的值,然后释放内存,所以将不需要的对象设为null即可。

内存分配

  • First-fit,找到第一个的大于等于 size 的块立即返回

  • Best-fit,遍历整个空闲列表,返回大于等于 size 的最小分块

  • Worst-fit,遍历整个空闲列表,找到最大的分块,然后切成两部分,一部分 size 大小,并将该部分返回

Worst-fit空间利用率看起来是最合理,但实际上切分之后会造成更多的小块,形成内存碎片,所以不推荐使用,

First-fitBest-fit 来说,考虑到分配的速度和效率 First-fit 是更为明智的选择

回收策略

标记清除(Mark-Sweep):最常用

(根对象,在浏览器环境中包括 全局Window对象文档DOM树 等)

  • 垃圾收集器在运行时会给内存中的所有变量都加上一个标记,假设内存中所有对象都是垃圾,全标记为0
  • 然后从各个根对象开始遍历,把不是垃圾的节点改成1
  • 清理所有标记为0的垃圾,销毁并回收它们所占用的内存空间
  • 最后,把所有内存中对象标记修改为0,等待下一轮垃圾回收

优点

简单

缺点

  • 内存碎片化,清除之后,剩余的对象内存位置不变的,也会导致空闲内存空间是不连续的,出现了 内存碎片,存在内存分配的问题
  • 分配速度慢,因为即便是使用 First-fit 策略,其操作仍是一个 O(n) 的操作,最坏情况是每次都要遍历到最后,同时因为碎片化,大对象的分配效率会更慢

标记整理(Mark-Compact)

改善标记清除清除之后剩余的对象位置不变而导致的空闲内存不连续

标记结束后,标记整理算法会将活着的对象(即不需要清理的对象)向内存的一端移动,最后清理掉边界的内存

引用计数(Reference Counting),的一种垃圾回收算法

它把 对象是否不再需要 简化定义为 没有引用指向该对象(零引用),对象将被垃圾回收机制回收,目前很少使用这种算法了,因为它的问题很多

跟踪记录每个变量值被使用的次数

  • 当声明了一个变量并且将一个引用类型赋值给该变量的时候这个值的引用次数就为 1

  • 如果同一个值又被赋给另一个变量,那么引用数加 1

  • 如果该变量的值被其他的值覆盖了,则引用次数减 1

  • 当这个值的引用次数变为 0 的时候,说明没有变量在使用,这个值没法被访问了,回收空间,垃圾回收器会在运行的时候清理掉引用次数为 0 的值占用的内存

优点

引用值为 0 时,可以立即回收垃圾

缺点

计数器需要占内存

不知道被引用数量的上限

无法解决循环引用无法回收的问题,这也是最严重的

内存泄漏

如果 那些不再使用的变量,它们所占用的内存 不去清除的话就会造成内存泄漏

造成系统内存的浪费导致程序运行速度减慢甚至系统崩溃等严重后果

比如说:

1、闭包:在闭包中引入闭包外部的变量时,当闭包结束时此对象无法被垃圾回收(GC)。

2、DOM:当原有的DOM被移除时,子结点引用没有被移除则无法回收

JS中拥有自动的垃圾回收机制,

宏任务、微任务、Event-Loop

js引擎会优先执行微任务,例如:网页加载完毕,但是图片没加载出来

  • 微任务microtask(异步):可以理解为task执行完后立刻执行,Promise async/await。
  • 宏任务macrotask: setTimeout,setInterval一类的定时事件,Ajax,DOM事件,script 脚本的执行、 I/O 操作、UI 渲等。

例如:new Promise实例化是同步,而then注册的回调才是异步执行的。

例如:等待的客户为宏任务,他的每个业务为微任务

每办理完一个业务,柜员就会问当前的客户,是否还有其他需要办理的业务。(检查还有没有微任务需要处理)
而客户明确告知说没有事情以后,柜员就去查看后边还有没有等着办理业务的人。(结束本次宏任务、检查还有没有宏任务需要处理)
这个检查的过程是持续进行的,每完成一个任务都会进行一次,而这样的操作就被称为Event Loop

setImmediate与setTimeout的区别

setImmediate为一次Event Loop执行完毕后调用。
setTimeout则是通过计算一个延迟时间后进行执行。

如果在主进程中直接执行这两个操作,很难保证哪个会先触发。
当注册这两个任务耗时超过delay(s),定时器处于可执行回调的状态,会先执行定时器,

执行完定时器以后才是结束了一次Event Loop,这时才会执行setImmediate

JS延迟加载的方式

JavaScript 是单线程(js不走完下面不会走是因为同步)会阻塞DOM的解析,因此也就会阻塞DOM的加载。所以有时候我们希望延迟JS的加载来提高页面的加载速度。

1.把JS放在页面的最底部(css放顶部,js放底部是框架常见优化

2.script标签的defer属性:脚本会立即下载但延迟到整个页面加载完毕再执行。该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。

3.是在外部JS加载完成后,浏览器空闲时,Load事件触发前执行,标记为async的脚本并不保证按照指定他们的先后顺序执行, 该属性对于内联脚本无作用 (即没有 「src」 属性的脚本)。

4.动态创建script标签,监听dom加载完毕再引入js文件

2023年最全前端面试题考点HTML5+CSS3+JS相关推荐

  1. 2023最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)

    近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k-15k的常见面试题 个人录制的最新Vue项目学习视频:B站 小胖梅-的个人空间_哔哩哔哩_Bilibili 红色为常见面试题 ====== ...

  2. 2018最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)--转载

    版权声明:本文为转载文章,感谢博主小胖梅的博客,如有侵权,请联系我删除,谢谢 转载链接: https://blog.csdn.net/xm1037782843/article/details/8070 ...

  3. 2021最新最全前端面试题(包含HTML、CSS、JavaScript、Vue、React、浏览器、算法与数据结构等)

    整理了一些前端面试题,希望对正在找前端工作的伙伴有用.本篇文章内容篇幅较大,主要针对初中级前端开发工程师. 篇幅过长,大家可以先点赞收藏以后慢慢看. 关于HTML 的title和alt属性有什么区别 ...

  4. 超全前端面试题及答案

    HTML+CSS 1.对WEB标准以及W3C的理解与认识 标签闭合.标签小写.不乱嵌套.提高搜索机器人搜索几率.使用外 链css和js脚本.结构行为表现的分离.文件下载与页面速度更快.内容能被更多的用 ...

  5. 前端面试题(HTML、JS、Vue、React、小程序)

    前端面试题 HTML && CSS HTML 1.Div 里面有个一个div ***** Q:有几种方法可以水平,垂直居中 2.doctype的作用 * 3.link标签和import ...

  6. 2021-最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)---Vue篇

    ★★★ 如何使用原生 Node.js 操做 cookie? ★★ 什么是 Node.js?我们在哪里使用它? ★★ 为什么要使用 Node.js? ★★★ Node.js 有哪些特点? ★★★ set ...

  7. 史上最全前端面试题(含答案)-B篇

    面试有几点需要注意 面试题目: 根据你的等级和职位变化,入门级到专家级:范围↑.深度↑.方向↑. 题目类型: 技术视野.项目细节.理论知识型题,算法题,开放性题,案例题. 进行追问: 可以确保问到你开 ...

  8. 【前端面试题】关于一些js的一些面试题(金融行业),我和面试官扯了三个小时

    今天去面试了一家金融公司,招聘比较着急,一面后直接二面等结果,这种公司一般对js要求比较高,笔试题基本都是js相关的题,针对公司的客户要求也会做一些jquery,vue.react相关的插件,H5及w ...

  9. 2022最全前端面试题(持续更新)

    css部分 如何水平垂直居中一个盒子? 已知高度可以使用 line-height 等于 高度实现垂直居中:使用 text-align:center实现水平居中 display:flex; align- ...

最新文章

  1. Reat学习01——初步接触与安装
  2. [TJOI2017]城市(未解决)
  3. 指标实现层级_企业如何构建核心指标系统,实现业务运营效率提升90%?
  4. 3. 什么是icmp?icmp与ip的关系_公共关系与人际交往能力自主模式课程相关
  5. Linux 常用的命令
  6. PyQT多线程串口 QtDesigner
  7. 怎么样利用栅格数据分类后的结果以行政区域统计各个地类的面积
  8. csv to dbf java_将csv文件转换为dbf
  9. 论文caj转换为word
  10. Evision显示器无法设置1440*900分辨率的问题解决
  11. Go 切片(slice)使用
  12. Linux RHEL/Ubuntu安装教程
  13. zerotier异地搭建组网
  14. Milk Measurement
  15. The 4th SMUCTF Office WriteUp
  16. Oracle、Mysql数据库编程开发基本操作命令语法脚本_基础篇(入门级)
  17. c++11 tupe
  18. M3DGIS全息裸眼三维电子沙盘数字沙盘大数据系统开发教程视频第6课
  19. Ant design系列认知
  20. 阿波罗 | 障碍物预测轨迹参考线交通规则融合

热门文章

  1. 盛迈坤电子商务:店铺内容营销的优势
  2. python GUI 绑定事件
  3. 网站的护眼模式和夜间模式
  4. 树莓派53/100 - Pico小车v4版本,蓝牙、陀螺仪之后,再加上OLED显示屏
  5. qdialog 圆角_重载QDialog开发自定义样式圆角边框和按钮的提示框
  6. python做的如何给别人用流量_流量怎么共享给别人用
  7. HELLDIVERS 游戏手柄冲刺方法 绝地潜兵
  8. hbase 二进制数据写入_分布式数据库HBase的架构设计详解(有彩蛋)
  9. 微服务框架springcloud
  10. md5加密及防止篡改