JavaScript(知识点总结)

JavaScript

数据类型

JS数据类型

数据类型和typeof

在这里插入图片描述

字符串

字符串翻转

str.split('').reverse().join(''); 
// split(): 将字符串转换为数组; 
// reverse(): 将数组倒序; 
// join(): 将数组转换为字符串

Math.floor()和parseInt()

Math.floor()在数轴上会转为偏小值
parseInt()会转为靠近原点的值

包装对象

在 JavaScript 中,包装对象是指将基本数据类型(如字符串、数字、布尔值)转换为对应的包装对象(String、Number、Boolean)的过程。这样做的主要目的是为了能够访问对象的属性和方法,因为基本数据类型本身是没有属性和方法的。

当你尝试访问基本数据类型的属性或方法时,JavaScript 会临时创建一个对应的包装对象,让你能够访问属性和方法,然后在访问完成后丢弃这个包装对象。

例如:

var str = "Hello";
var length = str.length; // 在这里,JavaScript 会创建一个 String 包装对象,以便访问字符串的 length 属性
console.log(length); // 输出: 5

var num = 10;
var numToString = num.toString(); // 在这里,JavaScript 会创建一个 Number 包装对象,以便调用 toString() 方法
console.log(numToString); // 输出: "10"

这种包装对象的过程是隐式的,通常不需要显式地创建包装对象。JavaScript 引擎会在必要时自动创建和销毁这些包装对象,以方便你使用基本数据类型的属性和方法。
自动转换生成的包装对象是只读的,无法修改

函数

定义方式

  • 自定义函数:function fn(){}
  • 匿名函数:var fn = function(){}
  • 构造函数:var fn = new function(){}

<script><script async><script defer>的区别

js默认同步下载、执行(所以会阻塞HTML渲染)

(对内联js无效↓)
async将下载改成异步(执行还是同步)【多个js存在时 谁先下载完谁先执行】
defer将下载、执行都改成异步【多个js存在时 按顺序执行,更常用】
在这里插入图片描述
script标签中defer和async的区别.png
<script> 标签中的 deferasync 属性都用于控制脚本的加载和执行方式,但它们之间有一些重要的区别:

  • async 属性

    • 当浏览器解析到带有 async 属性的 <script> 标签时,它会异步加载脚本文件,同时不会阻止页面的渲染和其他资源的加载。
    • 脚本加载完成后会立即执行,不管其他资源是否加载完成(哪怕html还在解析),也不会考虑脚本在页面中的顺序(多个脚本同时存在时,谁先加载完成谁先执行)。
    • 适用于独立的脚本,不依赖于其他脚本或页面内容的加载顺序。
  • defer 属性:(常用)

    • 当浏览器解析到带有 defer 属性的 <script> 标签时,它会继续渲染页面,同时异步加载脚本文件。脚本文件的加载不会阻止 HTML 解析和页面的渲染。
    • 脚本会按照它们在页面中出现的顺序依次执行(例如想要实现a.js->b.js->c.js)。即使脚本文件在 DOMContentLoaded 事件触发之前加载完毕,脚本的执行会被延迟到文档解析完毕。
    • 适用于需要等待整个文档解析完毕后再执行的脚本,避免阻塞页面渲染。

总结:

  • 如果脚本需要等待整个文档解析完毕,且依赖于文档的某些元素,可以使用 defer 属性。
  • 如果脚本是独立的,不依赖于其他资源或文档解析顺序,可以使用 async 属性。
  • 如果不使用 deferasync,则脚本会阻塞页面的渲染,直到脚本加载并执行完毕。

需要注意的是,deferasync 属性仅适用于外部脚本文件(使用 src 属性引入的脚本),对内联脚本无效。

闭包

因为全局变量容易污染环境,而局部变量又无法长期驻留内存于是我们需要一种机制,即能长期保存变量又不污染全局,这就是闭包

实现数据私有,使其成为全局变量,但是又不能被外部修改,只能调用包裹这个变量的函数引起变化

我们也可以使用闭包实现JS的模块化、函数柯里化、节流防抖

原型和原型链

原型链

遍历一个实例的属性时,先遍历实例对象上的属性,再遍历它的原型对象,一直遍历到Object

obj._proto_===Object.prototype

image.png
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JS继承的方式

  • 类继承
    在这里插入图片描述
  • 原型链继承
    在这里插入图片描述
  • 构造继承在这里插入图片描述
  • 组合继承:原型链 + 构造继承

在这里插入图片描述

  • 寄生组合继承:通过 Object.create() 方法来创建子类的原型对象,该原型对象的原型指向了父类的原型对象,从而实现了对父类原型属性和方法的继承,避免了调用父类构造函数两次的问题,提高了性能。
function Parent(name) {
    this.name = name;
}

Parent.prototype.sayName = function () {
    console.log('Parent name:', this.name);
};

function Child(name, age) {
    Parent.call(this.name); // 继承父类的属性
    this.age = age;
}

// 使用Object.create()创建一个临时的原型对象,并将其原型指向父类的原型对象
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // 修复constructor指向

Child.prototype.sayAge = function () {
    console.log('Child age:', this.age);
};

var child = new Child('John', 20);
child.sayName(); // 输出 "Parent name: John"
child.sayAge(); // 输出 "Child age: 20"

类、原型链、构造、组合、寄生组合继承的优缺点

  1. 类继承

    • 优点:
      • 易于理解和实现,符合面向对象的思想。
    • 缺点:
      • JavaScript 在 ES6 之前没有原生的类概念,需要通过函数和原型链来模拟类的实现。
      • 类继承受限于原型链的特性,可能会导致继承链过长、原型污染等问题。
  2. 原型链继承

    • 优点:
      • 简单易懂,易于实现。
    • 缺点:
      • 所有的实例对象共享同一个原型对象,可能会导致原型链过长、原型污染等问题。
      • 无法实现多继承。
  3. 构造继承

    • 优点:
      • 解决了原型链继承中的原型共享问题。
    • 缺点:
      • 无法继承父类原型链上的属性和方法。
      • 每个子类实例都会创建一份父类属性的副本,可能会浪费内存。
  4. 组合继承

    • 优点:
      • 结合了构造继承和原型链继承的优点,既可以继承父类的属性,又可以继承父类的原型链上的方法。
    • 缺点:
      • 调用了两次父类构造函数,可能会导致子类实例中存在重复的属性,造成内存浪费。
  5. 寄生组合继承

    • 优点:
      • 解决了组合继承中调用两次父类构造函数的问题,避免了内存浪费。
      • 子类的原型与父类的原型对象不同,不存在原型污染问题。
    • 缺点:
      • 实现相对复杂,需要使用 Object.create() 来创建临时的原型对象。

让事件实现先冒泡后捕获的效果

给同一个元素绑定两个 addEventListener
给第一个 addEventListener 设置成冒泡
给第二个 addEventListener 设置成捕获

mouseover、mouseout与mouseenter、mouseleave

  • mouseover、mouseout:当鼠标移入、移出元素或其子元素都会触发事件,所以有一个重复触发(冒泡)的过程
  • mouseenter、mouseleave:只有当鼠标移入、移出元素本身(不包含元素的子元素)会触发事件,也就是没有一个重复触发(冒泡)的过程

节流防抖

节流:一定时间只调用一次函数,常用于表单提交
在这里插入图片描述

防抖:多次操作变成一次,常用于搜索功能
在这里插入图片描述

数组Array

常用方法

reduce():累加
fiter():过滤,筛选满足条件的元素组成并【返回新数组】
map():通过对每个数组元素执行函数来创建新数组,【返回新数组】
forEach():遍历数组进行操作,【无返回值】
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

map()forEach()

共同点:

  1. 遍历数组并且不会改变原数组
  2. 执行匿名函数,this指向window对象
  3. 支持3个参数:item index array

不同点:

mapforEach
数组返回新数组对数组的每个元素进行操作
空数组返回空数组无操作,没有返回值(返回值为 undefined)
arr = [...new Set(arr)]; // 子项是简单类型
arr = [...new Set(arr.map(JSON.stringify))].map(JSON.parse); // 子项是复杂类型

检测类型

typeof demo === 'object' && demo !== null && demo.constructor === Array;
// 缺点:typeof 对于数组会返回 'object',而不是 'array'

demo.instanceof Array;
// 缺点:instanceof 只能用于判断对象类型,不能用于判断基本数据类型; 不能跨 iframe 检测对象

Object.prototype.toString.call(demo) === '[object Array]';
// 完美解决

fill():填充数组元素的值

new Array(24).fill("").map((item, index) => { return (index < 10 ? '0' + index : index) + ":00" });
// 生成24小时:["00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00"]

对象Object

常用方法

Object.keys():返回对象的【键】数组
Object.values() :返回对象的【值】数组
Object.entries():返回对象的【键值对】数组

for...in()for...of()

for...in()循环对象;for...of()循环数组

for...in

for...in 循环用于遍历对象的可枚举属性。它会迭代对象的所有可枚举属性,包括继承的属性。通常用于遍历对象的【键名】

const obj = { a: 1, b: 2, c: 3 };

for (let key in obj) {
  console.log(key); // 输出 'a', 'b', 'c'
  console.log(obj[key]); // 输出 1, 2, 3
}

需要注意的是,for...in 循环不保证属性的顺序,因为对象的属性没有固定的顺序。

for...of

for...of 循环用于遍历可迭代对象的元素,如数组、字符串、Set、Map 等。它遍历对象的可迭代【属性值】。

const arr = [1, 2, 3];

for (let value of arr) {
  console.log(value); // 输出 1, 2, 3
}

for...of 循环提供了一个简单、直观的方法来迭代数组和其他类似数组的对象。

总结一下,for...in 循环用于迭代对象的键名,而 for...of 循环用于迭代对象的属性值。

=====Object.is()

==会进行类型转换
===不会
Object.is()===类似,主要用于:

Object.is(NaN, NaN)=true
Object.is(-0, 0)=false
Object.is(-0, +0)=false

浅拷贝

  • ...
const obj1 = { name: "张三" }
const obj2 = { ...obj1 }
obj1.name = "李四"
console.log(obj1) // {name: "李四"}
console.log(obj2) // {name: "张三"}
  • Object.assign()
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const result = Object.assign(target, source);

console.log(target); // 输出: { a: 1, b: 4, c: 5 }
console.log(result); // 输出: { a: 1, b: 4, c: 5 }
  • contact(): 数组
const arr1 = [1, 2, 3, 4, 5]
const arr2 = arr1.concat()
arr1[0] = 99
console.log(arr1) // [99, 2, 3, 4, 5]
console.log(arr2) // [1, 2, 3, 4, 5]

深拷贝

  1. JSON.parse():JSON字符串转对象;JSON.stringify():对象转换为JSON字符串 (parse/pɑːrs/分析语句)
let cloneDemo=JSON.parse(JSON.stringify(demo)); ```

缺点:undefined、函数无法拷贝

  1. 递归+拷贝
// 定义一个函数 deepClone,用于深拷贝对象
function deepClone(obj) {
    // 如果传入的对象是 null 或者不是对象类型,则直接返回该对象,不需要进行拷贝
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    
    // 创建一个新的空对象,用于存储拷贝后的属性值
    var clone = Array.isArray(obj) ? [] : {}; // 判断传入的对象是数组还是普通对象,选择相应的初始化方式
    
    // 遍历传入对象的每一个属性
    for (var key in obj) {
        // 检查属性是否是对象自身的属性(而不是从原型链上继承来的)
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            // 递归调用 deepClone 方法,拷贝属性值并赋给新对象的相应属性
            clone[key] = deepClone(obj[key]);
        }
    }
    
    // 返回拷贝后的新对象
    return clone;
}

// 示例用法
let demo = { a: 1, b: { c: 2 } };
let cloneDemo = deepClone(demo);
  1. 使用第三方库
    lodash 的 _.cloneDeep

ES6

严格模式

严格模式.png

this 绑定的优先级

new > bind > call=apply > obj.func() > 默认绑定

this的指向

this指向
直接调用 fn()全局对象
objA调用objB.fn()objA对象
new调用:new method()新对象
call、apply、bind第一个参数

改变 this 指向

  1. 箭头函数
  2. new实例化对象
  3. call、apply、bind
let _this = this;

call、apply、bind

相同点:都是改变this指向

不同点:

  • call调用的是单个参数,apply调用的是参数数组
  • call、apply 是立即调用;bind 是返回对应函数,便于稍后调用

var let 区别

  • 全局污染
  • 变量提升
  • 重复声明
  • 块级作用域

new的执行过程 / 创建模拟对象

在内存中创建新的空对象
this 指向这个新对象
执行构造函数方法  给新对象添加属性方法
返回这个新对象

(因此构造函数无需 return )

function Demo1() {
    this.init = "a";
    return "A";
}
const demo1 = new Demo1();
console.log(demo1.init); // a

function Demo2() {
    this.init = "b";
    return { init: "B" };
}
const demo2 = new Demo2();
console.log(demo2.init); // B
// 如果构造函数返回一个对象,那么这个对象将作为 new 操作的结果。如果构造函数返回一个非对象类型的值(如字符串、数字等),那么这个返回值将被忽略,new 操作仍然会返回新创建的对象

普通函数和箭头函数

箭头函数(Arrow Functions)是 ES6 引入的一种新的‮数函‬语法,它提供‮一了‬种更简洁的‮式方‬来书‮函写‬数表达式。箭头函数和普‮函通‬数(Function Declarations/Expressions)在语法、this 绑定、构造函数能‮等力‬方面有‮些一‬不同。

  • 语法差异
  1. 函数声明 vs. 函数表达式:普通函数可以‮过通‬函数声明(function name() {})或‮数函‬表达式(var func = function() {})来创建,而箭头函数只‮是能‬表达式。
  2. 简洁性:箭头函数‮许允‬更简洁的语法,尤其是当‮数函‬只有一个‮数参‬和一个返回‮句语‬时,可以‮略省‬参数外的括号‮函和‬数体的大括号。
  3. 隐式返回:箭‮函头‬数在只有一条‮句语‬时,可以省略 return 关‮字键‬并隐式返回该‮句语‬的值。
  • this 绑定
  1. 普通函数:普‮函通‬数的 this 值在‮数函‬被调用时动态绑定,取决于调用‮下上‬文。在‮局全‬上下文中,this 指向全局对象(在‮览浏‬器中通常是 window)。
  2. 箭头函数:箭头函数没有自己的 this 绑定,它继‮自承‬父执行‮下上‬文中的 this 值。箭头函数的 this 在函‮定数‬义时‮经已‬确定,并且‮会不‬改变。
  • 构‮函造‬数能力
  1. 普通函数:可以作‮构为‬造函数使用 new 关键字来‮建创‬新的实例。构造函数内部‮常通‬会有一个 this 关键字,指向新‮建创‬的对象。
  2. 箭头函数:不能用作构造函数,尝试使用 new 关键字会抛出错误。箭头函数没有 this,也没有 prototype 属性。
  • 其‮差他‬异
  1. arguments 对象:普通‮数函‬内部有 arguments 对象,包含了函数调用‮传时‬入的‮有所‬参数。箭头‮数函‬没有 arguments 对象,但可‮使以‬用剩余参数(...rest)来获取所有‮入传‬参数。
  2. super 绑定:在 ES6 类的方法中,可以使用 super 关键字‮调来‬用父类的构‮函造‬数或方法。箭头函数也可以使用 super,但必须‮处是‬于对象字面量‮法方‬的简写形式中,或者是类中‮方的‬法。
  • 示例
    普通函数示例:
function add(a, b) {
  return a + b;
}```
箭头函数示例:
```javascript
const add = (a, b) => a + b;

在选择使‮箭用‬头函数还‮普是‬通函数时,需要考虑上‮差述‬异以及函数‮使的‬用场景。箭头函‮适数‬合用‮简于‬短的‮调回‬或函数式编程,而普通函数更‮合适‬需要复杂逻辑‮对或‬象方‮的法‬场景。

set map

在 JavaScript 中,SetMap 是 ES6 引入的两种新的数据结构,用于存储一组唯一的值或键值对。它们提供了高效的数据存储和检索操作,并且具有以下特点:

Set(集合):

  • Set 是一种类似于数组的数据结构,但其中的值都是唯一的,即不允许重复。
let demo=[1,2,2,3];
let demoSet=new Set(demo); // [1,2,3](但是不是数组,是类数组)
let demoSetNew=[...new Set(demo)]; //[1,2,3](借助了...实现转换成数组)
  • 你可以使用 new Set() 来创建一个空的 Set 对象,也可以在创建时传入一个可迭代的对象(如数组)来初始化 Set 对象。
  • Set 中的值可以是任意类型的 JavaScript 值,包括原始类型和对象引用。
  • Set 对象具有以下主要方法:
    • add(value):【增】向 Set 中添加一个新的值。
    • delete(value):【删】从 Set 中删除指定的值。
    • has(value):【查】检查 Set 中是否包含指定的值。
    • clear():【清】清空 Set 中的所有值。
  • Set 对象还具有 size 属性,用于获取 Set 中的值的数量。

Map(映射):

  • Map 是一种键值对的集合,类似于对象,但键可以是任意类型的值,而不仅限于字符串。
  • 你可以使用 new Map() 来创建一个空的 Map 对象,也可以在创建时传入一个可迭代的键值对数组来初始化 Map 对象。
  • Map 中的键值对可以是任意类型的 JavaScript 值,包括原始类型和对象引用。
  • Map 对象具有以下主要方法:
    • set(key, value):设置 Map 中指定键的值。
    • get(key):获取 Map 中指定键的值。
    • has(key):检查 Map 中是否包含指定的键。
    • delete(key):从 Map 中删除指定键及其对应的值。
    • clear():清空 Map 中的所有键值对。
  • Map 对象还具有 size 属性,用于获取 Map 中键值对的数量。

下面是一个简单的示例,演示了如何使用 SetMap

// 使用 Set 存储一组唯一的值
let uniqueValues = new Set();
uniqueValues.add(1);
uniqueValues.add(2);
uniqueValues.add(1); // 重复值不会被添加
console.log(uniqueValues.size); // 输出:2
console.log(uniqueValues.has(2)); // 输出:true

// 使用 Map 存储键值对
let keyValuePairs = new Map();
keyValuePairs.set('name', 'John');
keyValuePairs.set('age', 30);
console.log(keyValuePairs.get('name')); // 输出:'John'
console.log(keyValuePairs.has('age')); // 输出:true

SetMap 在 JavaScript 中提供了灵活且高效的数据结构,可以帮助你解决许多常见的问题,并且易于使用和理解。
在这里插入图片描述

Set的妙用

在这里插入图片描述

weakSet weakMap

在 JavaScript 中,WeakSetWeakMap 是 ES6 新增的两种集合类型,它们与 SetMap 类似,但具有一些不同的特性。它们主要用于存储对象引用,而且在某些情况下,不会阻止被引用对象的垃圾回收。

WeakSet:

  • WeakSet 是一种集合类型,其中的元素都是对象引用。
  • Set 不同的是,WeakSet 中的对象引用是弱引用,这意味着如果没有其他引用指向对象,对象可能会被垃圾回收,即使它存在于 WeakSet 中。
  • WeakSet 中的元素必须是对象,而且不能是原始值(如数字、字符串、布尔值等)。
  • WeakSet 没有 size 属性,也没有提供遍历的方法(如 forEachentries)。

WeakMap:

  • WeakMap 是一种键值对集合,其中的键必须是对象。
  • Map 不同的是,WeakMap 中的键是弱引用,这意味着如果没有其他引用指向键对象,键对象可能会被垃圾回收,即使它存在于 WeakMap 中。
  • WeakMap 中的值可以是任意类型,包括原始值和对象。
  • WeakMap 没有 size 属性,也没有提供遍历的方法(如 forEachentries)。

下面是一个简单的示例,演示了如何使用 WeakSetWeakMap

// 使用 WeakSet 存储对象引用
let weakSet = new WeakSet();
let obj1 = { name: 'John' };
let obj2 = { name: 'Jane' };
weakSet.add(obj1);
weakSet.add(obj2);
console.log(weakSet.has(obj1)); // 输出:true

// 使用 WeakMap 存储键值对,其中键是对象
let weakMap = new WeakMap();
let key1 = { id: 1 };
let key2 = { id: 2 };
weakMap.set(key1, 'value1');
weakMap.set(key2, 'value2');
console.log(weakMap.get(key1)); // 输出:'value1'

需要注意的是,由于 WeakSetWeakMap 中的对象引用是弱引用,因此它们并不适合用作普通集合类型。通常,它们主要用于特定的场景,如存储临时数据或实现对象私有属性等。在实际开发中,需要谨慎使用 WeakSetWeakMap,以避免可能的内存泄漏或意外行为。

Set、WeakSet、Map和WeakMap

Set:对象允许存储任何类型的唯一值,无论是原始值或者是对象引用

WeakSet:成员都是对象;成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏;

Map:本质上是键值对的集合,类似集合;可以遍历,方法很多,可以跟各种数据格式转换

WeakMap:只接受对象最为键名(null 除外),不接受其他类型的值作为键名;键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收, 此时键名是无效的;不能遍历,方法有 get、set、has、delete

SetWeakSetMapWeakMap
成员唯一、无序都是对象键值对的集合
能否遍历××

Promise

Promise.all

  • 返回所有 Promise(p1,p2,p3) 实例的新 Promise
  • 当所有 Promise 实例都变成 fulfilled 状态,新 Promise 的状态才是 fulfilled 状态,并且返回所有 promise 实例的 resolve value 数组
  • 如果有一个 Promise 实例状态是 rejected 状态,则新 Promise 的状态是 rejected,返回第一个 promise reject 的 reason

Promise.allSettled

  • 返回所有 Promise(p1,p2,p3) 实例的新 Promise
  • 返回所有 Promise 实例执行结果数组

Promise.race

返回 Promise(p1,p2,p3) 最先执行的 Promise 实例的 value 或者 reason,不论 fulfilledrejected 状态。

Promise.any

返回 Promise(p1,p2,p3) 状态最先变成的 fulfilled 实例的 value,如果 p1,p2,p3 最终状态都是 reject 则返回 All promises were rejected

importrequire

相同点:

  1. 用途:都用于导入(加载)其他模块的功能。

异点:

  1. 语法
  • import 是 ES6 模块系统中的语法,用于导入模块。
  • require 是 CommonJS 规范中的模块加载方法,通常在 Node.js 中使用,也可以用于浏览器端,但需要借助模块加载器(例如 RequireJS)。
  1. 加载方式
  • import 是静态加载,它会在代码解析阶段进行模块加载,因此不能动态使用变量或条件来决定加载哪个模块。
  • require 是动态加载,它可以根据条件或运行时的变量来决定加载哪个模块。
  1. 异步/同步
  • 在大多数情况下,import 是异步加载模块的,它返回一个 Promise 对象,支持异步加载模块。
  • require 在 Node.js 中是同步的,但在浏览器端(使用 RequireJS 等加载器)通常是异步的,能够异步加载模块。
  1. ES6 规范
  • import 是 ES6 中新增的模块系统语法,属于 ECMAScript 标准的一部分。
  • require 是 CommonJS 规范中定义的模块加载方式,是 Node.js 最早支持的模块加载方法,不属于 ECMAScript 标准。

虽然 importrequire 在导入模块时有不同的语法和加载方式,但它们的核心目的都是在 JavaScript 中实现模块化开发,方便代码组织和模块间的依赖管理。

新型技术

多线程

Web Workers

允许在后台线程中运行 JavaScript 代码,从而不影响主线程的性能

可以用来处理ajax返回的大批量数据,读取用户上传文件,计算MD5,更改canvas的位图的过滤,分析视频和声频文件等

// 线程JS
// 向 worker 发送消息
worker.postMessage('Hello, worker!');
// 主JS
// 创建一个新的 Worker 实例
let worker = new Worker('worker.js');
// 监听 worker 的消息
worker.onmessage = function(event) {
  console.log('Worker said: ', event.data); // Worker said: Hello, worker!
};

// 在 worker 中发送错误
worker.postMessage({error: 'An error occurred'});

// 在主线程中监听错误
worker.onerror = function(error) {
  console.error('Worker error:', error);
};

// 关闭 worker
worker.close();

webworker计算的时候用户切换页面了会怎么样

可能会暂停/终止/继续计算/数据丢失,取决于浏览器;所以可以在页面即将失去焦点时,使用worker.postMessage({command: 'pause'});通知 Web Worker 暂停计算,以及在页面重新获得焦点时使用worker.postMessage({command: 'resume'});通知 Worker 恢复计算

ES2020

||??

||在false、0、’ '(空字符串)、NaN、null、undefined会返回后面的值
??仅在null或undefined会返回后面的值

const value1 = false || 'default'; // value1 = 'default',因为false是假值
const value2 = 0 || 'default'; // value2 = 'default',因为0是假值
const value3 = null || 'default'; // value3 = 'default',因为null是假值
const value4 = undefined || 'default'; // value4 = 'default',因为undefined是假值

const value1 = false ?? 'default'; // value1 = false,因为false不是nullish(null或undefined)值
const value2 = 0 ?? 'default'; // value2 = 0,因为0不是nullish值
const value3 = null ?? 'default'; // value3 = 'default',因为null是nullish值
const value4 = undefined ?? 'default'; // value4 = 'default',因为undefined是nullish值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘泽宇Developer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值