「2024前端」常见面试题之JavaScript

1. 原型链和原型链的继承,前端的继承方式有哪些?

原型链和原型链的继承

在JavaScript中,原型链是实现继承的一种机制。每一个对象都有一个原型对象,从原型对象继承方法和属性。这些对象可以作为其他对象的原型,形成一个“原型链”。原型链的继承是通过将一个类型的实例设置为另一个构造函数的原型来实现的。

前端继承方式

  • 原型链继承: 如上所述。
  • 构造函数继承: 通过在子类构造函数中调用父类构造函数,可以继承父类的属性,但不继承父类原型上的属性。
  • 组合继承: 结合原型链继承和构造函数继承,既继承属性也继承方法。
  • 寄生组合继承: 最理想的继承方式,通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

2. 如何获得对象非原型链上的属性?

可以使用Object.hasOwnProperty()方法检查对象本身是否具有某个属性,而不是继承自其原型链。示例代码如下:

const obj = {ownProp: "this is an own property"
};console.log(obj.hasOwnProperty("ownProp"));  // 输出 true
console.log(obj.hasOwnProperty("toString")); // 输出 false,因为toString是继承自Object.prototype

3. ||&& 操作符的返回值?

  • || (逻辑或):返回第一个真值操作数,如果两者都是假值,则返回最后一个操作数。
  • && (逻辑与):返回第一个假值操作数,如果两者都是真值,则返回最后一个操作数。

4. 判断数据类型的方法都有哪些?

  • typeof 操作符:返回一个字符串,说明未经计算的操作数的类型。
  • instanceof 操作符:测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
  • Object.prototype.toString 方法:可以访问每个对象的 [[Class]],这是更准确的类型检测方法。

5. typeof 函数会返回什么?

typeof 操作符返回一个表示操作数类型的字符串。常见返回值有:“undefined”、“boolean”、“number”、“string”、“symbol”、“function” 和 “object”。

6. instanceof 可以判断基本类型吗?

不可以。instanceof 设计用于检查一个对象是否为一个构造函数的实例,它不适用于基本类型(如number、string 或 boolean)。

7. 如何判断数组类型?

可以使用Array.isArray()方法来判断一个变量是否为数组。这是一个简单且准确的方式来检测数组类型。

8. SessionStorage、localStorage 和 cookie

  • SessionStorage:存储在浏览器的会话(tab/window)中,当会话结束(页面关闭)时数据也被清除。
  • localStorage:同样存储在浏览器中,但数据可以长期存储,直到手动清除。
  • Cookie:存储在用户的计算机上,并且每次向同一服务器发送请求时,都会带上Cookie数据。它们通常用于持久化用户会话和存储用户偏好。

9. for in / for of 的区别

  • for in:循环遍历对象的所有可枚举属性(包括继承的属性)。
  • for of:提供遍历所有数据结构(如Array,Map,Set等)的值的方式,不包括对象,除非对象定义了迭代器。

10. JSONP的缺点

  • 安全风险:由于JSONP是通过<script>标签引入数据,可能会遇到跨站脚本(XSS)的安全问题。
  • 仅限GET请求:JSONP仅支持GET请求,不支持POST、PUT、DELETE等HTTP方法。
  • 错误处理不便:JSONP不支持错误处理,很难准确知道请求失败的情况。

11. new 操作符的过程

当你使用new操作符创建一个对象时,会发生以下几个步骤:

  1. 创建一个新的空对象。
  2. 将新对象的原型指向构造函数的原型对象。
  3. 将构造函数的this指向新对象,并执行构造函数代码。
  4. 如果构造函数返回一个对象,则返回该对象;否则返回刚创建的新对象。

12. 闭包及其问题

闭包是函数和声明该函数的词法环境的组合。闭包允许一个函数访问和操作函数外部的变量。闭包的常见问题包括:

  • 内存泄漏:闭包可以维持对外部变量的引用,这可能会导致内存不能被释放。
  • 性能问题:由于闭包需要维持更多的上下文信息,可能会导致相对较慢的执行速度和更多的内存使用。

13. Promise 和 allSettled 方法

  • Promise是异步编程的一种解决方案,代表一个可能在未来某个点完成的操作和它的结果。
  • Promise.allSettled方法接收一个Promise数组,返回一个Promise,该Promise在所有输入的Promise已经要么被兑现(resolved)要么被拒绝(rejected)后兑现,兑现的值是一个数组,每个数组元素表示对应的Promise的结果。

14. ES6 新特性和 const 定义的空数组是否能进行 push 操作

ES6引入了许多新特性,包括但不限于:

  • let和const关键字:提供块级作用域的变量声明方式。
  • 箭头函数
  • 模板字符串
  • 解构赋值
  • 类和继承
  • Promises
  • 模块化导入/导出
  • Symbol
  • Set和Map
  • 使用const定义的空数组是可以进行push操作的,因为const保证的是变量引用的不变性,而非值的不变性。

15. TypeScript 中 type 和 interface 的区别

  • Interface(接口) :主要用于定义对象的形状,支持扩展(extends)和实现(implements)。接口是开放的,可以在程序中多次声明同一个接口,TypeScript会将它们视为单个接口。
  • Type(类型别名) :可以用于对象类型,也可以用于其他类型(如基本类型、联合类型、交叉类型等)。类型别名不是开放的,不能像接口那样被扩展或实现。

16. TypeScript 中的枚举使用

TypeScript的枚举(Enum)是一种定义一组命名常量的方式。以下是一个基本的枚举使用示例:

enum Color {Red,Green,Blue
}
let c: Color = Color.Green;

17. TypeScript 泛型和 infer 关键字

  • 泛型:允许在定义函数、接口或类时不具体指定数据类型,使用时再指定类型。泛型提供了更大的灵活性和代码复用性。
  • infer 关键字:用在条件类型中,用于在条件类型的内部推断类型变量。

18. Websocket 的建立连接和优缺点

Websocket建立连接需要客户端发起一个特殊的HTTP请求,该请求包括一个Upgrade头部表示将HTTP升级到Websocket。连接建立后,客户端和服务器可以进行全双工通信。

  • 优点:允许服务器主动向客户端发送消息,适合需要频繁和实时交互的应用。
  • 缺点:在网络配置严格(如某些代理和防火墙配置)的环境下可能无法使用。

19. 前端路由实现和刷新404问题的处理

  • 前端路由:使用JavaScript来管理路由,不需要每次都从服务器加载新页面,常见的实现方式是利用hash(哈希)或history API(HTML5 历史API)。
  • 刷新404问题:可以通过服务器配置始终返回入口HTML文件(例如,使用单页应用时),或者使用hash模式,因为hash变化不会导致浏览器向服务器发起新的请求。

20. 捕获和冒泡事件的顺序

  • 捕获阶段:事件从文档根节点向下传递到目标元素。
  • 目标阶段:事件到达目标元素。
  • 冒泡阶段:事件从目标元素向上返回到文档的根节点。 在一般情况下,事件监听器是在冒泡阶段注册的,因为这样可以防止事件在到达目标之前被捕获阶段的祖先元素取消。

21. JavaScript 的变量提升

  • 变量提升(Hoisting) :在JavaScript中,变量和函数声明在编译阶段被放到它们各自作用域的顶部。这意味着可以在声明之前使用它们。变量提升可能导致理解上的困难和运行时错误,因为可能会误以为变量的作用范围是从它实际的代码位置开始的。

22. 观察者模式的实现

观察者模式是一种设计模式,允许多个对象监听某个对象的状态,以便在状态发生变化时得到通知。以下是一个简单的观察者模式实现示例:

class Subject {constructor() {this.observers = [];}subscribe(observer) {this.observers.push(observer);}unsubscribe(observer) {this.observers = this.observers.filter(obs => obs !== observer);}notify(data) {this.observers.forEach(observer => observer.update(data));}
}class Observer {update(data) {console.log("Observer received data:", data);}
}// 使用示例
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify("Hello Observers!");

此模式在JavaScript中的应用非常广泛,特别是在实现MVC或MVVM架构的框架中。

23. JavaScript中的面向对象实现

在JavaScript中,面向对象可以通过构造函数和类来实现。构造函数用于创建具有特定初始属性和方法的对象实例。ES6引入了类语法,使得面向对象编程更为直观和易于实现。

function Person(name) {this.name = name;
}
Person.prototype.sayHello = function() {console.log(`Hello, my name is ${this.name}`);
};const person1 = new Person("Alice");
person1.sayHello();// 使用ES6类
class Person {constructor(name) {this.name = name;}sayHello() {console.log(`Hello, my name is ${this.name}`);}
}const person2 = new Person("Bob");
person2.sayHello();

24. 移动端300ms延迟的原因及处理方法

移动端浏览器通常会有300ms的点击延迟,这是因为浏览器需要判断用户操作是单击还是双击。为了移除这个延迟,可以使用如FastClick库,或者通过设置CSS的touch-action属性为manipulation来禁用双击缩放,从而消除延迟。

25. 图片base64和外链的优缺点

  • Base64编码图片

    • 优点:减少HTTP请求次数,提高页面加载速度。
    • 缺点:编码后的字符串比原始二进制数据大约增加33%,增加页面大小,可能影响加载速度。
  • 外链图片

    • 优点:便于管理,可缓存,减轻服务器负担。
    • 缺点:增加HTTP请求次数,可能影响页面初始渲染速度。

26. 描述链表的反转实现及复杂度

链表反转可以通过迭代或递归完成。以下是迭代方法的实现,时间复杂度为O(n),空间复杂度为O(1):

function reverseLinkedList(head) {let prev = null;let current = head;while (current) {let next = current.next;current.next = prev;prev = current;current = next;}return prev;
}

27. Service Worker 的概念与应用

Service Worker是一种在Web浏览器后台运行的脚本,它能够拦截和处理网络请求,包括可编程地管理缓存中的资源。这使得它非常适合创建离线体验、发送推送通知和执行背景数据同步。

使用原理

  • Service Worker在独立于主网页的后台线程中运行,不会阻塞页面或影响页面性能。
  • 它通过监听和处理事件(如fetch, push, sync等)来实现功能。

应用场景

  • 离线应用支持:通过缓存关键资源来提供基本的离线浏览体验。
  • 网络请求拦截和管理:自定义响应网络请求的行为,如优先返回缓存内容,实现快速加载。

28. PWA (Progressive Web Apps)

PWA是一种通过适用现代Web技术来提供类似原生应用体验的Web应用。它的关键技术包括Service Worker、Manifest文件和响应式设计。

Service Worker的使用

// 注册Service Worker
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/sw.js').then(function(registration) {console.log('Service Worker registered with scope:', registration.scope);}).catch(function(error) {console.log('Service Worker registration failed:', error);});
}

29. 其他值到数字的转换规则

JavaScript在将非数字值转换为数字时遵循以下规则:

  • String:如果字符串是合法的数字文本,则转换为对应的数字,否则转换为NaN
  • Booleantrue转换为1false转换为0
  • Null:转换为0
  • Undefined:转换为NaN
  • Object:首先调用对象的valueOf()方法,如果返回的不是原始值,则调用toString()方法并根据上述规则转换返回的字符串。

30. 浏览器渲染过程

浏览器的渲染过程大致如下:

  1. 解析HTML:构建DOM树。
  2. 解析CSS:构建CSSOM树。
  3. 合并DOM树和CSSOM树:生成渲染树。
  4. 布局(Layout/Reflow) :计算出渲染树中每个节点的位置和大小。
  5. 绘制(Paint) :将渲染树的节点转换成屏幕上的实际像素。
  6. 合成(Composite) :将多层的图层合成为一层,以优化绘制效率。

31. 从输入URL到页面展示的过程

当你在浏览器地址栏输入URL并按下回车后,会经历以下步骤:

  1. DNS解析:将域名解析成IP地址。
  2. TCP连接:与服务器建立TCP连接。
  3. 发送HTTP请求:浏览器构建HTTP请求并发送到服务器。
  4. 服务器处理请求并返回HTTP响应
  5. 浏览器解析响应内容:解析HTML、CSS、JavaScript等。
  6. 渲染页面:按照上述浏览器渲染过程进行。
  7. 显示内容:在用户屏幕上展示最终内容。

32. 捕获和冒泡事件的具体序列

在浏览器的事件处理模型中,事件传递分为三个阶段:捕获阶段、目标阶段和冒泡阶段。详细说明如下:

  • 捕获阶段:事件从文档的根节点开始向下传递到目标元素,只有那些设置了监听器且addEventListener的第三个参数设置为true的元素才会在这个阶段捕获到事件。
  • 目标阶段:事件到达目标元素,无论事件监听器是在捕获阶段还是冒泡阶段注册,都会被触发。
  • 冒泡阶段:事件从目标元素开始向上冒泡到文档的根节点。默认情况下,事件监听器在此阶段被触发,除非addEventListener的第三个参数被显式设置为true

如果一个父元素和子元素同时注册了相同的事件(比如点击事件),且父元素在捕获阶段注册,子元素在冒泡阶段注册,那么事件触发的顺序将是:

  1. 父元素捕获阶段
  2. 子元素目标阶段
  3. 子元素冒泡阶段

33. 浏览器事件机制及e.targete.currentTarget的区别

  • 事件机制:包括事件捕获、目标处理和事件冒泡三个阶段,为了实现事件的全面控制和处理。
  • e.target:指向触发事件的元素,即事件实际发生的元素。
  • e.currentTarget:指向绑定事件监听器的元素,即当前通过事件传播处理事件的元素。

34. addEventListener的参数

addEventListener方法用来注册事件监听器,参数如下:

  • 第一个参数:事件类型(如"click", “load”, "input"等)。
  • 第二个参数:事件处理函数。
  • 第三个参数:可选,可以是布尔值或对象。布尔值决定监听器是在捕获阶段(true)还是冒泡阶段(false)触发;如果是对象,则可以设置如captureoncepassive等属性来详细控制监听器行为。

35. JavaScript的变量提升问题

变量提升是JavaScript中的一种机制,其中变量和函数声明在代码执行前被提升到它们所在作用域的顶部。这种行为可以导致:

  • 混淆:开发者可能会误认为未声明的变量可以使用,实际上在变量声明前使用这些变量会得到undefined
  • 错误:在函数或条件块中声明变量可能不会表现如预期,特别是使用var声明变量时,因为它会被提升至函数或全局作用域的顶部,而不是块级作用域。

36. this指向的代码示例和分析

在JavaScript中,this关键字的指向取决于函数的调用方式:

function show() {console.log(this);
}const obj = {show: show
};show();           // 全局对象(在浏览器中是`window`)
obj.show();       // 对象`obj`const newShow = obj.show;
newShow();        // 全局对象或undefined(在严格模式下)

在不同的调用环境下,this可以指向全局对象、当前对象、新创建的对象或严格模式下的undefined

37. 面向对象如何实现?需要复用的变量怎么处理?

面向对象的实现

在JavaScript中,面向对象编程(OOP)可以通过使用构造函数或类来实现。对象实例通常通过构造函数或类的new关键字来创建。例如:

class Person {constructor(name) {this.name = name;}greet() {console.log(`Hello, my name is ${this.name}`);}
}const alice = new Person("Alice");
alice.greet();

对于需要复用的变量,如果它们是不变的,可以考虑作为类的静态属性。如果变量会改变,但需要在实例之间共享,可以使用原型属性或通过外部作用域(如闭包)来维护这些变量。

38. ES6 Map 与 WeakMap 的区别

Map
  • Map对象保存键值对,并且记住了键的原始插入顺序。任何值(对象或原始值)都可以作为一个键或一个值。
  • 提供了常规的get(), set(), has(), delete()等方法,可以轻松地添加或删除键值对。
WeakMap
  • WeakMap对象是一组键/值对的集合,其中键是弱引用的对象,而值可以是任意的。
  • WeakMap中,每个键必须是一个对象,当对象的引用在外部消失,它们会自动从map中消失,有助于防止内存泄漏。
  • 不可枚举,这意味着无法获取大小,也不能清空所有元素,不支持forEach等方法。

39. Promise 的 resolve 和 reject

Promise是异步编程的一种解决方案。当你创建一个Promise时,需要提供一个执行器函数,这个函数接受两个参数,resolvereject

  • resolve:当异步操作成功时,我们调用resolve函数,这会将Promise状态从pending变为fulfilled
  • reject:当异步操作失败时,我们调用reject函数,这会将Promise状态从pending变为rejected

40. async 和 await 的使用以及错误捕获

使用方法

asyncawait是写异步代码的新方式,相比于之前的回调和Promise,它可以让异步代码看起来更像是同步代码:

async function fetchData() {try {const response = await fetch('https://api.example.com/data');const data = await response.json();console.log(data);} catch (error) {console.error('Error fetching data:', error);}
}
错误捕获

在使用asyncawait时,错误可以通过try...catch语句来捕获。await表达式可能会抛出异常,如果不捕获这些异常,会导致程序中断。

41. for…in, for…of, forEach 和 map 的终端控制

for…in 和 for…of
  • for..in主要用于遍历对象的键名。
  • for..of用于遍历具有迭代器特性的集合的值,如数组、Map等。
  • 这两种循环可以通过breakreturn在循环体内部直接终止。
forEach 和 map
  • forEach用于遍历数组,对每个元素执行回调函数,它没有内置的终止迭代的方法。
  • map类似于forEach,但它会返回一个新的数组,其中的元素是原始数组元素调用回调函数处理后的值。
  • 通常,forEachmap不能在中间通过break退出,但可以通过抛出异常等方式间接实现。

42. 扩展运算符 … 进行对象的拷贝是浅拷贝还是深拷贝?

扩展运算符...提供的是浅拷贝。当使用扩展运算符复制对象时,对象内部的属性只复制其引用值,所以如果属性值是复杂的数据结构,修改其中一个会影响另一个:

const obj1 = { a: { b: 1 } };
const obj2 = { ...obj1 };
obj2.a.b = 2;
console.log(obj1.a.b); // 输出 2

43. JavaScript中箭头函数与普通函数的区别

箭头函数是ES6中新增的一种函数声明方式,与传统的函数表达式相比,它们有几个主要的不同点:

  • 语法更简洁:箭头函数提供了更简短的语法。
  • 没有自己的this:箭头函数不绑定自己的thisthis值继承自外围最近一层非箭头函数的上下文。
  • 没有arguments对象:箭头函数内部没有arguments对象,如果要访问函数的参数列表,需要使用剩余参数(...args)。
  • 不能用作构造函数:箭头函数不能用作构造函数,使用new关键字调用会抛出错误。
  • 没有prototype属性:箭头函数本身没有prototype属性。
  • 不适合使用在对象字面量方法和事件处理函数中:由于this继承自外部,所以不适合用作对象的方法,或者DOM事件的回调函数。

44. Set 和 Map 的区别

SetMap都是ES6中新增的数据结构:

  • Set:是一种允许存储任何类型唯一值的集合,无论是原始值还是对象引用。
  • Map:是键值对的集合,但与对象不同,键的范围不限于字符串,可以包含任意数据类型。

区别:

  • Set主要用于数据的唯一性存储。
  • Map提供了更复杂的数据结构,可以将任意类型的键映射到任意类型的值。

45. ES6中Symbol的使用及应用场景

Symbol是ES6引入的一种新的原始数据类型,表示独一无二的值。最主要的用途是用来作为对象属性的键:

let sym = Symbol("key");
let obj = {[sym]: "value"
};
console.log(obj[sym]); // 输出"value"

应用场景:

  • 创建私有属性:因为Symbol值作为键不会被常规方法遍历到,所以可以用于对象的私有属性。
  • 防止属性名的冲突:如果使用第三方库,使用Symbol作为属性键可以防止与库内部可能存在的属性键冲突。

46. ES6 Proxy 和 Reflect 的使用场景

Proxy

  • Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,可以理解为在目标对象之前架设一层“拦截”。
  • 使用场景包括跟踪属性访问、属性验证、观察者模式等。
let handler = {get: function(target, name) {return name in target ? target[name] : 42;}
};let p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 输出1, 42

Reflect

  • Reflect是一个内置的对象,它提供拦截JavaScript操作的方法。这些方法与Proxy handlers的方法相同。
  • 使用场景主要是与Proxy一起使用,以简化自定义操作的实现。

47. Generator 函数的应用场景

Generator函数是一个状态机,封装了多个内部状态。执行Generator函数会返回一个遍历器对象,可以依次遍历Generator函数内部的每一个状态。

应用场景:

  • 异步操作的同步化表达:在异步操作中使用yield,使得异步代码看起来更像是同步代码。
  • 控制流管理:可以按部就班地执行代码,或者在特定的步骤中返回并稍后再从相同点继续执行。
  • 部分计算:生成器提供了一个强大的接口来控制函数的执行,可以按需执行计算。

48. async/await的实现原理

asyncawait是建立在Promise和生成器(Generator)之上的高级抽象,允许以更直观的方式处理异步操作。async函数的执行会返回一个Promise对象。当使用await时,函数执行会暂停,等待Promise解决。从实现的角度来看,async/await可以看作是Generator函数的语法糖。

49. ES6中Map与WeakMap的详细区别

除了之前提到的一些基本区别,这里补充一些更深入的细节:

  • 垃圾回收:在WeakMap中,键是对对象的弱引用,意味着如果没有其他引用指向键所对应的对象,这些键值对会被垃圾回收。相反,Map中的键则强引用其内容。

  • 可枚举性Map的键值对是可枚举的,可以通过.keys(), .values(), 和 .entries()方法获得迭代器。WeakMap不支持迭代和清除所有内容,没有这些方法。

  • 使用场景

    • Map适合需要主动枚举其键值对的场景,例如实现缓存或对象映射。
    • WeakMap适合管理没有明确生命周期的对象的私有数据,避免内存泄漏,例如在类中存储私有数据。

50. async和await的错误捕获细节

使用asyncawait时,错误捕获通常通过try...catch块来实现。这与使用传统的Promise链中的.catch()方法类似,但语法更接近同步代码的错误处理方式。例如:

async function fetchData(url) {try {const response = await fetch(url);const data = await response.json();return data;} catch (error) {console.error('An error occurred:', error);throw error;  // 可以重新抛出错误,如果你想让调用者也能处理这个错误}
}

51. JavaScript中的深拷贝与浅拷贝

  • 浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此原始对象与拷贝对象会引用同一个对象。
  • 深拷贝:将一个对象从内到外完整地复制一份,原始对象和副本的引用类型属性指向的是完全不同的两个对象。实现深拷贝可以使用JSON.parse(JSON.stringify(object)),但这种方法不能复制函数和原型链,也不能处理循环引用的对象。

52. 使用ES6 Proxy进行状态管理

Proxy可以非常方便地用于前端状态管理,比如在一个框架中跟踪状态的变化来自动更新UI。这可以通过拦截设置属性的操作并在属性值变化时通知视图层来实现。示例代码:

function updateComponent() {console.log('Component updated!');
}const state = new Proxy({ name: 'Alice' }, {set(target, property, value) {target[property] = value;updateComponent();  // 更新UI的函数return true;}
});state.name = 'Bob';  // 设置属性时自动触发组件更新

53. JavaScript的模块化:CommonJS与ES6模块的区别

  • CommonJS:主要用于服务器端,如Node.js,通过require来加载模块,通过module.exports来导出模块。加载是同步的。
  • ES6模块:设计用于浏览器和服务器端,使用importexport语句来导入和导出模块。支持静态和动态导入,并且导入是异步的。

54. JavaScript中的观察者模式和发布-订阅模式

  • 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 发布-订阅模式:通过一个中介者(通常是事件通道或事件总线)来管理事件和订阅者之间的关系,发布者发布事件到事件通道,而不是直接通知订阅者。

55. JavaScript中的装饰器模式

装饰器(Decorator)模式是一种结构型设计模式,它允许通过将对象放入包含行为的特殊封装对象中来动态地添加新功能。在JavaScript中,装饰器通常实现为高阶函数,返回一个包装了原始函数的新函数,能够执行额外的功能。

function readOnly(target, key, descriptor) {descriptor.writable = false;return descriptor;
}class Job {@readOnlytitle() {return 'Developer';}
}

注意:装饰器目前是一个实验性功能,需要在Babel等编译器中启用相应插件。

56. JavaScript的内存管理

JavaScript的内存管理主要是通过垃圾回收机制自动完成的。主要的垃圾回收算法包括标记清除(Mark-and-Sweep)和引用计数。标记清除是最常用的垃圾回收方法,工作原理是标记活动对象然后清除那些未被标记的对象。引用计数跟踪每个值被引用的次数,当引用次数降到零时,释放内存。

57. JavaScript执行上下文和作用域链

执行上下文是当前JavaScript代码被评估和执行时的环境。每次函数被调用时,就会创建一个新的执行上下文,包括绑定其所需的变量、函数声明、this的值等。

作用域链是由当前执行上下文中可访问的作用域组成的列表,它确保了对执行上下文有效的变量和函数的有序访问。当代码需要访问一个变量时,JavaScript引擎会首先查找当前执行上下文的变量对象,如果没有找到,就会沿着作用域链向上查找。

58. JavaScript异步编程的演进

JavaScript的异步编程已经从简单的回调函数发展到更加复杂的Promise和异步函数(async/await)。这个演变提高了代码的可读性和错误处理能力。

  • 回调函数:最初的异步编程模式,容易导致回调地狱。
  • Promise:提供了更好的错误处理机制和链式调用方式。
  • Async/Await:使异步代码看起来更像同步代码,提高了代码的可读性。

59. JavaScript模块加载器和工具

随着前端应用变得越来越复杂,模块加载器和构建工具变得至关重要。它们帮助组织和管理JavaScript代码和资源,优化加载时间。

  • 模块加载器(如RequireJS,SystemJS):动态加载模块,支持代码拆分,按需加载。
  • 构建工具(如Webpack,Rollup):分析项目结构,打包资源,优化代码,提高性能。

60. Web性能优化策略

优化Web应用的性能是一个持续的过程,包括多种技术和策略:

  • 代码拆分:使用如Webpack这样的模块打包器来实现代码拆分,按需加载。
  • 资源压缩和合并:减少HTTP请求的数量和大小。
  • 使用缓存策略:利用浏览器缓存,减少资源重复加载。
  • 延迟加载和预加载:优化资源加载策略,改善用户体验。
  • 服务端渲染(SSR) :提高首次加载性能和SEO。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/823263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python文件操作大全

1 文件操作 1.1 文件打开与关闭 1.1.1 打开文件 在Python中&#xff0c;你可以使用 open() 函数来打开文件。以下是一个简单的例子&#xff1a; # 打开文件&#xff08;默认为只读模式&#xff09; file_path example.txt with open(file_path, r) as file:# 执行文件操作…

LeetCode-二叉树修剪

每日一题 今天遇到的题比较简单&#xff0c;是一道二叉树的题。 题目要求 给定一个二叉树 根节点 root &#xff0c;树的每个节点的值要么是 0&#xff0c;要么是 1。请剪除该二叉树中所有节点的值为 0 的子树。 节点 node 的子树为 node 本身&#xff0c;以及所有 node 的…

appium2报错:Failed to create session. ‘automationName‘ can‘t be blank

1、问题概述&#xff1f; 今天在window环境中安装了appium2.5.2版本&#xff0c;通过appium inspector连接真机的时候报错如下&#xff1a; Failed to create session. automationName cant be blank 原因分析&#xff1a;这是因为appium2的比appium1有了很大的改进&#xff…

Linux 指令之文件

1.开发背景 记录 linux 下对文件操作的指令 2.开发需求 记录常用的文件操作指令 3.开发环境 linux 操作系统&#xff0c;如果不支持需要查看是否存在对应的可执行文件 4.实现步骤 4.1 查找字符串 查找指定目录下包含指定的字符串 grep -rn "Timer frequency" .…

python中如何求阶乘

第一种、利用functools工具处理 import functools result (lambda k: functools.reduce(int.__mul__, range(1, k 1), 1))(5) print(result)第二种、普通的循环 x 1 y int(input("请输入要计算的数:")) for i in range(1, y 1):x x * i print(x) 第三种、利用…

美格智能出席紫光展锐第三届泛金融支付生态论坛,引领智慧金融变革向新

4月16日&#xff0c;以“融智创新&#xff0c;共塑支付产业新生态”为主题的紫光展锐第三届泛金融支付生态论坛在福州举办&#xff0c;来自金融服务机构、分析师机构、终端厂商、模组厂商等行业各领域生态伙伴汇聚一堂&#xff0c;探讨金融支付产业的机遇与挑战。作为紫光展锐重…

浮点数的存储方式、bf16和fp16的区别

目录 1. 小数的二进制转换2. 浮点数的二进制转换3. 浮点数的存储3.1 以fp32为例3.2 规约形式与非规约形式 4. 各种类型的浮点数5. BF16和FP16的区别Ref 1. 小数的二进制转换 十进制小数转换成二进制小数采用「乘2取整&#xff0c;顺序排列」法。具体做法是&#xff1a;用 2 2…

数据结构复杂度

算法的时间复杂度 常对幂指阶 小练习1 小练习2

【实战】Dubbo应用可观测性升级指南与踩坑记录

应用从dubbo-3.1.*升级到dubbo-*:3.2.*最新稳定版本&#xff0c;提升dubbo应用的可观测性和度量数据准确性。 1. dubbo版本发布说明(可不关注) dubbo版本发布 https://github.com/apache/dubbo/releases 【升级兼容性】3.1 升级到 3.2 2. 应用修改点 注意&#xff1a;Sprin…

qutip,一个高级的 Python 量子力学研究库!

目录 前言 安装 特性 基本功能 量子态的创建和操作 量子态的测量 示例代码 动力学模拟 高级功能 退相干和噪声模拟 控制和优化 量子信息学工具 实际应用场景 量子态演化研究 量子计算机模拟 量子纠错协议 总结 前言 大家好&#xff0c;今天为大家分享一个高级的 Pytho…

机器学习理论入门---线性回归从理论到实践

线性回归是机器学习里面最简单也是最常用的算法&#xff0c;理解了线性回归的推导之后对于后续的学习有很大帮助&#xff0c;所以我决定从这里开始深入学习相关的机器学习模型。 本篇首先从矩阵求导开始切入&#xff0c;然后介绍一次线性回归的推导&#xff0c;再到代码实现。本…

酒店餐厅装水离子雾化壁炉前和装后对比

酒店餐厅装水离子雾化壁炉前和装后的对比可以体现出餐厅氛围和客户体验的显著改变&#xff1a; 装前&#xff1a; 普通的氛围&#xff1a;餐厅可能显得比较普通&#xff0c;缺乏特色或独特的装饰元素。 视觉上缺乏焦点&#xff1a;餐厅空间可能显得相对平淡&#xff0c;缺乏…

压缩感知(ISTA-Net论文)学习笔记

压缩感知&#xff08;ISTA-Net论文&#xff09;学习笔记 第一天&#xff0c;主要查找相关视频和笔记&#xff0c;补全预备知识 【nabla算子】与梯度、散度、旋度_哔哩哔哩_bilibili 近端梯度(Proximal Gradient)下降算法的过程以及理解|ISTA算法|LASSO问题_哔哩哔哩_bilibil…

华为ensp中静态路由和默认路由的原理及配置

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月17日17点37分 默认路由 [Router] ip route-static <目的网络> <目的网络掩码> <下一跳地址>默认路由的作用是将无法匹配路由表中其他路由表项的…

【行业前沿】制造业的数字化转型如何做?

随着科技的迅速发展&#xff0c;数字化转型已经成为制造型企业提高竞争力的关键因素。它可以帮助制造型企业&#xff0c;在产品优化设计、材料采购、生产流程方面实现精细化管理&#xff1b;提升上下游协同生产能力&#xff0c;提高生产效率、降低生产成本、优化产品质量&#…

RUM 最佳实践-视觉稳定性的探索与实践

写在前面的话 在当今数字时代&#xff0c;网页的视觉稳定性对于提供良好的用户体验至关重要。其中一个衡量视觉稳定性的关键指标就是累积布局偏移&#xff08;Cumulative Layout Shift&#xff0c;简称 CLS&#xff09;。CLS 作为 Web Vitals 指标之一&#xff0c;它衡量的是网…

jql联表查询涉及到权限的最好用上临时表

JQL联表查询的两种方法 联表查询 为方便文档描述定义以下两个概念&#xff1a; 临时表&#xff1a;getTemp方法返回的结果&#xff0c;例&#xff1a;const article db.collection(article).getTemp()&#xff0c;此处 article 就是一个临时表虚拟联表&#xff1a;主表与副…

【MySQL数据库】 (篇一 ) 让你快速上手——新手速通版

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、如何起步&#xff1f;&#x1f3c3;‍1.创建数据库&#xff1a;2.选择数据库&#xff1a;3.删除数据库&#xff1a;4.创建表&#xff1a;5.删除表&#xff…

48.基于SpringBoot + Vue实现的前后端分离-雪具销售系统(项目 + 论文PPT)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的雪具销售系统设计与实现管理工作系统…

Linux的学习之路:12、地址空间(续)与进程的创建、终止和等待

摘要 本章将讲述上章没说的一些东西以及进程创建终止与等待 目录 摘要 一、地址空间&#xff08;续&#xff09; 二、创建 三、终止 四、等待 五、思维导图 一、地址空间&#xff08;续&#xff09; 上篇文章中介绍了地址空间&#xff0c;但是没有说为什么会有地址空间…