Java教程

javascript基础问题整理(持续更新)

本文主要是介绍javascript基础问题整理(持续更新),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

      • 1.Number运算操作
      • 2.空位数组行为差异
      • 3.Object和Map的选择对比
        • 内存占用
        • 插入性能
        • 查找速度
        • 删除性能
      • 4.WeakMap特性
      • 5.可计算属性
      • 6.new.target
      • 7.作用域链相关
      • 8.dom元素事件阶段

1.Number运算操作

Javascript浮点值采用得是IEEE-754双精度标准模型。因此是占用8个字节的内存空间,因为设计精度问题,所以不能测试特定的浮点值,比如:0.1+0.2 != 0.3。具体的计算流程和原因可以参考这篇Number类型详解博客 。js高程第四版有说存储整形值比浮点值的内存空间减少一半,但javascript数值只有Number类型,并且Number类型遵循IEEE-754双精度标准。按理说不该有内存上的占用区别,此疑问留待解决。

2.空位数组行为差异

ES6新增的方法和迭代器与早期ECMAScript版本中存在的方法行为不同,导致对空位数组的处理行为不一致。ES6的新增方法会将空位元素当作undefine,ES6之前的方法会忽略空位。因此实践中避免使用数组空位。如果确实需要空位,采用显示设置undefine值代替。

3.Object和Map的选择对比

对于多数Web开发任务来说,选择Object还是Map只是个人偏好问题,影响不大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。

内存占用

Object和Map的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。不同浏览器的情况不同,但给定固定大小的内存,Map大约可以比Object多存储50%的键/值对。

插入性能

向Object和Map中插入新键/值对的消耗大致相当,不过插入Map在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操作,那么显然Map的性能更佳。

查找速度

与插入不同,从大型Object和Map中查找键/值对的性能差异极小,但如果只包含少量键/值对,则Object有时候速度更快。在把Object当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。这对Map来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择Object更好一些。

删除性能

使用delete删除Object属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为undefined或null。但很多时候,这都是一种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Map的delete()操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择Map。

4.WeakMap特性

weakMap只能使用对象作为"弱键",由于弱键的特性,当键值没有引用时,会被垃圾回收。"弱键"即便有引用,但引用在程序运行中不会被调用,也会被回收。

5.可计算属性

可计算属性,可以在对象字面量中完成动态属性赋值。中括号包围的对象属性键告诉运行时将其作为JavaScript表达式而不是字符串来求值:

const nameKey = 'name';
const ageKey = 'age';
const jobKey = 'job';

let person = {
  [nameKey]: 'Matt',
  [ageKey]: 27,
  [jobKey]: 'Software engineer'
};

6.new.target

抽象基类通过new.target可以实现。new.target保存通过new关键字调用的类或函数。通过在实例化时检测new.target是不是抽象基类,可以阻止对抽象基类的实例化:

// 抽象基类
class Vehicle {
  constructor() {
    console.log(new.target);
    if (new.target === Vehicle) {
      throw new Error('Vehicle cannot be directly instantiated');
    }
  }
}

// 派生类
class Bus extends Vehicle {}

new Bus();       // class Bus {}
new Vehicle();   // class Vehicle {}
// Error: Vehicle cannot be directly instantiated

7.作用域链相关

函数执行时,每个执行上下文中都会有一个包含其中变量的对象。全局上下文中的叫变量对象,它会在代码执行期间始终存在。而函数局部上下文中的叫活动对象,只在函数执行期间存在。定义函数时,就会为它创建作用域链,预装载全局变量对象,并保存在内部的[[Scope]]中。在调用这个函数时,会创建相应的执行上下文,然后通过复制函数的[[Scope]]来创建其作用域链。接着会创建函数的活动对象(用作变量对象)并将其推入作用域链的前端。作用域链越长,则查找变量所需的时间也越多。因此应该注意尽量减短作用域链的长度。

8.dom元素事件阶段

DOM事件流分为3个阶段:事件捕获、到达目标和事件冒泡。事件捕获最先发生,为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。大多数支持DOM事件流的浏览器实现了一个小小的拓展。虽然DOM2 Events规范明确捕获阶段不命中事件目标,但现代浏览器都会在捕获阶段在事件目标上触发事件。最终结果是在事件目标上有两个机会来处理事件。addEventListener方法的第三个参数Boolean值是指定事件注册的阶段,默认为false,注册到冒泡阶段,true注册到捕获阶段,一般都添加到冒泡阶段,除非事件需要拦截。

这篇关于javascript基础问题整理(持续更新)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!