likes
comments
collection
share

JavaScript强制类型转换、== 和 ===

作者站长头像
站长
· 阅读数 15

值类型转换

JavaScript值的强制类型转换总是返回基本类型值。如:字符串、数字和布尔值,不会返回对象和函数。如果被转换的值是对象,则进行抽象操作ToPrimitveToPrimitve 操作会首先检查是否有valueOf 方法,如有且返回基本类型的值,则使用该方法进行强制类型转换。如没有valueOf方法就调用toString的返回值来进行类型转换(前提是有toString方法)。

ToString、ToNumber、ToBoolean

转化为字符串
  • 1.1 其它类型的值转化为字符串的基本规则如下:
需要被转化的值转化为字符串
null"null"
undefined"undefined"
true"true"
false"false"
数字查看👇🏻备注
数组数组中的每一项转化为字符串,并通过,分隔符拼接在一起
对象(非数组)调用toString()方法

下面是一些常见的🌰

// 数组转化为字符串-1
var arr = [1,2,3];
var str = arr + '';
console.log('str: ', str);
// 控制台打印的值为 str:  1,2,3


// 数组转化为字符串-2
var arr1 = [{ name: 'ohYang', value: 1 },2,3];
var str1 = arr1 + '';
console.log('str1: ', str1);
// 控制台打印的值为 str1:  [object Object],2,3


// 非数组对象转化为字符串
var obj = { name: 'ohYang', value: 1 };
var str2 = obj + '';
console.log('str2: ', str2);
// 控制台打印的值为 str2:  [object Object]

备注:极大值和极小值数字使用指数形式转化为字符串显示;浮点数转化为字符串时,字符串在拼接的过程中会自动去除浮点数后面多余的0。

var numMax = 2 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000
numMax.toString(); // "2e21"

// 数字num转化为字符串,浮点数后面多余的零会被去除
var num = 10000.00
var numStr = num + '';
console.log(numStr)
// 控制太打印的值为:strNew:  1000 
  • 1.2 JSON字符串化 JSON字符串化,并非强制意义上的强制类型转换,但在大多情况下,也用到了toString()。能成功JSON字符串化的值,必须是安全的JSON值。

不安全的JSON值: undefinedfunctionsymbol循环引用(对象之间的互相引用,形成一个无限循环)。不安全的JSON值在进行JSON.stringify()操作中会忽略不安全的JSON值。基础类型的值只有undefined为不安全的JSON值

🌰 基础类型的值JSON值进行JSON.stringify()操作

/* 定义一个方法 */
function printJsonValue(val) {
    let jsonVal;
    jsonVal = JSON.stringify(val);
  	//第一个打印值,第二个打印的是第一个值的类型
    console.log(jsonVal, typeof jsonVal);
}
// undefined null true false NAN
printJsonValue(undefined); // 打印: undefined 'undefined'
printJsonValue(null); // 打印:null 'string'
printJsonValue(true); // 打印:true 'string'
printJsonValue(false); // 打印:false 'string'

// NaN JSON字符串化的结果是 'null'
printJsonValue(NaN); // 打印:null 'string'

🌰 对象(不含数组)中不安全JSON值进行JSON.stringify()操作

对象的属性所对应的值如果是undefined函数的时候,JSON.stringify()会忽略该部分,如下🌰所示

var obj = {
  a: null,
  b: undefined,
  c: false,
  d: 123,
  e: function() {}
}
vat jsonObj = JSON.string(obj);
// jsonObj的值如下:
// '{"a":null,"c":false,"d":123}'

像上🌰这种情况,对象的某些属性的值含有非安全的JSON值。如果还是需要对该对象进行JSON字符串化,需要在对象的内部定义一个toJSON方法。(注意:toJSON本身方法是返回一个安全的JSON值而不是JSON字符串)

let demo = {
	a: 'hello-world',
  b: undefined,
  c: function() {},
  // 返回一个安全的JSON值
  toJSON: function() { return this.a };
}
let jsonDemo = JSON.stringify(demo);
console.log('jsonDemo: ', jsonDemo);
// 打印结果:jsonDemo:  "hello-world"

🌰 _非空数组 _中不安全JSON值进行JSON.stringify()操作 :::warning 数组中非安全的JSON值会返回null,从而保证被该数组中的其它值的位置值不会因为非法的JSON值而改变 :::

var arr = [ null, undefined, false, 123, function() {} ]
var jsonArr = JSON.stringify(arr);
/* jsonArr的值如下:
	arr 中的非安全的JSON值如undefined、函数等会返回null
 '[null, null, false, 123, null]'
*/

注: 对象循环引用使用JSON.Stringify会报错 “TypeError: Converting circular structure to JSON”

var obj = { key: 'haha' };
var a = {
  key: 'hello world',
  x: obj,
  y: function() {}
};
obj.z = a;
JSON.stringify(a);
// 在浏览器的控制台输入上面的代码,并执行,会报出上文的错误
ToNumber

基本情况如下表格

被转化的值转化的结果
null0
undefinedNAN
true1
false0
NaNNaN
对象(包含数组)ToPrimitive操作,包含valueOf()toString()

注:如进行ToNumber操作,调用valueOf()toString()都无法最终得到基本类型的值,则会报错typeError

ToBoolean
  • 假值:nullundefinedfalse+0-0NAN'';
  • 真值:除假值之外的值都是真值(也就是除去上面的假值之外的值都是真值);

强制类型转换

转化为数字

常用方法如下:

// value 表示需要转化Number的值,
Number(value)
// 使用 + 转化为数字,可以简化代码。当然也可以使用 减号 - 、乘号 x、除号达到相同的目的
+value;

注:如果使用了+符号前置将一个值转化为Number,为了不让代码有歧义或是难以理解,不要与++--+=-=以及其他运算符号交织在一块使用。

var a = 10, b = '9', c = '8';
var d = a + +c; // 不建议使用这样写
var e1 = +c; var e2 =+ c; //  不建议,虽然得到的e1 e2的值都是Number
var f = a + ++e2; // 不建议

使用+加号运算符,可以将一些数字字符串转化为Number,例如上面代码中的示例

只有当x1 + x2都为数字的情况下,+作为加号运算符而非字符串拼接符。

var x = x1 + x2;

一些常见的坑(详细查看注释部分的文字说明)。

var x = [1] + [2];
// x 的最终值是 '12'

/* 上例 加号连接的两个值,遵循上面的规则,[1] [2]都是非Number类型的值,则 
	 + 就是字符串的拼接符,则必须把两个数字都转化为string然后再拼接
  (上例的数组最终转化为string先调用valueOf()再调用toString() 方法)
*/
{} + [];
/* 
	首先要明白 {} 放在语句的句首,是表示为这为一个『空的代码块』而非『空对象』。
	既然是空的代码块,就可以当成是不存在的部分,则 {} + []; 中的 + 运算符,则是把
	[]强制转化为number,等价于Number([])值为0;
*/

转化为字符串

常见的转化字符串的三种基本方式如下代码所示

// value 表示需要转化成字符串的值,
String(value);
value.toString();
// 实际中为了更方便快捷使用 value + ''来强制转化字符串
var targetStr = value + '';

value + ''以及String(value)都会把目标变量转化为字符串,但是两者之间还是有区别。前者的value会先调用内置的valueOf()方法、而后再调用内置的toString()方法。后者是直接调用内置的toString()方法。

/* 通过 +,将其它值强制显式转化为Number; */
var val = '100';
var valNum = +val;
// 等价于 Number(val)
var val1 = 199;
var sum = val1 + +val;
// 建议使用 Number(val) 代替 +val

上面的sum的值,可以很轻易的得出是299,但是如果当 + ,一元运算和其他运算符在同一个语句中使用,避免造成理解困扰,建议使用Number(value)代替

var x  = '10', d;
d = +x;

d的值是数字10,但是上面的写法似乎容易造成误解,毕竟很容易与d += xd -= x搞混,从而增加代码的理解难度。

使用+号连接字符串,是构成新的字符串较常用的方法,只要+连接的两个操作值不都为number,则+作为字符串拼接符号而非加号运算符;下面看一些例子 注:两个操作值之一或是同为null、undefined、false、true、NAN,不在本次的讨论范围

// 🌰1
var str = 'hello' + 'world';
// + 做为两个字符的拼接符

// 🌰2
[] + {};
// 结果是 '[object Object]'
/*
  🌰2 解析:
          + 左右的 []、{} 分别为数组和空对象
	  []: 调用valueOf(),然后再调用toString() 得到一个空的字符串
	  {}: 调用valueOf(),然后再调用toString() 得到一个字符串 '[object Object]'
	  所有最终的结果是'[object Object]'
*/
转化为布尔值

最常用的方式

// value 表示需要转化成布尔值的目标值,
Boolean(value);
// 实际中为了更便捷多使用 ! 取反符号、!! 两个取反符号 来强制转化成布尔值
var valueBoolA = !!value;
var valueBoolB = !value;

最常见用到布尔转换的是在条件判断语句中

  • if (conditiobn) { /* do something */}

括号内部内部的condition可以是变量也可以是表达式

if (condition) {
	console.log('print is true');
} else {
	console.log('print is false');
}

上面的代码括号内,虽然没有!!!Boolean(),但是被括号内的条件最终会被转化为布尔值来判断为true还是false

  • 三元运算符号
// 先把 condition 转化为布尔值,为真则执行 '?' 后面的语句,否则执行 ':' 后面的语句
let a = condition ? 'is true' : 'is false';

三元运算其实与if (condition) { /* do something */ } else { /* do something */ }本质在是一样的,只不过是书写形式上的差异。但是需要如果有下面的例子,则需要尽量避免(容易导致代码比较啰嗦)。

let a, b, value;
// if else 形式
if (condition) {
  a = true;
} else {
  a = false;
}
// 三元运算符形式
b = condition ? true : false;
// 以上两者方式都可以简写为下面的形式,避免弄得代码啰嗦
value = !!condition;
  • 其余常见的转化为布尔值的情况
let arr = [1, 2, 3];
/* for循环的第二个判断表达式 */
for (let i = 0, len = arr.length; i < len; i++) { /*  */}

/* while ()内的条件判断表达式*/
let i = 0,
    len = arr.length;
while (i < len) {
  let item = arr[i];
  console.log(i, item);
  i++;
}
/* do while, while括号内的条件表达式 */
do {
  let item = arr[i];
  console.log(i, item)
  i++;
} while (i < len);

宽松相等 == 与 严格相等 ===

首先需要了解的是,=====的区别。在以往对JS的认识中,以及一些博客文章中经常会看到这样的结论:“== 符号检查是否相等,而=== 符号会检查值以及类型是否相等”。

看一个🌰

var a =1,
    b = '1';
var isEqual = a == b;
var hasEqual = a === b;

易得出结果是: isEqual为truehasEqual为false,所以“==检查是否相等”这句话肯定是有问题的或者说表述的不够恰当与完整。 :::warning 1 == '1'一个数字和一个字符串之所以能相等(==),是因为**_==_**在比较时,a和b为不同类型的两个值,字符串**_b_**发生了类型转变,转变成了一个数字。而**_===_**进行比较时,不同类型的值比较不会发生类型转变。总结就是:**_==_**在进行比较的时候,会把其中的一个或是两个值强制转化为基本类型,再进行比较。 ::: 以下是使用宽松相等 == 比较常见的一些情况:

  • 字符串与数字直接 x == y

如果是xy一个是数字、另一个是字符串,则需要把字符串转化为数字,然后再进行类类型值的比较

  • 布尔值与其它值

看下面考察JS基础的面试题坑

var x = '2022', y = true, z = false;
var isEuqal = x == y;
var hasEqual = x == z;
// 不在浏览器控制台运行代码,判断isEqual的值,hasEqual的值,以及判断的理由

不要在控制台运行以上代码,推测一下结果。isEqual的值为falsehasEqual的值为false;是否感觉有点不符合逻辑,毕竟一个值如果不是真值,那必定是假值。剖析上面的代码:

最重要的一个前提:==进行两个不同类型的值进行比较的时候,如果其中一个为布尔值 ,布尔值会被强制转化为Number。 所有!!x 或是(Boolean(x))的结果不是真值就是假值,这个判断肯定是正确的。但是上面代码中的字符串xyxz最终的比较得出结果的为false,这是因为布尔值(y、z)被强制转化成数字,即是字符串x与数字进行比较==,最后按着上文字符串与数字进行==比较的方式处理

注: 如果进行比较相等比较的两个值,其中有一个为布尔值,则一定一定一定不能使用 ==,而需要用 ===代替。

  • nullundefined

nullundefined首先要记住一个点,在使用== 进行比较的时候 null等同与undefined,即是null == undefined为真,且nullundefined都与自身相等,且不等于(!=)其他类型的值。

下面判断一些常见类型的例子

null == undefined // true
null == null; // true
undefined == undefined; // true
undefined == ''; // false
undefined == false; // false
undefined == 0; // false
null == ''; // false
null == false; // false
null == 0; // flase

其他类型的值与进行 undefined或是null进行 ==比较的时候,不要凭直觉去推断该怎么进行值的类型转化,而需要记住这个特例**_null_****_undefined_**都与自身相等==,且互相相等==,且不等于(!=)其他类型的值

见识一下==让人迷惑的一些代码示例。

var bool1 = '0' == false; 
var bool2 = 0 == false;
var bool3 = false == '';
var bool4 = false == [];
var bool5 = '' == [];
var bool6 = '' == 0;
var bool6 = 0 == [];

一一来解释上面比较所的结果值,并及剖析原因:

  1. bool1的值为true==两边其中一个为布尔值,则布尔值false转化为Number 0,然后在 数字与字符串之间进行比较==;
  2. bool2的值为true==两边其中一个为布尔值,则布尔值false转化为Number 0,然后在 数字与同类型之间进行比较==;
  3. bool3的值为true==两边其中一个为布尔值,则布尔值false转化为Number 0,然后在 数字0与字符串0之间进行比较==;
  4. bool4的值为true==两边其中一个为布尔值,则布尔值false转化为Number 0,空数组[]与数字进行比较时,空数字会调用调用valueOf() 而后再调用toString()转化为基本类型''空字符串,然后在 数字0与空字符串``之间进行比较==;
  5. bool5的值为true,空数组[]与空字符串进行比较时,空数字会调用调用valueOf() 而后再调用toString()转化为基本类型''空字符串,然后字符串之间进行比较==;
  6. bool6的值为true,空字符串与数字0进行比较,首先空字符串会转化为数字0 ,然后数字之间进行比较==;
  7. bool7的值为true,空数组[]与数字0进行比较时,空数字会调用调用valueOf().toString()转化为基本类型''空字符串,然后字符串与数字0之间进行比较==;
转载自:https://juejin.cn/post/7280746697847259199
评论
请登录