前端基础知识点收集

一、HTML和CSS相关知识

1.1、浏览器内核

IE浏览器:trident内核

Firefox:gecko内核

Safari:webkit内核

Opera:旧:presto内核,新:Blink

Chrome:Blink(基于webkit,Google和Opera共同开发)

1.2、HTML语义化

html语义化就是用正确标签干正确的事。例如:p标签(段落使用)、h1-h6(标题)、文章(article)、ul(无序列表)、li(有序列表)、header(页面头部)、footer(页面底部)、aside(页面侧边栏)、section(区段)、nav(导航区)等

html语义化好处:

1、增强代码可读性,便于维护。

2、SEO优化

3、用于智能分析

4、CSS缺失时,依然可以展示页面结构。

SEO:利用搜索引擎的搜索规则来提高目前网站在有关搜索引擎内的自然排名的方式。

1.3、Doctype作用、严格模式、混合模式

1、<!DOCTYPE> 声明位于文档最开始,处于<html>标签前面,告诉浏览器使用什么模式渲染。

2、严格模式的排版和JS运作模式,以浏览器支持最高模式运行。

3、混合模式中,页面宽松向后兼容方式展示。模拟旧浏览器行为,以防站点不能展示。

4、如果DOCTYPE不存在或格式不正确,则会以混合模式展示页面。

1.4、Doctype定义多少种文档类型?

标签可以声明三种DTD,分别严格版本、过度版本和基于框架HTML文档。

HTML4.0.1规定三种文档类型:Strict、Transitional以及Frameset。

HTML1.0规定三种XML文档类型:Strict、Transitional和Frameset。Standards标准模式(严格模式)用于呈现遵循最新标准网页,然而Quirks包容模式(兼容模式)主要用来展示为旧浏览器设计的网页。

1.5、行内元素、块级元素、空元素举例,如何转化的

行内元素(不能设置宽度和高度,设置则无效):a、span,i,em,strong、label

行内块元素:img、input

块元素:div、p、h1-h6、ul、li、ol、dl、table...

空元素:img、input、br、hr、link、mate

通过display属性设置可以实现转化,inline-block(行内块元素)、block(块状元素)、inline(行内元素)

1.6、mate viewport作用及写法

viewport目的:告诉浏览器移动端怎么进行页面缩放。

代码格式如下:

<meta
  name="viewport"
  content="width=device-width, 
               initial-scale=1, 
               maximum-scale-1, minimum-scale=1"
/>

width=device-width:将布局视窗宽度设置为设备分辨率的宽高, 

 initial-scale=1:页面初始缩放比例为设备分辨率宽高, 

 maximum-scale=1: 指定用户放大的最大比例,

minimum-scale=1: 指定用户缩小的最大比例

1.7label标签作用

label主要用来定义表单控制关系,点击label,会自动聚焦到对应的绑定表单控件上。

<label for="Name">张三:</label>
<input type="text" name="Name" id="Name" />

<label
  >日期:
  <input type="text" name="date" />
</label>

1.8、canvas标签设置宽高和style设置宽高区别

canvas标签的width和height是画布的宽和高,画图都在这个上面。而style的width和height是canvas在浏览器中渲染的宽度和高度。若canvas没有设置宽高或设置不正确,则会设置为默认宽高。

1.9、html5新特性

1、标签语义化:header、footer、nav、aside、article、section

2、增强型表单(增加:文本框提示信息、表单校验、日期选择控件、颜色选择控件、范围控件、进度条、标签跨表单等功能)

3、视频video和音频audio

4、Canvas绘图

5、SVG绘图

6、地理定位

7、拖放API

8、WebWorker

9、WebStorage(离线存储localStorage和sessionStorage)

10、WebSocket

详细参考:HTML5新特性 - 知乎 HTML5 新特性 - 筱qian - 博客园HTML5新特性 - 知乎 

2.0、CSS3新特性

1、圆角效果;2、图形化边界;3、块阴影与文字阴影;4、使用RGBA实现透明效果;5、渐变效果;6、使用“@Font-face” 实现定制字体;7、多背景图;8、文字或图像变形处理;9、多栏布局;10、媒体查询

示例:

1、颜色:新增RGBA、HSLA模式
2、文字阴影:(text-shadow)
3、边框:圆角(border-radius)边框阴影:box-shadow
4、盒子模型:box-sizing
5、背景:background-size,background-origin background-clip(削弱)
6、渐变:linear-gradient(线性渐变):
eg: background-image: linear-gradient(100deg, #237b9f, #f2febd);
radial-gradient (径向渐变)
7、过渡:transition可实现动画
8、自定义动画: animate@keyframes
9、媒体查询:多栏布局@media screen and (width:800px)
10、border-image
11、2D转换:transform:translate(x,y) rotate(x,y)旋转 skew(x,y)倾斜 scale(x,y)缩放
12、3D转换
13、字体图标:Font-Face
14、弹性布局:flex
设为Flex布局以后,子元素的float、clear和vertical-align属性将失效

参考链接:CSS3有哪些新特性?CSS3新特性详解 - 知乎   Flex 布局语法教程 | 菜鸟教程

2.1、选择器种类

1、id选择器(#myId)

2、类选择器(.myclass)

3、标签选择器(p,h1-h6,div)

4、相邻选择器(h1+p)

5、子选择器(ul>li)

6、后代选择器(li a)

7、属性选择器(a[m]="exe")

8、伪类选择器(a:hover,li:nth-child)

9、通配符(*)

权重分布:

        !Important >行样式>id选择器>类、伪类、属性>标签选择器>全局

(权重: 最高         》1000》100       》10                   》1                》0)

2.2、盒子模型

盒子模型:单个盒子包含:content、padding、border、margin四个部分。标准盒子模型宽高指是content部分。

ie的盒模型宽高包括content+padding+border;可以通过box-sizing 修改盒子模型,box-sizing:border-box  content-box

2.3、margin合并问题

在垂直方向上,两个盒子同时设置margin时,会取其中最大值作为最终margin,例:第一个盒子设置margin-bottom: 20px; 第二个盒子设置为margin-top: 30px;  最终会取下面盒子作为margin,而不是两个相加即50px;

解决可以修改:给其中一个盒子添加父盒子,并且设置BFC。

开启BFC :

1、浮动元素(元素的float不是 none,指定float为left或者right就可以创建BFC)

2、绝对定位元素(元素的 position 为 absolute 或 fixed)

3、display:inline-block,display:table-cell,display:flex,display:inline-flex

4、overflow指定除了visible的值,如:overflow: hidden

5、根元素html

2.4、margin塌陷

margin塌陷:在父子盒子模型中,给子盒子设置margin-top:20px,结果和父盒子设置margin-top:20px效果一样。

解决方法:1、给父盒子设置border: 1px solid blue;2、父盒子设置BFC


2.5、BFC介绍

BFC(Block Formatting Context)块格式化上下文,    就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。            

BFC布局特点:

1、BFC中,块级元素从顶端开始垂直一个接着一个排列(不再BFC里块级元素也会垂直排列)

2、在同一个BFC中会出现margin的重叠或者折叠,会取最大值为准,如果两个块级元素不再同一个BFC中,上下margin则不会重叠,就是两个margin之和。

3、在BFC的区域中不会和浮动(float)元素区域重叠,而是紧贴边缘

4、BFC计算高度时,包含浮动元素高度。(作用:清除浮动)

5、在BFC内部的子元素,不会影响到外部元素。

解决的问题:

1、两栏布局:BFC区域不和float元素重叠

例:

.left{
	float: left;
}
.right{
	overflow: hidden;
}

2、解决margin合并和塌陷问题。

3、解决浮动元素无法计算高度问题。

2.6、计算单位rem、px、em区别

rem:相对单位,rem是相对于html元素的字体大小,没有继承性。

em:相对单位,相对于父元素字体大小有继承性。

px:绝对单位,就是css中的像素,利用px设置字体大小,较为准确和稳定。

2.7、响应式布局

什么是响应式设计?

答:响应式设计就是一个网站同时兼容多个终端(pc、手机),智能根据设备环境调整页面对应布局。

响应式布局原理?

答:头部设置mate声明,通过媒体查询检测不同设备屏幕尺寸设置不同的css样式实现。

实现方式种类

答:1、使用百分比布局,缺点:无法对字体和边框等比例缩放

2、弹性盒子布局 display:flex

3、rem布局,1rem=html的font-size值大小。

4、css3的媒体查询@media  screen  and (max-width:750px){}

5、vw+vh 方式

6、使用框架(bootstrap、vant)

2.8、布局种类

两栏布局:左侧固定宽度,右侧自适应。

三栏布局、圣杯布局、双飞翼布局。

2.9、水平垂直居中的实现

1、给父元素设置为弹性盒子(flex),子元素横向居中,纵向居中。

2、父元素相对定位,子元素绝对定位后,子元素向上移动自身宽度和高度一半,也可以transfrom:translate(-50%,-50%)(常用)

3、父元素相对定位,子元素绝对定位后,子元素所有定位为0,margin设置为auto自适应。

2.10、iframe有哪些特点?

iframe是一种框架,是常见的网页嵌入方式

iframe的优势:

1、iframe能够原封不动嵌入网页展现出来。

2、如果多个页面引入iframe,那么只需修改iframe的内容,便于快速修改所有引用页面内容。

3、网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe嵌套,增加代码重用度。

4、遇到第三方缓慢的第三方内容如广告和图标,这些问题可以用iframe解决。

iframe的劣势:

1、页面较多,管理不易。

2、很多移动设备无法完全显示框架,设备兼容较差。

3、代码复杂,某些搜索引擎无法引到,这个很关键,搜索引擎基本采用爬虫技术,无法很好处理iframe的内容,不利于SEO搜索引擎优化。

4、由于iframe嵌套较多页面会出现多个上下、左右滚动条,分散访问者注意力,用户体验度差。

5、iframe会增加服务器http请求,对大型网站不可取。现在基本都使用ajax代替iframe,iframe基本已经退出前端开发了。

2.11、link和@import导入css的用户和区别

link是html的标签,除了加载CSS外,还能定义RSS等其他事务;

@import属于CSS范畴,只能加载CSS。

link引用CSS时,在页面载入时同时加载;@import需要网页载入后加载,

link没有兼容问题;@import是在CSS2.1提出的,低版本浏览器不支持。

link支持使用JavaScript控制DOM去改变样式,而@import不支持。

2.12、DOM事件机制和模型

DOM0级模型、IE事件模型、DOM2级事件模型。

用户点击事件触发过程:

事件捕获阶段(从上到下,从外到内)》》处于目标事件阶段》》事件冒泡阶段(从下到上,从内到外)

window.addEventListener(
  "click",
  function (event) {
    event = event || window.event /*ie*/;
    const target = event.target || event.srcElement; /*ie*/ // 拿到事件目标

    // 阻止冒泡
    // event.stopPropagation()
    // event.cancelBubble=true; // ie

    // 阻止默认事件
    // event.preventDefault();
    // event.returnValue=false; // ie
  },
  /* 是否使用捕获,默认是fasle, */ fasle
);

事件委托

事件委托指的是,不再事件触发的元素上设置监听,而是在父元素上设置监听函数,通过判断事件发生的DOM类型,做出不同的动作。

例:如ul和li标签的事件监听,添加事件时,采用事件委托机制,不会在li上直接添加,而是在ul上添加。

优势: 适合动态元素的绑定,新增的子元素同时也有监听函数,也有事件触发机制。

2.13、手动编写动画时,设置最小时间间隔多少合适?

大多数显示器的频率60Hz,刷新频次每秒60次,时间间隔为 1/60*1000ms =16.7ms

2.14、::before和:after中双冒号和单冒号区别?

单冒号(:)用在CSS3伪类,双冒号(::)用于CSS3的伪元素。::before就是以一个子元素存在,定义一个元素主体之前的一个伪元素。不再dom之中,只存在页面上。:before和:after这两个伪元素,是CSS2.1新增。最初,伪元素前缀使用的是冒号语法,随着web优化,CSS规范中,伪元素语法被修改为使用双冒号::before和::after。

2.15、CSSsprites 精灵图

CSSsprites:就是网页中的一些背景图片整合到一张图中,利用CSS的“background-image”,“background-repeat”,“background-position”的组合进行图片定位,background-position能够精确定位图片出现在背景中的位置。这样减少很多图片请求开销,由于图片请求耗时较长。请求虽然可以并发,但是有限制,一般浏览器6个。

2.16、重排和重绘

重绘(repaint或redraw):当盒子的位置、大小及其他属性,如:颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器根据元素新属性重新绘制,使得元素出现新的外观。

重绘条件:改变元素外观属性。如:color、font-size、background等。

注意:table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比如同等元素需要两倍时间,这就是尽量避免使用table布局页面的原因。

重排(重构、回流、reflow):当渲染树中的一部分(或全部)应为元素的规模尺寸,布局、隐藏等改变是需要重新构建,成为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

重绘和重排的关系:在回流的时候,浏览器会使用渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。重排一定会引起重绘,重绘不一定会引发重排。

2.17、BOM浏览器  对象  模型

<1>Windows对象

概念:所有浏览器都支持window对象。它表示浏览器窗口。

所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。

全局变量是 window 对象的属性。

全局函数是 window 对象的方法。

<2>History

History对象是window对象的历史记录对象,常见的方法有back、forward、go(count)

<3>Location

Location对象式BOM中比较重要的对象

属性:host、hostname、href、pathname、port、protocol、方法有reload 刷新页面。

http协议://baijiahao.baidu.com:80 域名  :80/443 端口/s 虚拟路径?get请求参拼 接

id=1702594533775076008   key=value

*持续化存储:

localStorage.(永久存储,只要不删除存储数据)

setItem(key,value)

getItem(key)

removeItem(key)

SessionStorage.(永久存储,只要不关闭浏览器)

setItem(key,value)

getItem(key)

removeItem(key)

JS的Domument()

<1>获取目标元素

document.getElementByld() (可以通过id找到唯一的标签)

document.getElementsByTagName 找到所有标签名可匹配的标签

document.getElementsByClassName 根据类名查找所有类名可匹配的标签

document.get(...):有“Elements”,就说明返回类型为集合

innerText 只包含文本 innerHTML 可以包含标签 (只有js对象才有innerText)

innerText主要是设置文本的,设置标签内容,是没有标签的效果的

innerHTML是可以设置文本内容,主要的作用是在标签中设置新的html标签内容,是有标签效果的

<2>修改元素的属性、样式、内容

1.hasAttribute(“属性名”)(判断是否有想要添加的属性)

2.getAttribute(“属性名”)(获取属性名称)

3.setAttribute(“属性名”,“属性值”)(设置属性)

4.hasAttribute(“属性名”)(判断是否有添加的属性)

5.removeAttribute(“属性名”) (移除添加属性)

获取标签元素的内联样式,可以用(.style)

getComputedStyle  计算样式

获取标签元素的内部样式表、外部样式表getComputedStyle(目标)

*设置任何元素的样式都可以通过.style.属性名

操作DOM:绑定事件

on+事件名称 (事件监听;所有事件处理可理解为js对象中的键是时间名,键的值为匿名函数)

onscroll 就是window对象的滚动事件监听

onclick 鼠标点下抬起整个过程触发一次

onmousedown 鼠标点下时触发

onmouseup 鼠标在点下区域,抬起时触发

找到元素
赋予事件监听
修改属性、内容
操作DOM节点

<1>节点的创建和删除

createElement() 创建元素节点

appendChild() 末尾追加方式插入点

insertBefore() (新元素,参考元素) 在指定节点前插入新节点

remove() 删除指定节点

<2>相关节点获取

找元素的父标签 parentElement

找元素的所有子标签 children

第一个子元素 firstElementChild

最后一个子元素 lastElementChild

上一个 previousElementSibling

下一个 nextElementSibling

div一般不给予高度,是div里边的东西撑起来一个高度。

如外层容器,width、height的不满足,内部img的图片的width、height时,可以设置img 的width:100%,设置外层容器overflow:hidden

1.SVG代码:图片新格式(文本内容地址)

2.外层容器(div)设置font-size:0;

使用方式是,内部元素使用inline-block

二、JavaScript 部分内容

1.1、js的数据类型

js数据类型8中,es6新增Symbol、BigInt;具体有Number、String、Boolean、undefined、null、Object、Symbol、BigInt

js的基本数据类型和复杂数据类型的区别:在堆栈中,赋值时区别,一个拷贝值一个拷贝地址。

基本类型和引用类型内存中区别:

例:function  test(){

                var age =123;//值是直接存在栈中

                var arr =new Array(12,23,34); //栈中存储只是堆中的一个地址。

        }

null与undefined 的异同

相同:

Undefined 和Null都是基本数据类型,这两个基本数据类型分别都只有一个值,就是undefined和null。

不同点:

null转换成数字是0,undefined转换数字是NaN。

undefined代表的含义是未定义,null代表的含义是空对象。

typeof null 返回"object",typeof undefined 返回”undefined“。

null==undefined; //true

null ===undefined; //false

其实null不是对象,这个是JS存在很久的Bug。在js的初版中使用32位系统,为了性能考虑使用地位存储变量的类型信息,000开头代表的是对象;然而null表示为全零,所以会将null判断为object。虽然现在内部类型判断代码已经改变,但是bug却一直流传下来。

1.2、JavaScript判断数据类型有几种方法?

1、typeof方式

typeof一般用来判断基本数据类型,除了判断null会输出”object“,其它都是正确的。

typeof判断引用类型时,除了判断函数输出”function“,其它输出为”object“

2、instanceof方式

instanceof主要用于判断引用类型,原理就是检测构造函数的prototype属性是否在某个示例对象的原型链上,不能判断基本数据类型。

// 实现 instanceof 2
function myInstanceof(left, right) {
  // 这里先用typeof来判断基础数据类型,如果是,直接返回false
  if (typeof left !== "object" || left === null) return false;
  // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
  let proto = Object.getPrototypeOf(left);
  while (true) {
    if (proto === null) return false;
    if (proto === right.__proto__) return true; //找到相同原型对象,返回true
    proto = Object.getPrototypeof(proto);
  }
}
let obj =new Object({});
let obj1 ={};
console.log(myInstanceof(obj,obj1));

3、Object.prototype.toString.call() 返回 [object Xxxx] 都能判断,方法如下:

var getType = function(translateData) {
      var toString = Object.prototype.toString;
      var dataType =
        translateData instanceof Element
          ? "element" // 检测DOM节点类型
          : toString
              .call(translateData)
              .replace(/\[object\s(.+)\]/, "$1")
              .toLowerCase()
      return dataType
};
let number = new Number(223);
console.log(getType(obj))

1.3、深拷贝和浅拷贝

数据类型定义:

基本数据类型:Boolean、String、Number、null、undefined
引用数据类型:Object、Array、Function、RegExp、Date等

概念定义:

深拷贝和浅拷贝都只针对引用数据类型,浅拷贝会对对象逐个成员依次拷贝,但只复制内存地址,而不复制对象本身,新旧对象成员还是共享同一内存;

深拷贝会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

区别:浅拷贝只复制对象的第一层属性,而深拷贝会对对象的属性进行递归复制。

浅拷贝示例:

浅拷贝是按位拷贝对象,它会创建一个新对象,对原有对象的成员进行依次拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。因此如果新对象中的某个对象成员改变了地址,就会影响到原有的对象。

//手写浅拷贝
function shallowCopy(obj1) {
 let obj2 = Array.isArray(obj1) ? [] : {}
 for (let i in obj1) {
  obj2[i] = obj1[i]
 }
 return obj2
}
var obj1 = {
  'name' : 'zhangsan',
  'language' : [1,[2,3],[4,5]],
};
var obj2 = shallowCopy(obj1);
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1);//{"language":{"0":1,"1":{"0":"二","1":"三","length":2},"2":{"0":4,"1":5,"length":2},"length":3},"name":"zhangsan"}
console.log('obj2',obj2)//{"language":{"0":1,"1":{"0":"二","1":"三","length":2},"2":{"0":4,"1":5,"length":2},"length":3},"name":"lisi"}

JS中使用浅拷贝的方法有:

Object.assign()(把源对象自身的任意多个的可枚举属性拷贝给目标对象,然后返回目标对象)

Array.prototype.concat()和Array.prototype.slice()(两个方法:Array的slice和contact方法都不会修改原数组,而是会返回一个对原数组进行浅拷贝的新数组。)

深拷贝示例:

对对象的属性中所有引用类型的值,遍历到是基本类型的值为止。

function deepCopy(obj, parent = null) {
 let result
 let _parent = parent
 while(_parent) {
  if (_parent.originalParent === obj) {
   return _parent.currentParent
  }
  _parent = _parent.parent
 }
 if (obj && typeof(obj) === 'object') {
  if (obj instanceof RegExp) {
   result = new RegExp(obj.source, obj.flags)
  } else if (obj instanceof Date) {
   result = new Date(obj.getTime())
  } else {
   if (obj instanceof Array) {
    result = []
   } else {
    let proto = Object.getPrototypeOf(obj)
    result = Object.create(proto)
   }
   for (let i in obj) {
    if(obj[i] && typeof(obj[i]) === 'object') {
     result[i] = deepCopy(obj[i], {
      originalParent: obj,
      currentParent: result,
      parent: parent
     })
    } else {
     result[i] = obj[i]
    }
   }
  }
 } else {
  return obj
 }
 return result
}
var obj1 = {
 x: 1 
}
 
//试调用
function construct(){
  this.a = 1,
  this.b = {
    x:2,
    y:3,
    z:[4,5,[6]]
  },
  this.c = [7,8,[9,10]],
  this.d = new Date(),
  this.e = /abc/ig,
  this.f = function(a,b){
    return a+b
  },
  this.g = null,
  this.h = undefined,
  this.i = "hello",
  this.j = Symbol("foo")
}
construct.prototype.str = "I'm prototype"
var obj1 = new construct()
obj1.k = obj1
obj2 = deepCopy(obj1)
 
obj2.b.x = 999
obj2.c[0] = 666
 
console.log('obj1', obj1)
console.log('obj2', obj2)

可以使用js中的方法:

JSON.parse(JSON.stringify())(把JSON对象通过stringify转成字符串,parse再转成对象)

第三方js工具类,函数库lodash,其中的cloneDeep函数。

参考地址:https://www.jb51.net/article/192518.htm

1.4、JSON.stringify()问题有哪些

1、循环引用

 2、Symbol,function、undefined丢失

3、布尔值、数字、字符串包装对象转换为原始值

4、NaN、Infinity变成null

5、Date变为字符串

6、RegExp、Error转为空对象{}

1.5、模块化解决问题及种类

现代模块化机制要解决的问题如下

  1. 命名污染,全局污染,变量冲突等基础问题
  2. 内聚且私有,变量不能被外界污染到
  3. 怎么引入(依赖)其它模块,怎样暴露出接口给其它模块
  4. 依赖顺序问题,比如以前的 Jquery 问题
  5. 循环引用问题,等边界情况

模块化种类

1、commonjs(CJS)

服务端模块规范,可以实现服务器端模块重用,拷贝方式是是值拷贝;但加载模块是同步的,只有加载完成后才能执行后面的操作 。

//nodejs实现

const  sf  =require("sf")

module.exports = {};

2、AMD

可以实现异步加载依赖模块,并且会提前加载 ,require的时候加载;但使用需要先下载 require.js 文件,开发成本高,代码的阅读和书写比较困难。

// 由RequireJS实现

define(["juqery", "vue"], function ($, Vue) {

  // 依赖必须一开始就写好

  $("#app");

  new Vue({});

});

3、CMD

依赖就近,延迟执行;但需要下载seaJS模块 ,模块的加载逻辑偏重 ,依赖 SPM 工具打包。

// 由SeaJS 实现

define(function (require, exports, module) {

  var a = require("./a");

  a.doSomething();

  // ....

  var b = require("./b"); // 依赖可以就近书写

  b.doSomething();

  // ...

});

4、ESM

在ES6之前,要想在前端做模块化开发,必须依赖第三方框架来实现,如:requireJS与seaJS。ES6的出现,完全可以取代AMD 、CMD规范和NodeJS支持的CommonJS 规范,浏览器和服务端都支持。

// 由es6实现

import $ from "jquery";

export default $;

5、UMD(通用模块化导入)

(function (global, factory) 
  typeof exports === 'object' && typeof module !== 'undefined' ? 
         module.exports = factory() :
         typeof define === 'function' && define.amd ? 
                define(factory) :
                (global = global || self, global.Vue = factory());
}(this, function () { 'use strict';...})

参考地址:JS模块化 - 简书

1.6、call、apply、bind作用

call、apply、bind都是改变this指向,bind不会立即执行,会返回一个绑定this的函数,call和apply接收的参数不一样,call接收的时一个一个的参数,而apply接收的是个参数数组。

obj.call(this指向,参数1,参数2)

obj.apply(this指向,[参数1,参数2])

function fn(name){
    console.log(this,name)
}
const obj ={age:20}
const result =fn.bind(obj) //返回新函数
result("张三")
// 实现一个 apply
Function.prototype.myApply = function (context) {
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  var res = context[fn](...arguments[1]);
  delete context[fn];
  return res;
};

// bind实现示例
Function.prototype.bind =
  Function.prototype.bind ||
  function bind(thisArg) {
    if (typeof this !== "function") {
      throw new TypeError(this + " must be a function");
    }
    var self = this;
    var args = [].slice.call(arguments, 1);
    var bound = function () {
      var boundArgs = [].slice.call(arguments);
      var finalArgs = args.concat(boundArgs);
      if (this instanceof bound) {
        if (self.prototype) {
          function Empty() {}
          Empty.prototype = self.prototype;
          bound.prototype = new Empty();
        }
        var result = self.apply(this, finalArgs);
        var isObject = typeof result === "object" && result !== null;
        var isFunction = typeof result === "function";
        if (isObject || isFunction) {
          return result;
        }
        return this;
      } else {
        return self.apply(thisArg, finalArgs);
      }
    };
    return bound;
  };

1.7、防抖

debounce所谓防抖,就是值触发时间后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。

解决那些问题:

  • scroll事件滚动触发的时候
  • 搜索框输入查询的时候
  • 表单验证
  • 按钮的提交事件
  • 浏览器的窗口缩放,resize事件

示例代码:

function debounce(func, wait, immediate) {
  let timeout;
  return function () {
    const context = this;
    const args = [...arguments];
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(() => {
        timeout = null;
      }, wait);
      if (callNow) func.apply(context, args);
    } else {
      timeout = setTimeout(() => {
        func.apply(context, args);
      }, wait);
    }
  };
}


/**
 * 防抖函数的自定义实现
 * @param func 执行的函数
 * @param wait 等待的时间
 * @param immediate 是否立即执行
 */
function debounce (func, wait, immediate) {
  // result -- 返回值
  let timeout, result;
  let debounced = function () {
    let self = this
    let args = arguments
    clearTimeout(timeout)
    if (immediate) {
      // callNow是立即执行的变量
      let callNow = !timeout
      timeout = setTimeout(() => {
        timeout = null
      }, wait)
      // 由于最开始timeout为undefined,取反为true,故立即执行
      if (callNow) result = func.apply(self, args)
    } else {
      // 不会立即执行
      timeout = setTimeout(function() {
        //解决执行函数内部this指向问题以及event指向问题
        result = func.apply(self, args)
      }, wait)
    }
    return result
  }
  // 取消
  debounced.cancel = function () {
    clearTimeout(timeout)
    timeout = null // 防止内存泄露
  }
  return debounced
}

1.8、节流

连续触发事件但是n秒内只能触发一次

解决那些问题:

  • DOM元素的拖拽功能的实现
  • 计算鼠标移动的距离
  • 监听scroll滚动事件

示例:

function throttle(fn, wait) {
  let pre = 0;
  return function (...args) {
    let now = Date.now();
    if (now - pre >= wait) {
      fn.apply(this, args);
      pre = now;
    }
  };
}

/**
 * 节流函数
 * 最终版本
 * 第一次不会触发,最后一次会调用 leading:false, trailing:true
 * 第一次会触发,最后一次不会触发 leading:true, trailing:false
 */
function trottle (func, wait, options) {
  let context, args, timeout, result
  let old = 0 // 时间戳
  if (!options) options = {} 
  let later = function () {
    old = new Date().valueOf()
    timeout = null
    result = func.apply(context, args)
  }
  let trottled = function () {
    context = this
    args = arguments
    let now = new Date().valueOf()
    if (options.leading === false  && !old) {
      old = now;
    }
    if (now - old > wait) {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null 
      }
      result = func.apply(context, args)
      old = now
    }

    if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, wait)
    }
    return result
  }
  trottled.cancel = function () {
    clearTimeout(timeout)
    timeout = null
  }
  return trottled
}

1.9闭包

闭包是指有权访问另一个函数作用域中的变量的函数 ——《JavaScript 高级程序设计》

闭包是将函数内部和函数外部连接起来的桥梁。

示例:

//函数内部定时器
(
function(){
	var a =0;
	setInterval(function(){
		console.log(a++)
	},1000)
}
)()
  • 闭包用途:
    • 能够访问函数定义时所在的词法作用域(阻止其被回收)
    • 私有化变量
    • 模拟块级作用域
    • 创建模块
  • 闭包缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

2.0、原型、原型链定义

原型:对象中固有的__proto__属性,该属性指向对象的prototype原型属性。

原型链:当我们访问一个对象的属性时,如果这个属性在对象的内部不存在,就会去它的原型对象中找,这个原型对象又有自己的原型,于是一直找下去。原型链的尽头是Object.prototype,因此我们新建对象就可以使用toString()方法。

特点:JavaScript 对象通过引用传递,我们创建的每个对象中并没有自己的一份原型副本。当我们改变原型时,相关对象也就一起改变了。

2.1、this指向、new关键字

1、this对象是执行上下文中的一个属性,它指向最后一次调用此方法的对象,在全局函数中,this等于window,而当函数作为某个对象调用时,this等于那个对象。在开发中通过如下方法判断:

1)、函数调用,当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象。

2)、方法调用,如果一个函数作为一个对象的方法来调用时,this指向这个对象。

3)、构造函数调用,this指向这个new新创建的对象。

4)、第四种apply、call和bind调用模式,这三个方法都能显示的指定调用函数的this指向。apply接收参数是数组,call接受的参数列表,bind方法通过传入一个对象,返回this绑定了传入对象的新函数。这个函数的this指向除了使用new是被改变,其他情况不变。

2、模拟实现new操作符

1)、创建一个新空对象

2)、设置原型,将对象的原型设置为函数的prototype对象。

3)、让函数this指向这个对象,执行构造函数的代码(为这个新对象添加属性)

4)、判断函数的放回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。

/**
 * 模拟实现 new 操作符
 * @param  {Function} ctor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    // ES6 new.target 是指向构造函数
    newOperator.target = ctor;
    // 1.创建一个全新的对象,
    // 2.并且执行[[Prototype]]链接
    // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor构造函数的其余参数
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新对象会绑定到函数调用的`this`。
    // 获取到ctor函数返回结果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
}
// 例子3 多加一个参数
function Student(name, age){
    this.name = name;
    this.age = age;
    // this.doSth();
    // return Error();
}
Student.prototype.doSth = function() {
    console.log(this.name);
};
var student1 = newOperator(Student, '若', 18);
var student2 = newOperator(Student, '川', 18);
// var student1 = new Student('若');
// var student2 = new Student('川');
console.log(student1, student1.doSth()); // {name: '若'} '若'
console.log(student2, student2.doSth()); // {name: '川'} '川'

student1.__proto__ === Student.prototype; // true
student2.__proto__ === Student.prototype; // true
// __proto__ 是浏览器实现的查看原型方案。
// 用ES5 则是:
Object.getPrototypeOf(student1) === Student.prototype; // true
Object.getPrototypeOf(student2) === Student.prototype; // true

参考案例:

面试官问:能否模拟实现JS的new操作符 - 掘金

2.2、作用域、作用域链、变量提升

作用域:负责收集和维护所有声明的标识符(变量)组成一系列查询,并实施一套严格的规则,确定当前执行的代码对这些标识符的访问权限(全局作用域、函数作用域、块级作用域)。

作用域链:从当前作用域开始一层一层向上寻找某个变量,直到找到全局作用域还没找到,就放弃。这种一层层的关系,就是作用域链。

2.3、继承多种方式

1、原型链继承方式:这中方式存在一个缺点,在包含引用数据类型时,会被所有示例对象共享,容易造成修改的混乱。在创建子类型的时候不能项超类型传递参数。

function Person(name,age){
	this.name =name;
	this.age =age;
	this.say =function(){
		console.log(`${this.name}${this.age}`)
	}
}
Person.prototype.test=function(){
	console.log("我是原型上的方法")
}
function Women(){
	this.sex="男";
}
Women.prototype = new Person('张三',30);//父类实例作为子类原型
var one = new Women("王五",100);
one.say();//张三 30 子类示例,不能向类构造函数中传递参数
one.test();//可以调用原型方法。

2、构造函数方式:通过在子类的函数中调用超类的构造函数实现的。解决不可以向超类传递参数问题。缺点不能实现构造函数复用,且超类型原型定义的方法不能在子类型调用。

function Person(name,age){
	this.name =name;
	this.age =age;
	this.say =function(){
		console.log(`${this.name}${this.age}`)
	}
}
Person.prototype.test=function(){
	console.log("我是原型上的方法")
}

// 构造函数实现继承
function Women(){
	//在子类中,使用call调用父类方法,并将父类的this修改为子类的this。相当于把父类的实例属性复制一份到子类函数中。
	Person.call(this);
	this.name ="JACK";
	this.age =30;
}

var one =new Women();
one.say(); //JACK 30
one.test(); //错误,不能调用继承原型上的方法
只能继承父类实例的属性和方法,不能继承原型上的属性和方法

3、组合继承方式:就是将原型链和构造函数组合一起使用的。通过借用构造函数实现类型的属性继承,通过将子类型的原型设置为超类型的实例来实现方法的继承,可以解决以上两种方式缺点。由于是以超类型的实例作为子类型的原型,调用两次超类型构造函数,会造成子类型的原型中多了很多无用属性。

function Person(name,age){
	this.name =name;
	this.age =age;
	this.say =function(){
		console.log(`${this.name}${this.age}`)
	}
}
Person.prototype.test=function(){
	console.log("我是原型上的方法")
}

//子类
function Women(name,age,sex){
	Person.call(this,name,age);//实现继承一种方式
	this.sex = sex;
}
Women.prototype =new Person();//把Women 原型变成Person的实例(由于Women的实例能够访问到Women原型上的方法。)
var x =new Women("张三",39,'男');
x.say();
x.test();//继承原型上的方法

4、原型式继承:就是基于已有对象创建新对象,向函数中传入一个对象,返回一个以这个对象为原型的对象。这种继承不是为了创造一个新的类型,只是对某个对象实现简单继承,ES5中的Object.create()方法就是原型继承。缺点和原型链式相同。

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

5、寄生式继承:创建一个用于封装继承过程的函数,通过传入一个对象,然后赋值一个对象的副本,并且对对象进行扩展,最后返回这个对象。优点:对一个简单对象实现继承,如果这个对象不是我们的自定义类型时。缺点:没有办法实现函数复用。

	function createAnother(original) {
	  var clone = Object(original); //通过调用object函数创建一个新对象
	  clone.sayHi = function () {
	    //以某种方式来增强这个对象
	    alert("hello");
	  };
	  return clone; //返回这个对象
	}
	console.log(createAnother(aa))

6、寄生式组合继承:使用超类型的原型副本来作为子类型的原型,避免创建不必要的属性。组合继承缺点:使用超类型的实例作为子类型的原型,导致添加无用的原型属性。

	function extend(subClass, superClass) {
	  var prototype = Object(superClass.prototype); //创建对象
	  prototype.constructor = subClass; //增强对象
	  subClass.prototype = prototype; //指定对象
	}
	
	var cc ={
		name:"张三",
		sex:"男"
	}
	var dd = {
		name:"人",
		age:0,
		sex:"性别"
	}
	extend(cc,dd)
	console.log(cc,dd);

7、es6中的class继承

	//父类
	class People{
		constructor(name="张三",age=23){
			this.name = name;
			this.age = age;
		}
		eat(){
			console.log(`${this.name} ${this.age} eat food`)
		}
	}
	//子类
	class man extends People{
		constructor(name="王五",age=34){
			console.log("name",name)
			//继承父类属性
			super(name,age);
		}
		eat(){
			//继承父类方法
			super.eat();
		}
	}
	let manObj =new man("小明");
	manObj.eat();

2.4、类型转换

js使用运算符或者比较符,会自动隐式转换,规则如下:

-、*、/、%:一律转换为数值后计算。

+ 号情况:

        1、number+string =string ,运算顺序从左到右。

        2、number+Object,优先调用对象valueOf  在转toString

        3、number+boolean/null  》》number

        4、number+undefined 》》NaN

        5、[1].toString()==="1" 内部调用.join方法

        6、{}.toString() ==='[object object]'

        7、NaN !=NaN、+undefined 为NaN

2.5、Object.is()与比较操作符==、===的区别?

1、==会先进行类型转换在比较。

2、===比较时不会进行类型转换,类型不同则直接返回false。

3、Object.is()在===基础上特别处理了NaN,-0,+0,保证-0与+0不相等,但NaN与NaN相等。

4、==操作符强制转换规则

        1)、字符串和数字之间的相等比较,将字符串转换为数字之后在比较。

        2)、其它类型和布尔类型之间相等比较,先将布尔值转为数字,在应用其他规则进行比较。

        3)、null和undefined之间的相等比较,结果为真。其它值和他们进行比较都返回假。

        4)、对象和非对象之间的相等比较,对象先调用ToPrimitive抽象操作后,在进行比较。

        5)、如果一个操作值为NaN,则相等比较返回false(NaN本身也不等于NaN)。

        6)、如果两个操作值都是对象,则比较他们是不是指向同一个对象。如果都指向同一个对象,则相等操作符返回true,否则false。

img

 2.6、ES6相关内容  (ES6 入门教程

1、新增Symbol类型,标示独一无二的值,用于定义对象独一无二属性名

2、const/let都是用来声明变量,不能重复声明,具有块作用域。存在暂时性死区,不存在变量提升。(const一般用于声明常亮)

3、变量的结构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(...rest)

4、模板字符串(${data})

5、...扩展运算符(数组、对象)

6、箭头函数

7、Set和Map数据结构

8、Proxy/Reflect

9、Promise

10、async 函数

11、Class

12、Module语法(import/export)

2.7、let/const区别

const声明只读常亮,一旦声明值不在变化;

let是用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

var 在全局作用域中声明变量会变成全局变量。

let、const和var区别

1、不允许重复声明

2、不存在变量提升

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

3、暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

4、块级作用域:用 let 和 const 声明的变量,在这个块中会形成块级作用域

es5只有函数作用域和全局作用域

// IIFE 写法  函数会立即执行
(function () {
  var tmp = ...;
  ...
}());

// 块级作用域写法
{
  let tmp = ...;
  ...
}
// 函数声明
function a() {}
// 函数表达式
const b = function () {};

//rest  参数示例
function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3); // 10

//...扩展运算符
console.log(...[1, 2, 3]);
// 1 2 3

const b = { ...{ a: "2", b: "3" } };

//?. 可选链运算符:规则:左侧的对象是否为null或undefined。如果是的,就不再往下运算,而是返回undefined

a?.b;
// 等同于
a == null ? undefined : a.b;
// 注意 undefined == null ==> true


//?? Null 判断运算符: 规则:如果左侧的为 undefined或者null是就返回右边的,否则就直接返回左边的
const headerText = response.data.headerText ?? "Hello, world!";

2.8、箭头函数和普通函数区别

1、箭头函数没有this,this继承自当前的上下文,不能通过call、apply、bind去改变this。

2、箭头函数没有自己的arguments对象,但是可以访问外部函数的arguments对象。

3、不能通过new关键字调用(不能作为构造函数),同样也没有target和原型。

2.9、异步回调地狱问题

promise、generator,async/await

3.0、mouseover和mouseenter的区别

mouseover:当鼠标移入元素或其子元素会触发事件,所以有一个重复触发。

冒泡过程。对应的移除事件是mouseout

mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,不会冒泡,对应移除事件mouseleave。

3.1、setTimeout、setInterval和requestAnimationFrame之间区别

requestAnimationFrame不需要设置时间间隔,大多数电脑刷新频率60Hz,每秒重绘60次。大多浏览器对重绘有限制,不超过显示器重绘频率,即使超过这个频率用户体验也不会提升。因此,最平滑的最佳循环间隔是1000ms/60,约等于16.6ms。RAF采用的是系统时间间隔,不会因为前面任务影响运行,如果前面任务多,会影响setTimeout和setInterval真正运行时间间隔。

特点:

1)、RAF会把每一帧中所有Dom操作集中起来,在一次重绘或者回流中就完成,并且重绘或回流时间间隔,紧紧跟随浏览器的刷新频率。

2)、在隐藏或不可见的元素中,RAF不会进行重绘或回流,减少了CPU、GPU和内存使用量。

3)、  RAF是由浏览器专门为动画提供的API,在运行时自动优化方法调用,并且如果页面不是激活装在下,动画自动暂停,有效节省CPU开销。

3.2、JS常用函数:

*函数使用function声明 后面跟函数名()中编写形参列表

*函数语句块,使用{}声明,函数默认没有返回值,可以使用return返回

1、匿名函数

        匿名函数不能单独存在

        1)、可将匿名函数赋予一个变量,变量就代表着函数内存地址,变量名+()可以执行该匿名函数

        2)、可将匿名函数赋予一个形参

        3)、将匿名函数作为对象的键

2、js延迟函数setTimeout(匿名函数(){},时间);3000mg/s为3秒

        js延迟(延迟时间去执行函数)

3、js计时函数setInterval(匿名函数(){},时间)

        计时(间隔时间重复执行)

        clearInterval 清除计时

4、JS的数组

        1)、获取数组的长度(数组名.length)

        2)、为数组添加元素

        数组名.push();(默认从数组右边开始添加)

        数组名.unshift();(从左添加)  

        3)、删除数组元素

        数组名.pop();(默认删除右边,返回值是删除的元素)

        数组名.shift();(默认删除左边,返回值是删除的元素)

        4)、splice(第一个参数为索引,第二参数是删除的个数,第三个参数开始都是添加的元素)

        5)、sort(按字符排序)

        6)、reverse(逆序)

        7)、indexof(求元素的索引,不存在返回 -1)

        8)、join(将元素连接成字符串)       

        9)、slice()(数组截取,第一个参数起始位置,第二个参数结束位置)

        10)、include()(左侧数组是否包含,传入的参数元素)

                ["Banana", "Orange", "Lemon", "Apple", "Mango"].includes('Apple'); // true

5、JS的内置对象(命名为大写)

1)、Math(math是js中数学相关的内置对象,可直接使用)

        Math.PI   3.14

        Math.random 随机数[0,1)

        Math.floor 向下取整

        Math.ceil 向上取整

        Math.round   四舍五入

6、JS的字符串

        1)、js关于字符串常用函数

                length属性  求字符串的长度

                charAt   求对应位置字符  

                indexOf  求字符对应索引

                lastIndexOf  从右侧开始查找  求字符对应的索引值

                substring(start,end)  切片

                replace  替换

                split  分割字符串,返回类型为数组

7、JS的Date对象

        1)、常用函数

let time = new Date()  现在的时间
time.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)

time.getYear(); //获取当前年份(2位)

time.getFullYear(); //获取完整的年份(4位,1970-????)

time.getMonth(); //获取当前月份(0-11,0代表1月)

time.getDay(); //获取当前星期X(0-6,0代表星期天)

time.getDate(); //获取当前日(1-31)

time.getHours(); //获取当前小时数(0-23)

time.getMinutes(); //获取当前分钟数(0-59)

time.getSeconds(); //获取当前秒数(0-59)

time.getMilliseconds(); //获取当前毫秒数(0-999)

time.toLocaleDateString(); // 当前日期字符串 '2024/1/3'

time.toLocaleString(); // 当前日期及时间'2024/1/3 14:07:11'

        2)、日期处理库:moment.js

8、JSON对象

        1)、序列化(将对象转成JSON字符串(数组,对象))

                eg:let strObj = JSON.stringify(obj);

        2)、反序列化(就是将字符串转成新对象)

                eg:let.newObj = JSON.parse(strObj);

                *|| 左边为真返回左边,左边为假,返回右边;从localstorage中取info反序列失败,则obj赋值(let obj = JSON.parse(localStorage.getItem(“info”)) || {})


 

三、Vue知识点

1.1、vue响应式原理,及出现问题解决方法

Object.defineProperty 讲解参考:https://blog.csdn.net/weixin_46726346/article/details/115913752

vue2是通过Object.defineProperty来实现响应式的,存在一些缺陷:

1、当修改一个对象的某个键值属性时,这个键值没有在这个对象中,vue不能做响应式处理。

2、直接修改数组的某一项(arr[index]=“xxx”)vue无法进行响应式处理

解决方法:

1、Vue.set 去解决,具体this.$set(对象/数组,key值/index,value)

2、修改数组长度,使用splice方法

1.2、vue生命周期

beforeCreate() 实例化之前可以获得this,无法获得data中数据
created()  实例化之后
beforeMount()
mounted() $el用于获取Vue实例挂载的DOM元素,在mounted生命周期中才有效,之前的钩子函数内无效。

beforeUpdate()
updated()

beforeDestroy() 清除监听、定时器
destroyed()


// 被keep-alive 包裹的  参考:https://blog.csdn.net/m0_45070460/article/details/107432685
// keep-alive 标签 include exclude max
activated() {},
deactivated() {},

// 父子组件执行顺序
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted。


// 父子组件更新执行顺序

父组件 beforeUpdate -->
子组件 beforeUpdate -->
子组件 updated -->
父组件 updated -->


// 离开页面:实例销毁 --> DOM卸载
parent  beforeDestroy
child   beforeDestroy
child   destroyed
parent  destroyed

1.3、Vue的data为什么是个函数

由于vue中一个组件可以在多个地方调用,会有多个实例,如果返回对象,这些组件之间的数据是同一份(引用关系),改变其中一个组件数据,另一个组件数据也会被改变。

1.4、vue 的key的作用(遍历列表时,key最好不用index)

1、虚拟DOM中key作用:key是虚拟DOM对象标识,在更新显示时有重要作用。当后台数据发生变化时,vue根据新的数据,生成对应的虚拟DOM,随后会进行新旧虚拟DOM的比较,规则如下:

1)、旧的虚拟DOM中找到与新的虚拟DOM相同的key,如果虚拟DOM中的内容没有变化,直接用旧的真实DOM;如果虚拟DOM中内容变化了,则直接生成新的真实DOM,随后替换页面中原来的真实DOM。

2)、旧的虚拟DOM未找到和新的虚拟DOM相同的key,根据新的数据创建新的真实DOM,随后渲染至页面。

2、用index作为key可能存在问题:

1)、对数据进行逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新》》界面效果没有问题,效率低下。

2)、如果结构中包含输入类的DOM(输入框,复选框、单选框)、这时会产生错误的DOM更新》》界面问题出现。

3)、注意:如果不存在逆序添加、逆序删除等破坏顺序操作,仅仅做列表渲染,使用index作为key不会有问题。

1.5、vue双向数据绑定原理

vue.js主要采用的数据劫持结合发布者-订阅者模式方式,通过Object.defineProperty()来劫持。

各个属性的setter和getter,数据变动时发布消息给订阅者,触发相应监听回调。

具体步骤:

1)、需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter。这样就可以给对象某个值赋值,就会触发setter,那就可以监听到数据变化。

2)、compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应节点绑定更新函数,添加监听数据的订阅者,一旦数据变动收到通知更新视图。

3)、Watcher订阅者是Observer和Compile之间的通信桥梁,主要做的事情:

        a、在自身实例化是往属性订阅器(dep)里面添加自己

        b、自身必须有一个update()方法。

        c、待属性变动dep.notice()通知时,能调用自身的update方法,并触发Compile中绑定的回调,则调用成功。

4)、MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化-》视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。

1.6、Vue extend 和 mixins

vue extend 和 mixins 的区别, mixins 里面的 函数和本身的函数重名了使用哪一个,mixins 里面的生命周期和本身的生命周期哪一个先执行?

答:

1.7、组件动态加载

// component 动态组件,通过is设置要显示的组件
<component is="tradeInfo" >

1.8、组件递归

为组件设置name之后,就可以在当前组件递归使用。

1.9、vue的传值方式

// Vue组件间的传值的几种方式
1. props/emit
2、vuex
3. $refs/$parent/$children/$root/
4. $attrs/$listeners // $attrs 除了父级作用域 props、class、style 之外的属性
// $listeners 父组件里面的所有的监听方法
5. 事件总线,通过new Vue去实现 / mitt <==> vue3
6. provide/inject
    // 父组件
    props: {},
    provide() {
        name: this.name,
        user: this.user
    }
    // 子组件
    props: {},
    inject: ['user']
7. 本地存储、全局变量

2.0、watchmixins、组件顺序、组件配置

export default{
    name:"myComponentName",
    mixins:[混入名],
    components:{组件名},
    inject:["子组件中接收父组件的参数名,数据由父组件provide提供"],
    //props:["value","visible"],
    props:{
        id: String,
        type:{
            type:String,
            default:"warning",
            validator(val){
                return ["primary","warning","danger","success","info"].includes(
                val
                )
            }
        },
        list:{
            type:Array,
            default:()=>[]
        }
    },
    data:{
        return{
            name:"张三",
            user:{name:"张三",age:19},
            loading:true,
            //vue2
            obj:{
                name:"李四"
            },
            //vue2会进行深度合并
            obj:{name:"李四~",age:19},
            //vue3{name:"李四~"}
        }
    },
    //provide 不支持响应式,支持响应式需要传对象。
    provide(){
        return {
            userName:this.name,
            user:this.user,
        };
    },
    computed:{
        // fullName(){
        //     return "xxx";
        // },
        fullName:{
			get(){
				return this.$store.state.userName;
				// return "李四";
			},
			set(val){
				this.$store.commit("SET_NAME",val);
			}
        }
    },
	watch:{
		// name(value){
		// 	this.handleName();
		// },
		name:{
			immediate:true,
			deep:true,//
			handler(val,oldValue){
				this.handlerName()
			},
		},
		// this.obj.name="xxx",//写法不会执行。
		this.obj ={name:"xxx"},//可以执行。
		//和上面等价
		obj:{
			handler(value){
				console.log("value",value);
			}
		},
		this.obj.name ="xxx",//这样可以监听到
		obj:{
			deep:true,//深度监听
			immediate:true,//第一次就用执行这个方法
			handler(){
				console.log("value",value)
			}
		},
		obj:{
			deep:true,//深度监听
			immediate:true,//第一次就用执行这个方法
			handler:"handlerName",
		},
		//==>
		obj:handlerName,
		"$route.path":{},
		"obj.a":{}		
	},
	beforeCreate(){
		console.log("this",this);
	},
	mounted(){
		//this.handlerName();
		this.fullName ="xxx";
		//this.fullName '李四'
	},
	methods:{
		handlerName(){
			this.obj.name ="xxx";
		}
	}
}

2.1、常用指令

1、v-show  控制display none 切换

2、v-if、v-else-if、v-else  判断逻辑

3、v-for 数据遍历, 需要绑定key(vue2 v-for比v-if 优先级高  vue3  v-if比v-for优先级高)

4、v-html 直接放入html页面展示

5、v-text  鼠标悬浮元素时提示信息

6、v-once 元素或组件只会渲染一次,即静态内容

7、v-cloak [v-cloak] {dispaly:none}  解决浏览器在加载页面时因存在事件差而产生的闪动问题,它的原理是先隐藏文件挂载位置,处理渲染好后在显示最终结果。这个指令需要与css规则一起使用才可以。

8、v-bind =》:  属性或入参绑定    v-on => @  绑定事件

<!--- 可以直接 v-bind="object" v-on="object" -->

<Child1 v-bind="$attrs" v-on="$listeners"></Child1>

9、v-model 一般绑定data中的某个变量

<el-input v-model="keyword"></el-input>
<!--- 等价下面这个 -->
<el-input :value="keyword" @input="keyword = $event"></el-input>

10、自定义指令

Vue.directive("指令名", {
  // 生命周期
  // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  bind(el, binding, vnode, oldVnode) {
    //
    // binging.value 拿到指令值
    // binding.modifiers 修饰符对象
  },
  // 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
  inserted(el, binding) {},
  update() {},
  componentUpdated(el, binding) {},
  // 只调用一次,指令与元素解绑时调用
  unbind() {},
});

// 默认绑定 bind update 的生命周期
Vue.directive("指令名", function (el, binding, vnode, oldVnode) {});

2.2、修饰符

.lazy、.number、.trim、.enter、.prevent、.self 

 .sync

<Dialog  :visible.sync="visible"></Dialog>
<!--- 等价下面这个 -->
<Dialog  :visible="visible" @update:visible="visible = $event"></Dialog>

2.3、scoped 作用

scoped  用于控制样式只在当前组件生效。

<style scoped></style>

渲染规则:

.a .b {
}
== > .a .b[data-v-xx] {
}
.a /deep/ .b {
}
== > .a[data-v-xxx] .b {
}
.a >>> .b {
}
== > .a[data-v-xxx] .b {
}
.a ::v-deep .b {
}
== > .a[data-v-xxx] .b {
}

2.4、router的使用

// 全局路由守卫
router.beforeEach((to, from, next) => {})
router.afterEach((to, from) => {})

new VueRouter({
    mode: 'hash', // hash | history | abstract
    // 滚动位置
    scrollBehavior(to, from, savedPosition) {
       if (savedPosition) return savedPosition
       return { y: 0 }
	},
    routes: [
        {
            path: '/',
            // 路由独享守卫
            beforeEnter(to, from, next) {}
        }
    ]
})

// 组件内的路由
beforeRouteEnter(to, from, next) {}
beforeRouteUpdate(to, from, next) {}
beforeRouteLeave(to, from, next) {}

// 跳转
this.$router.push({name: '', path: '', query: {}})
this.$router.replace({path:"/education"}); //不记录历史跳转
// 路由信息
this.$route.query this.$route.params

2.5、vuex的使用

state getters mutations actions modules  主要涉及这些关键字

//第一步、目录 :src/store/modules/app.js
//内容:
const state = {
  userName: ''
}
const mutations = {
  SET_USER_NAME(state, name) {
    state.userName = name
  }
}
const actions = {
  // 设置name
  setUserName({ commit }, name) {
    commit('SET_USER_NAME', name)
  }
}
export default {
  state,
  mutations,
  actions
}

//第二步、目录:src/store/getters.js
//内容:

const getters = {
    userName: state => state.app.userName,
}
export default getters
//第三步、目录:src/store/index.js
//内容:
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'

Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = new Vuex.Store({
  modules,
  getters
})

export default store


//第四步、在main.js导入store
import store from './store'
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

//第五步:在组件中使用
    import {
        mapState,
        mapGetters,
        mapMutations
    } from 'vuex'


    computed: {

      ...mapState(['']),
      ...mapGetters(['userName', ''])
    },


methods: {
...mapMutations(['setUserName','']),
    test(){
        this.setDisabledFlag('张三'); //设置名称
    }

}
原始方法使用:

// state
this.$store.state.userInfo;
// getters
this.$store.getters.userInfo;

// mutations
this.$store.commit("SET_USER_INFO", "传递数据");

// actions
this.$store.dispatch("logout").then((res) => {});

// -----------------------------------
// modules > user
// namespaced: true,

// state 拿 name
this.$store.state.user.avatar;
// getters
this.$store.getters.user.avatar;

// mutations
this.$store.commit("user/SET_TOKEN", "传递数据");

// actions
this.$store.dispatch("user/login").then((res) => {});

// -----------------------------------
// modules > user
// namespaced: false,

// state 拿 name
this.$store.state.user.avatar;
// getters
this.$store.getters.user.avatar;

// mutations
this.$store.commit("SET_TOKEN", "传递数据");

// actions
this.$store.dispatch("login").then((res) => {});

2.6、vue3相关内容

1.1、vue3新增内容

1、新增了三个组件:Fragment 支持多个根节点、Suspense 可以在组件渲染之前的等待时间显示指定内容、Teleport 可以让子组件能够在视觉上跳出父组件(如父组件overflow:hidden)

2、新增指令 v-memo,可以缓存 html 模板,比如 v-for 列表不会变化的就缓存,简单说就是用内存换时间

3、支持 Tree-Shaking,会在打包时去除一些无用代码,没有用到的模块,使得代码打包体积更小

4、新增 Composition API 可以更好的逻辑复用和代码组织,同一功能的代码不至于像以前一样太分散,虽然 Vue2 中可以用 minxin 来实现复用代码,但也存在问题,比如方法或属性名会冲突,代码来源也不清楚等

5、用 Proxy 代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等13种方法

6、重构了虚拟 DOM,在编译时会将事件缓存、将 slot 编译为 lazy 函数、保存静态节点直接复用(静态提升)、以及添加静态标记、Diff 算法使用 最长递增子序列 优化了对比流程,使得虚拟 DOM 生成速度提升 200%

7、支持在 <style></style> 里使用 v-bind,给 CSS 绑定 JS 变量(color: v-bind(str))

8、用 setup 代替了 beforeCreate 和 created 这两个生命周期

9、新增了开发环境的两个钩子函数,在组件更新时 onRenderTracked 会跟踪组件里所有变量和方法的变化、每次触发渲染时 onRenderTriggered 会返回发生变化的新旧值,可以让我们进行有针对性调试

10、毕竟 Vue3 是用 TS 写的,所以对 TS 的支持度更好

11、Vue3 不兼容 IE11

不错的文章推荐:聊一聊 Vue3 的 9 个知识点 - 掘金

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,以下是 TypeScript 前端开发中的十个重要知识点: 1. 类型系统:TypeScript 是 JavaScript 的超集,它引入了静态类型检查,可以在编译时捕获潜在的类型错误,并提供更好的代码补全和文档。 2. 接口和类型:TypeScript 提供了接口和类型(type)来定义自定义数据结构和对象的形状。它们可以用于强制编译时类型检查和类型推断。 3. 类和继承:TypeScript 支持类和继承,让你可以使用面向对象的编程范式来组织和管理代码。 4. 泛型:泛型允许你编写可重用的代码,可以在不同类型之间共享相同的逻辑。它在创建通用数据结构和函数时非常有用。 5. 模块化:TypeScript 原生支持 ES 模块规范,可以帮助你将代码拆分为多个可重用的模块,并提供更好的代码组织和封装。 6. 异步编程:TypeScript 提供了异步编程的支持,包括 Promise、async/await 和生成器等语法糖,使得处理异步操作更加简洁和可读。 7. 枚举类型:枚举类型允许你定义一组命名的常量,并将它们作为一种数据类型使用。这在需要表示一组相关的变量时非常有用。 8. 类型推断:TypeScript 的类型系统可以根据上下文自动推断变量的类型,减少了手动类型注解的工作量,并提供更好的开发体验。 9. 类型声明文件:TypeScript 可以使用类型声明文件(.d.ts)来描述 JavaScript 库的类型信息,从而提供更好的代码补全和类型检查。 10. 第三方库和工具支持:TypeScript 生态系统非常丰富,支持大多数常用的前端库和工具,如 React、Vue、Webpack 等,使得开发和维护前端项目更加便捷。 这些知识点涵盖了 TypeScript 前端开发的核心概念和特性,希望对你有所帮助!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值