IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 杂记-随缘啦 -> 正文阅读

[JavaScript知识库]杂记-随缘啦

组件之间如何通信?

组件间通信可以通过props、传递回调函数、context、redux等形式进行组件之间通讯

react/vue中的key有什么作用?(key的内部原理是什么?)

1)简单来说,key是虚拟DOM对象的标识,在更新显示时,key起着极其重要的作用。

2)详细来说,当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

? a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:

? (1)若虚拟DOM中内容没变,直接使用之前的真实DOM

? (2)若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

? b. 旧虚拟DOM中未找到与新虚拟DOM相同的key

? 根据数据创建新的真实DOM,随后渲染到页面

使用index作为key可能会引发的问题

  1. 若对数据进行逆序添加,逆序删除等破坏顺序性的操作:

    会产生没有必要的真实DOM更新 ==> 界面效果没有问题,但效率低

  2. 若结构中还包含输入类的DOM(如输入框,选择框等):

    会产生错误DOM更新 ==> 界面有问题

  3. 注意:如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

选择key

  1. key应该是唯一的
  2. key不要使用随机值(随机数在下一次render时,会重新生成一个数字)
  3. 避免使用index作为key

refs的理解?应用场景?

Refs允许我们访问DOM节点或在render方法中创建的React元素

应用场景:

  • 对DOM元素的焦点控制、内容选择、控制
  • 对DOM元素的内容设置及媒体播放
  • 对DOM元素的操作和对组件实例的操作
  • 集成第三方DOM库

Hooks的理解?解决了什么问题?

Hook是React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React特性

解决问题:

  • 难以重用和共享组件中的与状态相关的逻辑
  • 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state时,每个生命周期函数可能会包含着各种互不相关的逻辑在里面
  • 类组件中的this增加学习成本,类组价在基于现有工具的优化上存在些许问题
  • 由于业务变动,函数组件不得不改为类组件等

redux工作原理?

redux 要求我们把数据都放在 store 公共存储空间

一个组件改变了 store 里的数据内容,其他组件就能感知到 store的变化,再来取数据,从而间接的实现了这些数据传递的功能

工作流程如下所示:
在这里插入图片描述

render触发时机?

在 React 中,类组件只要执行了 setState 方法,就一定会触发 render 函数执行

函数组件 useState 会判断当前值有无发生改变确定是否执行render方法,一旦父组件发生渲染,子组件也会渲染

如何减少render?

父组件渲染导致子组件渲染,子组件并没有发生任何改变,这时候就可以从避免无谓的渲染,具体实现的方式如下:

  • shouldComponentUpdate
  • PureComponent
  • React.memo

jsx转化DOM过程?

jsx首先会转化成 React.createElement这种形式,React.createElement作用是生成一个虚拟DOM对象,然后会通过ReactDOM.render进行渲染成真实DOM

性能优化手段有哪些?

除了减少render的渲染之外,还可以通过以下手段进行优化:

  • 避免使用内联函数
  • 使用React Fragments避免额外标记
  • 使用Immutable
  • 懒加载组件
  • 事件绑定方式
  • 服务端渲染

什么是防抖和节流?有什么区别?如何实现?

防抖:触发高频事件后n秒内 函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

// 每次触发事件时 都取消之前的延时调用方法
function debounce(fn) {
  let timeout = null; //创建一个标记用来存放定时器的返回值
  return function() {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout,这样就能保证输入字符后 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
      fn.apply(this, arguments);
    },500);
  }
}
function sayHi() {
  console.log("防抖成功");
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi));

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

function throttle(fn) {
  let canRun = true; // 通过闭包保存一个标记
  return function() {
    if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
    canRun = false; // 立即设置为false
    setTimeout(() => {// 将外部传入的函数的执行放在setTimeout中
      fn.apply(this, arguments);
      // 最后在setTimeout执行完毕后
      canRun = true;
    },500);
  }
}
function sayHi(e) {
  console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));

npm模块安装机制,为什么输入 npm install 就可以自动安装对应模块?

  1. npm 模块安装机制:
  • 发出npm install 命令
  • 查询node_modules目录之中是否已经存在指定模块
    • 若存在,不再重新安装
    • 若不存在
      • npm 向 registry 查询模块压缩包的网址
      • 下载压缩包,存放在根目录下的 .npm目录里
      • 解压压缩包到当前项目的node_modules目录
  1. npm 实现原理:
    输入 npm install 命令并敲下回车后,会经历如下几个阶段(以npm 5.5.1为例):
    1. 执行工程自身的 preinstall
      当前 npm 工程如果定义了preinstall 钩子此时会被执行

    2. 确定首层依赖模块

      • 首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)
      • 工程本身是整颗依赖树的根节点,每个首层依赖模块都是根节点下面的一颗子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。
    3. 获取模块
      获取模块是一个递归的过程,分为以下几步:

      • 获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为package.json中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中该模块信息直接拿即可,如果没有则从仓库获取。如 package.json 中某个包的版本是^1.1.0,npm就会去仓库中获取符合 1.x.x形式的最新版本。
      • 获取模块实体。上一步会获取到模块的压缩包地址(resolved字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。
      • 查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。
    4. 模块扁平化(dedupe)
      上一步获取到的是一颗完整的依赖树,其中可能包含大量重复模块。比如A模块于loadsh,B模块同样依赖于lodash。在npm3以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。

      从npm3开始默认加入了一个dedupe的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块,则将其丢弃。

      这里需要对重复模块进行一个定义,它指的是模块名相同semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在dedupe过程中被去掉。

      比如 node-modules 下 foo 模块依赖 lodash@^ 1.0.0,bar模块依赖lodash@^ 1.1.0,则^ 1.1.0 为兼容版本。

      而当 foo 依赖 lodash@^ 2.0.0 ,bar依赖 lodash@^ 1.1.0,则依据 semver 的规则,二者不存在兼容版本。会将一个版本放在 node_modules 中,另一个仍然保留在依赖树里。

      举个例子,假设一个依赖树原本是这样:
      node_modules
      – foo
      ---- lodash@version1

      – bar
      ---- lodash@version2
      假设 version1 和 version2 是兼容版本,则经过 dedupe 会成为下面的形式:

      node_modules
      – foo

      – bar

      – lodash(保留的版本为兼容版本)
      假设 version1 和 version2 为非兼容版本,则后面的版本保留在依赖树中:

      node_modules
      – foo
      – lodash@version1

      – bar
      ---- lodash@version2

    5. 安装模块
      这一步将会更新工程中的 node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall的顺序)。

    6. 执行工程自身生命周期
      当前 npm 工程如果定义了钩子此时会被执行(按照install、postinstall、prepublish、prepare 的顺序)。
      最后一步是生成或更新版本描述文件,npm install 过程完成。

ES5的继承和ES6的继承有什么区别?

ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))

ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super() 方法,然后再用子类的构造函数修改this)

具体的:ES6通过clas s关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。
ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。

为什么虚拟dom会提高性能?

虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff 算法避免了没有必要的dom操作,从而提高性能。
具体实现步骤如下:

  1. 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中
  2. 当状态变更时,重新构造一颗新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
    把步骤2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了。

分析比较 opacity:0、visibility:hidden、display:none优劣和适用场景

结构:
display:none 会让元素完全从渲染树中消失,渲染的时候不占据任何空间,不能点击
visibility:hidden 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击
opacity:0 不会让元素从渲染树消失,渲染元素继续占据空间,只是不可见,可以点击

继承:
display:none 和 opacity:0 是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。
visibility:hidden 是继承属性,子孙节点消失由于继承了hidden,通过设置visibility:visible 可以让子孙节点显示。

性能:
display:none 修改元素会造成文档回流,读屏器不会读取display:none 元素内容,性能消耗较大
visibility:hidden 修改元素只会造成本元素的重绘,性能消耗较少,读屏器读取visibility:hidden元素内容
opacity:0 修改元素会造成重绘,性能消耗较少

css sprite 是什么,有什么优缺点?

概念:将多个小图片拼接到一个图片中。通过 background-position 和元素尺寸调节需要显示的背景图案。
优点:

  1. 减少 HTTP 请求数,极大的提高页面加载速度
  2. 增加图片信息重复度,提高压缩比,减少图片大小
  3. 更换风格方便,只需要在一张或几张图片上修改颜色或样式即可实现

缺点:

  1. 图片合并麻烦
  2. 维护麻烦,修改一个图片可能需要重新布局整个图片、样式

link和@import的区别

  1. link 是 HTML 方式,@import 是 CSS 方式
  2. link 最大限度支持并行下载,@import 过多嵌套导致串行下载,出现FOUC
  3. link 可以通过 rel=“alternate stylesheet” 指定候选样式
  4. 浏览器对 link 支持早于 @import,可以使用@import 对老浏览器隐藏样式
  5. @import 必须在样式规则之前,可以在css文件中引用其他文件
  6. 总体来说:link 优于 @import

display:block 和 display:inline的区别

block 元素特点:

  1. 处于常规流中时,如果 width 没有设置,会自动填充满父容器
  2. 可以应用margin/padding
  3. 在没有设置高度的情况下会扩展高度以包含常规流中的子元素
  4. 处于常规流中时布局是在前后元素位置之间(独占一个水平空间)
  5. 忽略 vertical-aligh

inline 元素特点:

  1. 水平方向上会根据 direction 依次布局
  2. 不会在元素前后进行换行
  3. 受 white-space 控制
  4. margin/padding 在竖直方向上无效,水平方向上有效
  5. width/height 属性对非替换行内元素无效,宽度由元素内容决定
  6. 非替换行内元素的行框高由 line-height 确定,替换行内元素的行框高 由height,margin,padding,border决定
  7. 浮动或决定定位时会转换为 block
  8. vertical-align 属性生效

PNG、GIF、JPG的区别及如何选

GIF:

  1. 8位像素,256色
  2. 无损压缩
  3. 支持简单动画
  4. 支持boolean透明
  5. 适合简单动画

JPEG:

  1. 颜色限于 256
  2. 有损压缩
  3. 可控制压缩质量
  4. 不支持透明
  5. 适合照片

PNG:

  1. 有PNG8 和 truecolor PNG
  2. PNG8 类似 GIF 颜色上限为 256,文件小,支持alpha 透明度,无动画
  3. 适合图标、背景、按钮

js有几种数据类型,其中基本数据类型有哪些?

七种数据类型
Boolean、Null、Undefined、Number、String、Object、Symbol(ES6)
Symbol也是原始数据类型,表示独一无二的值
Object 为引用类型(范围挺大),也包括数组、函数

Promise构造函数是同步执行还是异步执行,那么 then 方法呢?

promise构造函数是同步执行的,then方法是异步执行的
Promise new 的时候会立即执行里面的代码, then是微任务 会在本次任务执行完的时候执行
setTimeout是 宏任务,会在下次任务执行的时候执行

列举出几种创建实例的方法

  1. 字面量
let obj = {'name':'张三'};
  1. Object构造函数创建
let Obj = new Object();
Obj.name = "张三";
  1. 使用工厂模式创建对象
function createPerson(name) {
	var o = new Object();
	o.name = name;
};
return o;
  1. 使用构造函数创建对象
function Person(name) {
	this.name = name;
}
var person1 = new Person('张三');

简述一下前端事件流

HTML中与JavaScript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预定事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流"的概念。
什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。
事件捕获阶段
处于目标阶段
事件冒泡阶段
addEventListener是DOM2级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

Function.proto_(getPrototypeof)是什么?

获取一个对象的原型,在Chrome中可以通过__proto__的形式,或者在ES6中可以通过Object.getPrototypeOf的实行
那么Function.proto是什么?也就是说Function由什么对象继承而来?

Function.__proto__==Object.prototype // false
Function.__proto__==Function.prototype // true

我们发现Function的原型也是Function

简述一下原型/构造函数/实例

原型(prototype):一个简单的对象,用于实现对象的 属性继承。可以简单理解为对象的爹。在FireFox和Chrome中,每个JavaScript 对象中都包含一个 protp(非标准)的属性指向它爹(该对象的原型),可obj.__protp__记性访问

构造函数:可以通过 new 来 创建一个对象 的函数
实例:通过构造函数和 new 创建出来的对象,我们常用的Object 便是一个构造函数,因此我们可以通过它构建实例。

const instance = new Object();

则此时,实例为instance,构造函数为Object,我们知道,构造函数拥有一个 prototype 的属性指向原型,因此原型为:

const prototype = Object.prototype

这里我们可以来看出三者的关系:

实例.__proto__ === 原型
原型.constructor === 构造函数
构造函数.prototype === 原型

如何实现一个bind函数

Function.prototype.myBind = function(context) {
	if(typeof this !== 'function') {
		throw new TypeError('Error');
	}
	var _this = this;
	var args = [...arguments].slice(1)
	// 返回一个函数
	return function F() {
		if (this instanceof F) {
			return new _this(...args, ...arguments)
		}
		return _this.apply(context, args.concat(...arguments))
	}
}

如何实现一个call函数

Function.prototype.myCall = function(context) {
	var context = context || window;
	// 给context添加一个属性
	context.fn = this
	// 将 context 后面的参数取出来
	var args = [...arguments].slice(1);
	var result = context.fn(...args)
	// 删除 fn
	delete context.fn
	return result
}

如何实现一个apply函数

Function.prototype.myApply = function(context) {
	var context = context || window
	context.fn = this
	
	var result;
	// 需要判断是否存储第二个参数
	// 如果存在,就将第二个参数展开
	if (arguments[1]) {
		result = context.fn(...arguments[1])
	} else {
		result = context.fn()
	}
	delete context.fn
	return result
}

参考链接:https://mp.weixin.qq.com/s/A2RtdHVhRq3ZTRchktPrrg

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:09:16  更:2021-08-09 10:11:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 12:55:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码