常见数据类型
简述
JavaScript中的内置类型,七中类型中的又分为两大类:基本类型(值类型)和引用类型 基本类型有六种:null、number、string、undefined、boolean、symbol
引用类型:Object、Array等等。
所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。 变量会被赋予一个新值,而原值不能像数组、对象以及函数那样被改变。
基本类型 是储存在栈中 引用类型 引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,堆内存中的值地址引用保存在栈中,我们都是操作栈中的地址引用。
如果想看数据结构如堆、栈、链表等等,可以在本站搜索。
如下图所示:
如果不知道怎么判断数据类型的请看另一篇文章 JavaScript类型判断
基本类型
像基本类型如果String、Boolean、Number我们就不细写了,讲一下里面比较特殊的。如 null、undefined、NaN、symbol等等。
null
值null是一个字面量,他不像undefined是一个全局对象的一个属性。null是表示缺少的标识,知识变量未被指向任何对象,也可以看做是一个空指针对象。
如果我们在浏览器中赋值 null,他会报错如下:
// chrome Google Chrome 已是最新版本
// 版本 75.0.3770.100(正式版本) (64 位)
null = '111';
// Uncaught ReferenceError: Invalid left-hand side in assignment
undefined
undefined它是一个JavaScript基本类型。它也是一个全局的属性undefined表示undefined,undefined也可以表示一个被声明没有被赋值的变量。
| undefined 属性的属性特性: | |
|---|---|
| writable | false |
| enumerable | false |
| configurable | false |
在现代浏览器(JavaScript 1.8.5/Firefox 4+),自ECMAscript5标准以来undefined是一个不能被配置(non-configurable),不能被重写(non-writable)的属性。即便事实并非如此,也要避免去重写它。
如果我们在浏览器中赋值 undefined, 因为他的writable是为false,所以我们的赋值没有生效,如下所示:
// chrome Google Chrome 已是最新版本
// 版本 75.0.3770.100(正式版本) (64 位)
undefined = '111';
undefined === undefined; // true
NaN
全局属性 NaN 的值表示不是一个数字(Not-A-Number),NaN是一种特殊的Number类型.
NaN 属性的初始值就是 NaN,和 Number.NaN 的值一样。在现代浏览器中(ES5中),NaN 属性是一个不可配置(non-configurable),不可写(non-writable)的属性。但在ES3中,这个属性的值是可以被更改的,但是也应该避免覆盖。
| NaN 属性的属性特性: | |
|---|---|
| writable | false |
| enumerable | false |
| configurable | false |
如果我们在浏览器中赋值 NaN, 因为他的writable是为false,所以我们的赋值没有生效,如下所示:
// chrome Google Chrome 已是最新版本
// 版本 75.0.3770.100(正式版本) (64 位)
NaN = '111';
NaN === NaN; // false
判断NaN 我们必须使用 Number.isNaN() 或 isNaN() 函数和比较中不等于它自己来判断是否为NaN,为什么NaN不等于NaN自己,这是因为NaN它使表示一个集合
NaN == NaN; // false
NaN === NaN; // false
isNaN(NaN); // true
Number.isNaN(NaN); // true
symbol
这个技术术语页面同时描述了一种称为 “symbol” 的数据类型,还有一个像类的函数 “Symbol()”,用来创建 symbol 数据类型实例。
数据类型 “symbol” 是一种原始数据类型,该类型的性质在于这个类型的值可以用来创建匿名的对象属性。该数据类型通常被用作一个对象属性的键值——当你想让它是私有的时候。
Symbol 是 JavaScript 的 原始数据类型 ,Symbol实例是唯一且不可改变的.
符号类型是唯一的并且是不可修改的, 并且也可以用来作为Object的key的值(如下). 在某些语言当中也有类似的原子类型(Atoms).
我们只能通过Symbol('ssss')声明symbol,不能通过new声明Symbol.
引用类型
对象
在计算机科学中, 对象是指内存中的可以被 标识符引用的一块区域. 在 Javascript 里,对象可以被看作是一组属性的集合。用对象字面量语法来定义一个对象时,会自动初始化一组属性。 ECMAScript定义的对象中有两种属性:数据属性和访问器属性。
数据属性 数据属性的特性(Attributes of a data property)
| 特性 | 数据类型 | 描述 | 默认值 |
|---|---|---|---|
| [[Value]] | 任何Javascript类型 | 包含这个属性的数据值。 | undefined |
| [[Writable]] | Boolean | 如果该值为 false,则该属性的 [[Value]] 特性 不能被改变。 | true |
| [[Enumerable]] | Boolean | 如果该值为 true,则该属性可以用 for...in 循环来枚举。 | true |
| [[Configurable]] | Boolean | 如果该值为 false,则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。 | true |
还有一些过时的数据属性Read-only、DontEnum、DontDelete 访问器属性
| 特性 | 数据类型 | 描述 | 默认值 |
|---|---|---|---|
| [[Get]] | 函数对象或者 undefined | 该函数使用一个空的参数列表,能够在有权访问的情况下读取属性值。另见 get。 | undefined |
| [[Set]] | 函数对象或者 undefined | 该函数有一个参数,用来写入属性值,另见 set。 | undefined |
| [[Enumerable]] | Boolean | 如果该值为 true,则该属性可以用 for...in 循环来枚举。 | true |
| [[Configurable]] | Boolean | 如果该值为 false,则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。 | true |
- 注意:这些特性只有 JavaScript 引擎才用到,因此你不能直接访问它们。所以特性被放在两对方括号中,而不是一对。
"标准的" 对象, 和函数
对象 一个 Javascript 对象就是键和值之间的映射.。键是一个字符串(或者 Symbol) ,值可以是任意类型的值。 这使得对象非常符合 哈希表。 函数 函数是一个附带可被调用功能的常规对象。 日期 当你想要显示日期时,毋庸置疑,使用内建的 Date 对象。 数组和类型数组 数组是一种使用整数作为键(integer-key-ed)属性和长度(length)属性之间关联的常规对象。 Int8Array、Uint8Array、Uint8ClampedArray 、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array 键控集: Maps, Sets, WeakMaps, WeakSets Map, Set, WeakMap, WeakSet
动态类型
JavaScript是一种弱类型或者说动态语言。这意味着我们不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。
var one = 'one'; // one is a String now
one = 456; // one is a Number now
总结
JavaScript是一种弱类型或者说动态语言。 JavaScript中的内置类型,七中类型中的又分为两大类:基本类型(值类型)和引用类型
基本类型有六种:null、number、string、undefined、boolean、symbol 引用类型:object
所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。
基本类型 是储存在栈中
引用类型 引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,堆内存中的值地址引用保存在栈中,我们都是操作栈中的地址引用。
类型转换
简述
在JavaScript中关于类型转换的规则是非常混乱的,有强制转换(显示转换)、隐式转换,并且转换的规则没有完整可参考的文档,只有当时的提议书。并且在隐式转换的时候会出现很多不可思议的bug.
类型转换发生在静态类型的语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时(runtime);
我们先来解释显示转换再来隐式转换。 如果想了解javaScript中的类型,或者if运算符转换规则的知识可以看看我其他的博客。
显示转换
- ToString
- ToNumber
- ToBoolean
首先介绍显示转换中的基本类型互转,字符串、数字、布尔值、null、undefined之间的转换。
隐式转换
- ToPrimitive(转换为原始值)
- valueOf(返回指定对象的原始值)
- 运算符中的转换(+、-、*、/)
- ==
再来看一下ToPrimitive把对象转为原始值,当然也有Object.prototype.toString()的介绍,再试valueOf返回对象的原始值,再最后就是运算符在基本类型和object之间的运算,其中最坑的应该是==的隐士转换,因为他的左右规则不同,左右类型不同执行的又不同。
ToPrimitive的规则
我们要用到的ToPrimitive的规则,因为显示转换也会用到ToPrimitive的规则,如果还想所有的转换规则请看.ecma规则
ToPrimitive(转换为原始值)
ToPrimitive 运算符接受一个值,和一个可选的 期望类型作参数。
/**
* @params obj 要转换的对象 ,required
* @params type 期望转换为的原始数据类型,
*/
ToPrimitive(obj, type);
根据type的不同会他后面的步骤也不相同,如下所示
type为string
- 先调用obj的toString方法,如果返回原始值,则不往下执行,如果返回不是原始值,则执行第二步。
- 调用obj的valueOf方法,如果为原始值,则不往下执行,如果返回不是原值值,则执行第三步。
- 抛出TypeError异常
type为Number
- 先调用obj的valueOf方法,如果返回原始值,则不往下执行,如果返回不是原始值,则执行第二步。
- 调用obj的toString方法,如果为原始值,则不往下执行,如果返回不是原值值,则执行第三步。
- 抛出TypeError异常
type参数为空
- 该对象为
Date,则type被设置为String - 否则,type被设置为Number
这基本上就是object常用的转换的一些规则,在下面会验证ToPrimitive规则是否正确。
显示转换
我们先看一下基本类型之间的转换的图标如下:
| Null | Undefined | Boolean(true) | Boolean(false) | Number | String | |
|---|---|---|---|---|---|---|
| Boolean | false | false | - | - | (0/NAN)=>false OR true | ('')=>false OR true |
| Number | 0 | NaN | 1 | 0 | - | ('')=>false OR true |
| String | 'null' | 'undefined' | 'true' | 'false' | 'Number' | - |
我们下面一个一个说明ToString、ToNumber、ToBoolean的大致规则。
ToString
抽象操作ToString负责处理非字符串到字符串的强制类型转换。
验证一下上面表格中的转换规则,验证的时候加上object的转换验证,代码如下:
console.log(String(null)); // 'null'
console.log(String(undefined)); // 'undefined'
console.log(String(true)); // 'true'
console.log(String(false)); // 'false'
console.log(String(1)); // '1'
console.log(String(0)); // '0'
console.log(String(NaN)); // 'NaN'
console.log(String([1, 2, 3])); // '1,2,3' or [].toString()
console.log(String({a: 123})); // [object Object]
console.log(String(new Date())); // 'Sat Apr 20 2019 00:00:00 GMT+0800 (中国标准时间)'
上面的代码证明了我们上面table中的基本类型的·String·转换规则。
注意:对象这里要先转换为原始值,调用
ToPrimitive转换,type就指定为string了,继续回到ToPrimitive进行转换(看ToPrimitive)。
ToNumber
抽象操作ToNumber负责处理非Number到Number的强制类型转换。
验证一下上面表格中的转换规则,验证的时候加上object的转换验证,代码如下:
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number('1')); // 1
console.log(Number('0')); // 0
console.log(Number('abcd')); // 'NaN'
console.log(Number([1, 2, 3])); // NaN
console.log(Number({a: 123})); // NaN
console.log(Number(new Date())); // 1555689600000
上面的代码证明了我们上面table中的基本类型的Number转换规则。
注意:对象这里要先转换为原始值,调用
ToPrimitive转换,type就指定为number了,继续回到ToPrimitive进行转换(看ToPrimitive)。
ToBoolean
抽象操作ToBoolean负责处理非Boolean到Boolean的强制类型转换。
验证一下上面表格中的转换规则,验证的时候加上object的转换验证,代码如下:
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean('true')); // true
console.log(Boolean('false')); // true
console.log(Boolean('')); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean('abcd')); // true
console.log(Boolean([1, 2, 3])); // true
console.log(Boolean({a: 123})); // true
console.log(Boolean([])); // true
console.log(Boolean({})); // true
console.log(Boolean(new Date())); // 1555689600000
在表格上只有基本类型的转换为Boolean的规则,具体的转换规则为:
- false
- null
- undefined
- 空字符串' '
- 数字零 0
- NaN
只有上面的会转为false,其他的都会转为true.
他和if()条件运算符转换的规则基本上一至,请看if运算符转换。
隐士转换
在上面已经列出了ToPrimitive的常用的转换规则,在下面会验证上面的规则是否正确。最坑的也是规则对多的就是运算符的转换,可能现在只知道一部分,后面会慢慢补全。
ToPrimitive验证
Object转String规则验证 首先验证Obejct转换为String的规则,直接上代码。
var obj = {
toString: function () { console.log('toString'); return {}; },
valueOf: function () { console.log('valueOf'); return {};}
};
String(obj);
// 1. toString
// 2. valueOf
// Uncaught TypeError: Cannot convert object to primitive value
根据上面的输出结果,证明上面的String(),走了ToPrimitive(obj, string)的type为string的规则。详情见上面。
Object转Number规则验证 再验证Obejct转换为Number的规则,直接上代码。
var obj = {
toString: function () { console.log('toString'); return {}; },
valueOf: function () { console.log('valueOf'); return {};}
};
Number(obj);
// 1. valueOf
// 2. toString
// Uncaught TypeError: Cannot convert object to primitive value
根据上面的输出结果,证明上面的Number(),走了ToPrimitive(obj, number)的type为number的规则。详情见上面。
其他转变如数组转String或者Number 再验证Obejct转换为Number的规则,直接上代码。
var obj = {
toString: function () { console.log('toString'); return {}; },
valueOf: function () { console.log('valueOf'); return {};}
};
Number(obj);
// 1. valueOf
// 2. toString
// Uncaught TypeError: Cannot convert object to primitive value
根据上面的输出结果,证明上面的Number(),走了ToPrimitive(obj, number)的type为number的规则。详情见上面。
valueOf
JavaScript 调用 valueOf() 方法用来把对象转换成原始类型的值(数值、字符串和布尔值)。但是我们很少需要自己调用此函数,valueOf 方法一般都会被 JavaScript 自动调用。
String=> 返回字符串值Number=> 返回数字值Boolean=> 返回Boolean的this值Object=> 返回thisDate=> 返回一个数字,即时间值,字符串中内容是依赖于具体实现的
代码如下:
console.log('abc'.valueOf()); // 'abc'
console.log(Number(123).valueOf()); // 123
console.log(Boolean(true).valueOf()); // true
console.log({a: 123}.valueOf()) // {a: 123}
console.log(new Date()); // Sat Apr 20 2019 00:00:00 GMT+0800 (中国标准时间)
运算符中的转换(+、-、*、/)
在运算符中的转换又分为两种,自动转换为string类型、自动转换为number类型。
自动转换为string类型
在基础类型中,当一个值为字符串,另一个值非字符串,则后者转为字符串,当有一个是对象时,会走ToPrimitive(obj, number),ToPrimitive转换请看上面,下面看代码。
console.log('a' + 1); // 'a1'
console.log('a' + true); // 'atrue'
console.log('a' + false); // 'afalse'
console.log('a' + undefined); // 'aundefined'
console.log('a' + null); // 'anull'
console.log('a' + []); // 'a'
console.log('a' + {toString: function () { return '1' }}); // 'a1'
console.log('a' + {valueOf: function () { return 1 }}); // 'a1'
自动转换为number类型
加法运算符,如果没有一个为string类型的时候,都会优先转换为Number类型,如果有一个为object时,会走ToPrimitive(obj, number),ToPrimitive转换请看上面。一元运算符,也是需要注意。下面看代码。
console.log(true + false); // 1
console.log(true + null); // 1
console.log(true + undefined); // NaN
console.log(true + []); // ‘true’
console.log(true + null); // 1
console.log(true - false); // 1
console.log(true - true); // 0
console.log('1' - '0'); // 1
console.log('1' * 0); // 0
console.log('0' * 1); // 0
console.log('1' - '0'); // 1
console.log('abc' - 0); // NaN
console.log('abc' - '0'); // NaN
console.log(null - 0); // 0
console.log('1' - 0); //NaN
console.log(1 - {valueOf: function () { return 1 }}); // 0
console.log(1 - {valueOf: function () { return {} }, toString: function () { return 1 }}); // 0
// 一元运算符
console.log(+'abc'); // NaN
console.log(-'abc'); // NaN
console.log(+'1'); // 1
console.log(-'1'); // -1
console.log(+true); // 1
console.log(-false); // -0
console.log(+true); // 1
注意:null转为数值时为0,而undefined转为数值时为NaN
==
== 抽象相等比较与+运算符不同,不再是String优先,而是Nuber优先。假设左面为x、y为右面,大概的规则如下。
- 如果x,y都为number,直接比较
- 如果x为string,y为number,x转换为number比较,反则相反。
- 如果存在对象,通过ToPrimitive(obj, number)type为number进行转换,再进行比较。
- 如果x,y有一方存在boolean,按照ToNumber将boolean转换为1或0,再进行比较。
验证代码如下:
// x,y 都number 比较
console.log(1 == 2) // false
console.log(1 == 1) // true
// 一方为string一方为number
console.log('1' == 2) // false
console.log(1 == '1') // true
// 如果一方为 对象
console.log(null == 2) // false
console.log(1 == undefined) // false
// 因为对象的规则比较繁杂,如果普通对象[] 和 ![] 规则不同请看下面文章
// 存在 booelan
console.log(true == 0); // false
console.log(true == '0'); // false
console.log(false == '0'); // true
在这里就不多赘述了,看我另一篇文章 ![] == [],通过一道面试题。来讲解基本的转换规则,因为这个规则其实挺复杂的,一两句话讲不清楚。
总结
JavaScript中的类型转换基本上分为显示转换、隐式转换。
显示转换
ToStringToNumberToBoolean
隐式转换
ToPrimitive(转换为原始值)valueOf(返回指定对象的原始值)运算符中的转换(+、-、*、/)==
IF 转换规则
简介
在 JavaScript 中使用 if 的时候,自己如果不注意的话很可能出现判断进错,其实在 JavaScript 中只有固定的几个值会转为 false,其它的统一认为为 true。
- false
- null
- undefined
- 空字符串' '
- 数字零 0
- NaN
其他的全部都算为 true,'false'、'0'也是为 true,其实这也是一种隐性的类型转换。和 == 又有不同。
逻辑运算符
由于逻辑表达式是从左往右计算的,由于运算符优先级的存在,下面的表达式的结果却不相同。如下例所示
(false && true) || true; // 结果为 true
false && (true || true); // 结果为 false
右侧被小括号括起来的操作变成了独立的表达式。 转换规则:
- 将 AND 转换为 OR
- 将 OR 转换为 AND
- 删除嵌套的 AND
- 删除嵌套的 OR 可参考>developer.mozilla.org/zh-CN/docs/…
逻辑与(&&)
尽管 && 和 || 运算符能够使用非布尔值的操作数, 但它们依然被看作是布尔操作符,因为它们的返回值总是能够被转换为布尔值。
expr1 && expr2
如果expr1能转换为false则返回expr1,否则返回expr2。因此,与布尔值一起使用时,如果两个操作数都为true时&&返回true,否则返回false.
a1 = true && true; // t && t 结果为 true
a2 = true && false; // t && f 结果为 false
a3 = false && true; // f && t 结果为 false
a4 = false && 3 == 4; // f && f 结果为 false
a5 = "Cat" && "Dog"; // t && t 结果为 Dog
a6 = false && "Cat"; // f && t 结果为 false
a7 = "Cat" && false; // t && f 结果为 false
逻辑与(||)
expr1 && expr2 如果expr1能转换为true则返回expr1,否则返回expr2。因此,与布尔值一起使用时,如果任意一个操作数为true时||返回true.
o1 = true || true; // t || t 结果为 true
o2 = false || true; // f || t 结果为 true
o3 = true || false; // t || f 结果为 true
o4 = false || 3 == 4; // f || f 结果为 false
o5 = "Cat" || "Dog"; // t || t 结果为 Cat
o6 = false || "Cat"; // f || t 结果为 Cat
o7 = "Cat" || false; // t || f 结果为 Cat
逻辑非(!)
!expr 如果单个表达式能转换为true的话返回false,否则返回true。
n1 = !true; // !t 结果为 false
n2 = !false; // !f 结果为 true
n3 = !"Cat"; // !t 结果为 false
总结
在 JavaScript 中使用 if 的时候,自己如果不注意的话很可能出现判断进错,其实在 JavaScript 中只有固定的几个值会转为 false,其它的统一认为为 true。
- false
- null
- undefined
- 空字符串' '
- 数字零 0
- NaN
== 混乱的转换规则
简介
JavaScript 有两种比较方式:严格比较运算符和转换类型比较运算符。对于严格比较运算符(===)来说,仅当两个操作数的类型相同且值相等为 true,而对于被广泛使用的比较运算符(==)来说,会在进行比较之前,将两个操作数转换成相同的类型。
比较的特点:
- 对于两个拥有相同字符顺序,相同长度,并且每个字符的位置都匹配的字符串,应该使用严格比较运算符。
- 对于两个数值相同的数字应该使用严格比较运算符,NaN和任何值不相等,包括其自身,正数零等于负数零。
- 对于两个同为true或同为false的布尔操作数,应使用严格比较运算符。
- 不要使用严格比较运算符或比较运算符来比较两个不相等的对象。
- 当比较一个表达式和一个对象时,仅当两个操作数引用相同的对象(指针指向相同对象)。
- 对于Null 和 Undefined 类型而言,应使用严格比较运算符比较其自身,使用比较运算符进行互相比较。
一致/严格相等 (===)
一致运算符不会进行类型转换,仅当操作数严格相等时返回true
相等(==)
比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
非严格比较操作符 == 是会做强制类型转换的,那么根据 ECMA 262 它的规则是:
图1-1



图1-4

图1-5


[] == false or ![] == [] or ![] == false 为true
mdn运算符优先级参考表


==的优先级16 !的优先级10
[] == false 结果为 true
根据图1-1可知
- 第 7 条:If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
- 第 9 条:If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
所以 [] == false 的比较是对 x 执行 ToPrimitive(x),然后和 ToNumber(false) (为 0)进行比较。
看一下 ToPrimitive:
根据上图1-2、1-3、1-4的规则对于ToPrimitive([]),先执行[].valueOf(),返回result的是'[]',因为Type(result)是Object,所以继续执行[].toString(),返回””。
因此实际上最终是比较"" == 0,结果为true。
![] == [] 结果为 true
按照优先级,先执行 ![],根据规范,实际上是 !(ToBoolean([])):
根据上图1-5、1-6可看出,实际上 ToBoolean([]) 会return出true, ![] 就是 false.
[] 上文已经讲过了 是 ""。
所以对比就是 false == "",结果为true。
![] == false 结果为 true
按照优先级,先执行 ![],根据规范,实际上是 !(ToBoolean([])):
根据上图可看出,实际上 ToBoolean([]) 会return出true, ![] 就是 false.
false == false ,结果为true。
!![] == false 结果为 false
按照优先级,先执行 !![],根据规范,实际上是 !!(ToBoolean([])):
根据上图可看出,实际上 ToBoolean([])会return出true, !![] 就是 true.
true == false ,结果为 false。
总结
基本上一个对象转为原始值的大致过程再进行对比,如果不太清楚可以看另一篇博客JavaScript数据类型(二) 类型转换,但是在本篇博客中最重要的时ToBoolean([])的转换比较不容易理解。
常见的面试题
简述
在另一篇文章中有表述大致显示转化规则,隐式转换规则,着篇文章中会收集一些前端比较经典的关于类型转换的问题。下面就开始比较经典的面试题。
![] == []
这个题在另一篇面试中有记录过,![] == [].
(a == 1 && a == 2 && a == 3)
这个真的有很多种办法,这里只记录我知道的方法,如果有好的方法,请在下方留言,大家一起进步。 首先要知道==和===的区别。
==
宽松匹配 ==会先将左右两两边的值转化成相同的原始类型,然后再去比较他们是否相等。
===
他是不转化直接比较,如果类型不同直接就是false,如果类型相同,原始值相同就为true。
这里主要讲解(a == 1 && a == 2 && a == 3)相等的多种解法,如下:
- 重写
Object的valueOf - 重写
Object的toString - 重写
ToPrimitive,es6 smybol('') - 通过劫持 obj 的
getter方法 - 数组
join、shift - 字符串骚操作
重写 Object 的 valueOf、重写 Object 的 toString
重写代码的 valueOf 方法、和 toString 方法,如果不知道 ToPrimitive(obj, type)规则,请看ToPrimitive 规则我的另一篇博客。代码如下:
const a = { value: 0 };
a.valueOf = function() {
return (this.value += 1);
};
console.log(a == 1 && a == 2 && a == 3); // true
const a1 = { value: 0 };
a1.valueOf = function() {
return {};
};
a1.toString = function() {
return (this.value += 1);
};
console.log(a1 == 1 && a1 == 2 && a1 == 3); // true
重写 ToPrimitive,es6 smybol('')
在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为,得到我们想要的结果。看代码:
const a = { value: 0 };
a[Symbol.toPrimitive] = function() {
return (this.value += 1);
};
console.log(a == 1 && a == 2 && a == 3); // true
Obj.defineProperty
通过劫持对象的属性值的 getter 操作,让他累加来做到我们想要的。
var value = 0;
Object.defineProperty(window, "a", {
get: function() {
return (this.value += 1);
}
});
console.log(a == 1 && a == 2 && a == 3); // true
通过数组的方式实现
通过改变数组的 join 方法实现。
var a = [1, 2, 3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true
字符串的骚操作
通过定义变量是包含空格,实现视觉上的相等。
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
console.log(aᅠ == 1 && a == 2 && ᅠa == 3);
上面就是知道的可以让(aᅠ == 1 && a == 2 && ᅠa== 3 )的六种方法,如果还有后面会接着补充,下面来说一下(a === 1 && a === 2 && a === 3)。
(a === 1 && a === 2 && a === 3)
在上面介绍过==与===的区别, ===是不会进行类型转换的,所以==的很多规则并不适用,那只有劫持方法和字符串的操作可以实现,其他方法都不能实现。
Obj.defineProperty
通过劫持对象的属性值的 getter 操作,让他累加来做到我们想要的。
var value = 0;
Object.defineProperty(window, "a", {
get: function() {
return (this.value += 1);
}
});
console.log(a === 1 && a === 2 && a === 3); // true
字符串的骚操作
通过定义变量是包含空格,实现视觉上的相等。
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
console.log(aᅠ === 1 && a === 2 && ᅠa === 3);
未完待续。。。。如有经典试题可评论