JavaScript / ES6
Posted Silam Lin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript / ES6相关的知识,希望对你有一定的参考价值。
javascript / ES6
- -----------------数据类型---------------
- JavaScript的数据类型
- 为什么有BigInt
- 原始数据类型、引用数据类型
- undefined 与 null
- typeof 操作符
- instanceof 操作符
- 判断数据类型的方式
- 判断数组的方法
- 0.1 + 0.2 !== 0.3 的原因,如何解决?
- 安全地获得undefined值
- NaN
- isNaN 与 Number.isNaN
- ------------单个数据的类型转换---------------
- 将某个值转成Boolean
- 将某个值转成Number
- 将某个值转成String
- ToPrimitive 对象转成原始数据类型
- ------------多个数据的类型转换---------------
- x + y
- - * / 减乘除
- x == y
- ------------------- 其它操作符 -----------------
- && 与 || 操作符
- == 操作符、=== 操作符 与 Objece.is()
- ---------------- JavaScript 基础 -----------------
- new操作符的原理
- Object.assign和扩展运算符
- 深拷贝与浅拷贝
- DOM
- BOM
- 对AJAX的理解
- 封装一个AJAX
- Ajax,Axios,Fetch的区别
- 关注点分离原则
- 软件架构模式 MVC, MVP, MVVM **
- 延迟加载JavaScript脚本的方法
- 判断一个对象是否为空对象的方法
- 正则表达式
- 对JSON的理解
- use strict 严格模式
- 事件流
- 事件模型
- 事件委托
- preventDefault(),stopPropagation(),return false
- JavaScript 本地缓存 **
- ------------------- 关于数组 -----------------
- 数组的原生方法
- 数组的遍历方法
- for...in 和 for...of 的区别
- 数组去重
- 数组的乱序输出
- 数组的扁平化
- 数组元素求和
- 类数组对象
- 类数组对象如何转化为数组
- arguments
- -----------------原型与原型链-----------
- 原型链:__ proto __ 、prototype 、constructor
- -------声明变量、作用域链、闭包-----------
- 变量声明 var,let,const
- 变量提升、函数提升
- 作用域链
- 闭包
- ----------执行上下文与this的指向-----------
- 执行上下文
- 词法环境与变量环境
- this的指向规则
- -----------------ES6相关---------------
- let 、 const 、 var 的区别
- const声明的变量可以修改吗
- 箭头函数与普通函数的区别
- rest参数
- ES6的模板语法
- 解构赋值
- 尾调用优化
- Set
- Map 与 Object 的比较
- Map 与 WeakMap
- Symbol
- proxy
- Iterator 和 for...of 循环
- Generator
- Class
- Module
- ----------------面向对象编程---------------
- 对象的创建方式
- 对象的继承方式
- --------------异步编程/事件循环---------------
- 异步编程的实现方式
- 对Promise的理解
- Generator和yield
- 对async/await的理解
- setTimeout、setInterval、requestAnimationFrame
- 事件循环EventLoop
- Node的事件循环
- --------------垃圾回收/内存泄漏---------------
- 垃圾回收机制
- 内存泄漏
-----------------数据类型---------------
JavaScript的数据类型
JS共有八种数据类型:
- Undefined
- Null
- Boolean
- Number
- String
- Object
- Symbol(ES6新增)
- BigInt(ES6新增)
为什么有BigInt
- JavaScript中有Number.MAX_SAFE_INTEGER,表示最大安全数字,在这个范围内不会出现精度缺失的问题
- 但一旦超过这个范围,大数计算结果就不准确
- 因此提出了BigInt
原始数据类型、引用数据类型
原始数据类型有:
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
- BigInt
引用数据类型:
- Object 普通对象
- Array 数组
- Date 日期
- Function 函数
- Math 数学函数
- RegExp 正则对象
原始数据类型和引用数据类型的区别(存储的位置不同):
- 原始数据类型直接存在 栈Stack 中的,是占据空间小,大小固定,被频繁使用的简单数据段
- 引用数据类型是存储在 堆Heap 中的,是占据空间大,大小不固定的复杂对象。(引用数据类型是在栈中存储了指针,该指针指向堆中该数据实体的起始地址。)
堆与栈 —— 在数据结构中:
- 栈的存取方式是先进后出
- 堆是一个优先队列,按照优先级大小进行排序
堆与栈 —— 在操作系统中:
- 栈区内存 由编译器 自动 分配与释放
- 堆区内存 由开发者 手动 分配与释放
undefined 与 null
- Undefined与Null都是基本数据类型,它们都只有一个值,分别是undefined与null
- undefined表示的是未定义,即已声明但未初始化的变量保存的值就是undefined
- null表示的是空对象,意在保存对象却暂无真正保存对象的变量,应该让该变量保存null值;
- 声明但未初始化的变量(Undefined类型)使用typeof返回的是字符串’undefined’;
- 对Null类型使用typeof(typeof null)返回的是字符串‘object’,null实际上是空对象指针
- null == undefined 返回true
- null === undefined 返回false
typeof 操作符
typeof操作符的返回值(字符串):
- undefined(未定义的变量、声明但未初始化的变量)
- boolean(变量是Boolean类型)
- number(变量是Number类型)
- string(变量是String类型)
- object(变量是Object类型、数组、Null)
- function(若变量的值是函数)
注意:
- typeof对Undefined类型返回的是‘undefined’
- typeof对Null类型返回的是’object’,null是空对象指针
值得注意的是:未声明的变量只能进行typeof操作
instanceof 操作符
描述:A instanceof B,A对象是否为B构造函数的一个实例对象
- 判断当前实例对象A的原型链上能否找到B类型的原型对象
- 故要遍历实例A的原型链,若找到了B的原型对象,就返回true
- 否则返回false
function myInstanceof(a,b)
a = a._proto_; //起点设为实例a的原型对象
b = b.prototype; //b类型的原型对象
while(true)
if(!a)
return false;
if(a === b)
return true;
a = a._proto_; //若找不到,继续往上找
判断数据类型的方式
① typeof 的返回值(字符串)
- undefined(未定义的变量、声明但未初始化的变量)
- boolean(变量是Boolean类型)
- number(变量是Number类型)
- string(变量是String类型)
- object(变量是Object类型、数组、Null)
- function(若变量的值是函数)
缺点:
- Object对象、数组、Null都会返回字符串‘object’。这是typeof操作符不太准确的地方
② instanceof 操作符
A instanceof B, 即判断 A对象是否为B构造函数的一个实例对象
- 原理:判断某个对象实例A的原型链中是否能找到B类型构造函数的原型对象(是否存在构造函数的prototype属性)
缺点:
- instanceof 只能正确判断引用数据类型,不能判断基本数据类型
③ constructor
- 每一个函数都有prototype属性, 该属性是一个指针,指向原型对象
- 原型对象内有constructor属性,也是指针,指向prototype属性所在的函数;
- 函数的实例可以继承并获得原型对象的constructor属性,从而通过constructor去访问构造函数,因而可判断数据类型
缺点:
- prototype有可能被重写
④ Object.prototype.toString.call()
上面三种方法都各有缺点:
- typeof 操作符对于Object对象、数组、和Null都会返回object字符串
- instanceof 操作符只能判断引用数据类型,不能判断基本数据类型
- constructor会担心prototype被改写
所以最好用有一种是 Object.prototype.toString.call()
大多数对象的toString方法都是重写过的,所以使用Object原型对象上的toString方法,去判断类型。
也就是使用Object.prototype.toString.call()
console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call(name: "jerry"));//[object Object]
console.log(Object.prototype.toString.call(function()));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\\d/));//[object RegExp]
function Person();
console.log(Object.prototype.toString.call(new Person));//[object Object]
判断数组的方法
不可以使用typeof,会返回object
上一题的后三种方法都可以:instanceof,constructor,Object.prototype.toString.call()
- instanceof操作符 :obj instanceof Array;
- constructor
- Object.prototype.toString.call()方法
- 利用原型链 obj.__ proto __ === Array.prototype
- Array.prototype.isPrototypeOf(obj) 判断Array.prototype是否是obj的的原型对象
- ES6的方法:Array.isArray(obj)
0.1 + 0.2 !== 0.3 的原因,如何解决?
原因:
- 这是关于JavaScript数字运算的精度缺失问题
- 在JS中,浮点数是用64位固定长度来表示。其中1位符号位,11位指数位,52位尾数位。
- 0.1与0.2转为二进制形式后,是一个无限循环小数。然而只有52位去保存,所以会精度缺失。取出来后转为十进制就不是0.1和0.2了
方法一:利用ES6的Number.EPSILON
- ES6中提供了Number.EPSILON属性,值为2^(-52)。可以理解为机器精度,设置了允许误差范围
- 只需判断 0.1 + 0.2 - 0.3 < Number.EPSILON :若成立,则返回true,否则返回false
function test(a,b)
return Math.abs(a-b) < Number.EPSILON;
console.log(test(0.1+0.2,0.3)); // true
方法二:将浮点数化为整数
- 0.1 与 0.2 本身以二进制形式存储后,变成了无限循环小数
- 将其重新转化为整数,再进行计算
function test(a,b)
console.log((a*1000 + b*1000)/1000)); // 0.3
安全地获得undefined值
- undefined本身并非保留字,因此可能被用作变量或赋值
- 因此若后续需要用undefined作为判断条件,结果可能会受影响
- 可以通过void(0)获得纯正的undefined
NaN
定义:
- NaN 即 Not A Number,用于表示本应该返回数值的操作数却没有返回数值的情况
- 返回NaN,可以避免抛出错误,避免代码因此停止执行
特点:
- 包含NaN的任何操作数,都返回NaN
- NaN与任何值都不相等 (NaN == NaN // false;NaN !== NaN //true)
- typeof NaN 返回 ‘number’
isNaN 与 Number.isNaN
- isNaN()接收参数后,若不是数值,则会尝试将其转化为数值。无法转化成数值的参数则返回true,表示它 Not A Number
- Number.isNaN,会先判断参数是否为数字,是的话再进一步判断是否为NaN
- Number.isNaN 对于NaN的判断更加准确,因为会先判断是否为Number;isNaN可以接受任何类型的参数
------------单个数据的类型转换---------------
数据类型可以进行转换,转成Boolean类型、Number类型和String类型;
需要记住转换的方式和规则
将某个值转成Boolean
转成Boolean类型常见的有两种方式:
- !!value 即对值进行两次取反
- Boolean(value) 使用Boolean方法显示转换
假值列表
- undefined
- null
- false
- +0 , -0 , NaN
- “” (空字符串)
注意,属于假值列表内的值,转成Boolean结果都为false
也就是说,假值列表外的值,转为Boolean结果都为true
// 使用!!两次取反
console.log(!!undefined); // false
console.log(!!null); // false
console.log(!!false); // false
console.log(!!+0); // false
console.log(!!-0); // false
console.log(!!NaN);// false
console.log(!!""); // false
// 使用Boolean()方法显示转换
console.log(Boolean(undefined));
console.log(Boolean(null));
console.log(Boolean(false));
console.log(Boolean(+0));
console.log(Boolean(-0));
console.log(Boolean(NaN));
console.log(Boolean(""));
将某个值转成Number
转成Number类型常见有两种方式:
- +value
- Number(value)
基本的转换规则:
- Undefined类型的值:undefined是转成NaN
- Null类型的值:null是转成0
- Boolean的值:true转为1,false转为0
- String类型的值:如果字符串中只包含有效数字(包括浮点数、十六进制),则会忽略前导零输出十进制数值;如果字符串为空,则输出0;若字符串包含上述之外的字符,则输出NaN
- Symbol类型的不可以转成Number,会报错!!
// 基本转换规则
console.log(+undefined); // NaN
console.log(+null); // 0
console.log(+true); // 1
console.log(+false);// 0
console.log(+'123');// 123
console.log(+""); // 0
console.log(+"123x"); //NaN
// Symbol -> 报错
// 使用Number进行显示转换,结果相同
console.log(Number(undefined));
console.log(Number(null));
console.log(Number(true));
console.log(Number(false));
console.log(Number("123"));
console.log(Number(""))
console.log(Number("123x"))
Object类型 即引用数据类型转成Numberd的规则!!
- 数组只有一个元素,且为数字或者数字字符串,则转成对应的数字
- 空数组,转为0
- 日期Date也可以转成Number
- 其它情况都是NaN
注意:其实数组和对象转成数字类型,都会先转成原始数据类型,这个过程叫ToPrimitive,然后再按上面的规则转成数字
console.log(+[]); // 0
console.log(+[10]) // 10
console.log(+['10']) // 10
console.log(+new Date()) // 1644911468454
console.log(+[1,2]) // NaN
console.log(+[1,"2"]) // NaN
console.log(+) // NaN
还有两种不常用的,专门用于字符串转换
- parseInt()
- parseFloat()
parseInt()函数 – 专门转换字符串
- 忽略字符串前面的空格,直至找到第一个非空格字符;
- 若第一个非空格字符是数字字符,则会继续解析,直至解析完或遇到一个非数字字符
- 若第一个非空格字符不是数字字符或负号,则返回NaN
- 能识别各类进制,但最好提供基数作第二个参数表示进制类型
console.log(parseInt('AF',16)); // 正确识别是16进制数
console.log(parseInt('AF')); // 第一个非空格字符并非数字字符或负号,直接返回NaN
parseFloat函数 – 专门转换字符串
- 也是从第一个字符开始解析,直至解析完或遇到无效的浮点数字字符(第二个小数点无效)
- 始终忽略前导零,只解析十进制数(没有第二个参数指定基数)
- 十六进制格式的字符串始终会变成0;
将某个值转成String
转成String类型有两种方式
- “” + value,即value前加上 空字符串和加号
- String(value) 使用String方法显示转换
转换规则
- Undefined类型:undefined会转成’undefined’
- Null类型:null会转成’null’
- Boolean类型:true转成’true’,false转成’false’
- Number类型:直接转成数字字符串
引用数据类型
- 如果是空数组,转成空字符串 “”
- 如果是非空数组,则把数组中每一项拿出,并用逗号分隔,形成字符串
- 如果是对象,转成 ‘[object Object]’
console.log(''+undefined) // 'undefined'
console.log(''+null) // 'null'
console.log(''+true) // 'true'
console.log(''+false) // 'false'
console.log(''+111) // '111'
console.log(''+[]) // ''
console.log(''+[1,2,3]) // '1,2,3'
console.log(''+[1,2,'x']) // '1,2,x'
console.log(''+) // [object Object]
console.log(''+a:1) // [object Object]
ToPrimitive 对象转成原始数据类型
有时候我们要把引用数据类型,即对象或者数组[],转成原始数据类型
实际上就是调用了[[ToPrimitive]]
ToPrimitive(input,type)
如果input为Date对象,则type默认为String
其他情况下,type都认为是Number
当type是Number
- 会先调用valueOf方法,如果是原始值就返回结果
- 如果不是,进一步调用 toString方法,如果是原数组则返回
- 如果不是,抛出错误
当type是String
- 先调用toString方法,如果是原始值就返回结果
- 如果不是,进一步调用 valueOf方法,如果是原数组则返回
- 如果不是,抛出错误
------------多个数据的类型转换---------------
x + y
先判断x和y的成分,有如下四种情况。
- ① 如果有一方是String类型,则应该把另外一方转成String类型
- ② 如果一方是Number类型,另外一方是引用数据类型,双方都转为String类型,再拼接成一个String类型
- ③ 如果一方是Number,一方是原始数据类型,则应该把原始数据类型转换为Number类型
- ④ 有一方为NaN,则结果都为NaN
- ⑤ 都是Number,才进行单纯的加法
确定好情况,再根据单个数据的类型转换进行具体转换
情况①:一方为String,则将另外一方转为String
console.log('test' + undefined)
console.log('test' + null)
console.log('abc' + true)
console.log('abc' + false)
console.log('test' + 2022)
console.log('test' + [])
console.log('test' + [1,2,'a'])
console.log('test' + )
console.log('test' + a:1)
// 结果
testundefined
testnull
abctrue
abcfalse
test2022
test
test1,2,a
test[object Object]
test[object Object]
情况②:一方为Number,而另外一方是引用数据类型,都转成String
console.log(2022 + []);
console.log(2022 + [1,2,3])
console.log(2022 + )
console.log(2022 + a:1)
// 结果
2022
20221,2,3
2022[object Object]
2022[object Object]
情况③: 一方为Number,另外一方是基本数据类型,则将基本数据类型转成Number
console.log(2022 + undefined)
console.log(2022 + null)
console.log(2022 + true)
console.log(2022 + false)
// 结果
NaN
2022
2023
2022
undefined转为Number是NaN,相当于2022 + NaN,则输出NaN
null是转为0
true是转为1
false是转为0
空字符串转为0
纯数字字符串
题目
console.log( + 1);
- 一方是Number,一方是引用数据类型,都转成String类型
- .valueOf().toString() 得到 “[object Object]”
- 1得到 “1”
- 进行拼接,得到 “[object Object]1”
console.log([] + 1 )
- 一方是Number,一方引用数据类型,都转成String
- 1就得到’1’
- []调用[[ToPrimitive]],即 [].valueOf().toString()得到的是空字符串’’
- ‘’+’1‘
- ’1‘
console.log([1, 2, 3] + 0)
- 一方是Number,一方是引用数据类型,都转成String
- [1,2,3].valueOf().toString(),得到 ‘1,2,3’
- 0得到’0‘
- 进行拼接
- 得到 ’1,2,30‘
console.log(![] + [])
- 逻辑非运算优先级更高,所以先运算 ![]
- ![] 相当于 !Boolean([]),空数组不属于假值列表,返回true,再取反,得到 false
- 变成 false + []
- 右边的空数组是引用数据类型,调用primitive,转成字符串
- [].valueOf().toString(),得到的是空字符串“”
- false + “”
- 一方是字符串,所以把另外一方 false也转成字符串,得到 ‘false’
- ‘false’ + ‘’
- 所以是 ‘false’
console.log([] + )
console.log( + []);
- 两方都是引用数据类型,调用[[ToPrimitive]]
- .valueOf().toString(),得到的是 “[object Object]”
- [].valueOf().toString(),得到的是空字符串""
- 拼接
- 结果是 “[object Object]”
注意 + [] 有可能得到别的结果。前面的有可能被认作代码块,相当于是 +[],那么相当于是 Number([]),把空数组转成Number,得到0
console.log( + ) // '[object Object][object Object]'
console.log(你不知道的JavaScript上卷 - 读书笔记 - 第2章词法作用域-2.2 欺骗词法