JavaScript / ES6

Posted Silam Lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript / ES6相关的知识,希望对你有一定的参考价值。

javascript / ES6

-----------------数据类型---------------

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 欺骗词法

你不知道的JavaScript上卷 - 读书笔记 - 第2章词法作用域-2.2 欺骗词法

js中ES6语法的super到底是啥?

JavaScript 词法静态动态作用域初级理解

JS中的预编译(词法分析)阶段和执行阶段

ES6~ES13