数据类型的转换/判断/比较

这篇博客主要包括数据类型深拷贝&浅拷贝数据类型的转换toString()方法判断数据相等与全等的区别。若有错误,欢迎指正。javascript

由于上次金山面试问了巨多这一块的内容,因此作个总结,零碎的知识点不少。这篇原本是上周先发在掘金的,可是掘金的排版器没有思否用着顺手,之后仍是在这里更。。。(唉出场顺序过重要了,我爱思否)html

数据类型

null是对象类型仍是基本数据类java

1.基本数据类型有 numberstringbooleannullundefinedsymbol(ES6新增的),也称原始数据类型面试

2.JS有原始值类型引用值类型
2.1 原始值类型里面存储的都是值,原始值类型是没法改变的。
2.2 引用值类型指的是由多个值构成的对象。segmentfault

let str = "hello";
str[0] = "z"; //没法修改
通常状况下声明的变量是对象类型的话,会在栈内存中存放着引用地址,该地址会指向堆内存中的内容。

3.JS内存分为堆内存和栈内存,栈内存保存的都是有固定大小、空间的内容。堆内存中存储的都是不固定的内容。数组

  • 字符串是个特例,字符串具备不变性,字符串存储在栈内存中

4.两者区别
4.1 原始值类型保存在栈内存中,能够按值直接访问。
值与值之间是独立存在的,修改一个变量不会影响到其余变量app

var a = 10;
var b = a; //将a的值赋给b
b = 20;
console.log(a); // 10
console.log(b); // 20

① 基本数据类型赋值过程:
函数

4.2 引用值类型存放在堆内存中,按照引用访问。spa

  • 每新建一个新的对象,就会在堆内存中开辟一块新的空间
  • 若是两个变量保存的是同一个对象引用,当经过一个变量修改属性时,另一个也会受到影响.net

    var obj = new Object();
    obj.name = "孙悟空";
    var obj2 = obj;
    obj2.name = "猪八戒";
    console.log(obj.name); //猪八戒
    console.log(obj2.name); //猪八戒

② 引用数据类型赋值过程:

5.若是两个对象如出一辙,但也仍是两个对象

  • 当比较两个基本数据类型的值时,就是比较数值
  • 比较两个引用数据类型时,比较的是对象的内存地址,对象相同,但地址不一样,会返回false

6.null不是引用数据类型,是基本数据类型。

深拷贝、浅拷贝

1.深拷贝: 修改新变量的值不会影响原有变量的值,默认状况下基本数据类型都是深拷贝

let num1 = 123;
let num2 = num1;
num2 = 666; // 修改新变量的值
console.log(num1); //123
console.log(num2); /666

2.浅拷贝:修改新变量的值会影响原有的变量的值,默认状况下引用类型都是浅拷贝。

class Person{
   name = "jjj";
   age = 23;
}
let p1 = new Person();
let p2 = p1;
p2.name = "wdhj";   //修改p2的值影响了p1的值
console.log(p2.name);   //wdhj
console.log(p1.name);   //wdhj

如何实现引用数据类型的深拷贝(上)

当引用数据类型中保存的都是基本数据类型时

如下三种方法并不能实现真正意义上的深拷贝,由于对象中保存的都是基本数据类型

1.方法一(很差)
浅拷贝的缘由:多个变量指向了同一块存储空间,想要实现深拷贝,可让每一个变量分别指向本身的存储空间

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 //由于p1里面的属性都是基本数据类型,因此能够取出p1的name赋值给p2
 p2.name = p1.name; 
 p2.age = p1.age;
 p2.name = "mhf";
 p2.age = 20;
 console.log(p1.name); //mss
 console.log(p2.name); //mhf

2.方法二(很差)
利用循环来遍历每一个属性

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 for(let key in p1){ //利用遍从来赋值每一个属性
        p2[key] = p1[key];
    }
 p2.name = "mhf";
 console.log(p1.name);//mss
 console.log(p2.name);//mhf

3.方法三(重点)
Object的assign()方法接收两个参数,表明含义是将p1中的全部属性拷贝到p2中

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 Object.assign(p2,p1);
 p2.name = "mhf";
 console.log(p1.name);//mss
 console.log(p2.name);//mhf

如何实现引用数据类型的深拷贝(下)

当引用数据类型中保存的都是引用数据类型时

1.方法一:JSON.parse(JSON.stringify(obj))
2.方法二:手写深拷贝

数据类型转换

其余类型 ---> 数值类型

1.Number(常量或者变量)
1.1 注意:

  • Number()没法转换“数字+字母”组合,会转换为NaN,
  • undefined也转换为NaN
let str = Number('123');
console.log(str); //123
console.log(typeof str); //number

1.2 转换规则

  • 纯数字字符串 --> 数字
  • 字符串中有非数字内容 --> NaN
  • undefined --> NaN
  • 空字符串/空格 --> 0
  • false --> 0
  • Null --> 0
  • true --> 1

2.数学运算符中的“+”、“-”
2.1 注意:

  • “+”、“-”均可以将其余类型转换为数值类型,可是“-”会改变数值的正负性
  • “+”、“-”底层上调用了Number()函数
  • “+”、“-”没法转换“数字+字母”组合
  • 任何值作“-”、“*”、“/”运算都会自动转换为Number类型
let str = "123";
let num = +str;
console.log(num); //123
console.log(typeof num); //number

3.parseInt(字符串)和parseFloat(字符串)
3.1 注意:

  • parseInt()和parseFloat()都会从左至右提取数值,一旦遇到非数值就会中止,返回NaN
  • parseInt()和parseFloat()都会将传入的数据先转为string类型,再操做
let res = true;
// let res = "true";
let num = parseInt(res); //把true当作字符串处理,没有遇到数字因此返回NaN
console.log(num); //NaN

其余类型 ---> 字符串类型

1.toString()
Number、Boolean类型可调用toString()转换为String类型

格式:变量名称.toString()
注意:

  • toString()是对拷贝的数据进行转换,所以不会影响原有的数据
  • 不能使用常量直接调用toString()方法
  • null和undefined不能够调用toString()方法
let value = 123;
let str = value.toString();
console.log(str); //123
console.log(typeof str); //string

console.log((3).toString()); //影响原有的数据

2.String()方法

格式: String(常量or变量)
注意:

  • String(变量or常量)能够转换常量,由于是根据传入的值从新生成一个新的值,并不会修改原有的值
  • 常量能够直接使用String()方法
  • String()能够用来转换null,undefined
let res = String(3);
console.log(res); //3
console.log(typeof res); //string

let str = String(undefined);
console.log(str); //undefined
console.log(typeof str); //string

3.常量/变量 + “”

利用 常量/变量 加上一个空字符串来转换,本质上是调用了String()函数, 不会修改原有的值

let value = 123;
let str = value + '';
console.log(str); //123
console.log(typeof str); //string

其余类型 ---> 布尔类型

Boolean(变量or常量)

注意:

  • 只要字符串中有内容就会转换为true,只要字符串的没有内容才会转换false
  • NaN、0会转换为false
  • undefined、null会转换为false

总结:
空字符串/0/NaN/undefined/null会转换成false


toString方法判断数据类型

1.undefinednull没有toString()方法

console.log(undefined.toString()); //报错
console.log(null.toString()); //报错

2.NumberBooleanString等包装对象的toString()方法;本地对象的toString()方法

console.log(Number.toString()); //function Number() { [native code] }
console.log(Boolean.toString()); //function Boolean() { [native code] }
console.log(String.toString()); //function String() { [native code] }

console.log(Function.toString()); //function Function() { [native code] }
console.log(Array.toString()); //function Array() { [native code] }
console.log(Object.toString()); //function Object() { [native code] }
console.log(RegExp.toString()); //function RegExp() { [native code] }
console.log(Date.toString()); //function Date() { [native code] }

3.整数直接跟上.toString()形式会报错,提示无效标记,由于整数后的点会被识别为小数点

  • 解决:
    ①用括号将整数括起来
    ② 或者使用两个..
    ③ 若是仅仅是数据转换,能够利用String()方法
console.log(3.toString()); //报错
console.log((3).toString()); //3
console.log(3..toString()); //3
let res = String(3);
console.log(res); //3

4.Object.prototype.toString()来进行类型识别,返回表明该对象的[object Type]字符串表示

  • 注意:虽然每一个对象都继承了toString()方法,可是不能直接使用,由于对象有可能直接重写了此方法,必须使用call()或者apply()调用
console.log(Object.prototype.toString.call("abc")); //[object String]
console.log(Object.prototype.toString.call(1)); //[object Number]
console.log(Object.prototype.toString.call(true)); //[object Boolean]
console.log(Object.prototype.toString.call(null)); //[object Null]
console.log(Object.prototype.toString.call(undefined)); //[object Undefined]
console.log(Object.prototype.toString.call({})); //[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(/\s/)); //[object RegExp]
console.log(Object.prototype.toString.call(new Date));//[object Date]
function Person(){}
console.log(Object.prototype.toString.call(new Person));//[object Object]

5.除了类型识别以外,还能够进行其余识别,例如识别arguments或DOM元素

(function(){
    console.log(Object.prototype.toString.call(arguments));//[object Arguments]
})();
console.log(Object.prototype.toString.call(document));//[object HTMLDocument]

6.数组Array类型调用toString()方法,返回由数组中每一个值的字符串形式拼接而成的一个以逗号分隔的字符串

console.log([1, 2, 3, 4].toString()); //1,2,3,4
console.log([].toString()); // 输出空

这时咱们能够用这个思路来将多维数组转为一维数组,注意数组中的每一项变为字符串了

let arr = [1,[2,[3,4],5],6];
// console.log(arr.join(",").split(","));
console.log(arr.toString().split(","));

"==" VS "==="比较数据

"=="相等运算符

1.两个值类型相同
若是两个值类型相同,再进行三个等号(===)的比较, 与严格相等运算符彻底同样。

2.两个值类型不一样
在比较不一样类型的数据时,相等运算符会先将数据进行类型转换,而后再用严格相等运算符比较。类型转换规则以下:
(1) 原始类型值比较
原始类型的数据会转换成数值类型再进行比较
① 若是有一个操做数是布尔值,则在比较相等性以前先将其转换为数值; false转换为0,而true转换为1
console.log(true == 1); //true
② 若是一个操做数是字符串,另外一个操做数是数值,在比较相等性以前先将字符串转换为数值
console.log('123' == 123);//true
(2) 对象与原始类型值比较
若是一个操做数是对象,另外一个操做数不是,则调用对象的toString()方法,用获得的基本类型值按照前面的规则进行比较

console.log([] == 0); //true
console.log([].toString()); //空

console.log({} == 0); //false
console.log( {}.toString()); //[object Object]

(3) undefined和null的比较
undefined和null与其余类型的值比较时,结果都为false,它们互相比较时结果为true。

console.log(null == undefined); //true

console.log(undefined == 0); //false
console.log(null == 0); //false

console.log(undefined == undefined); //true
console.log(null == null); //true

(4) NaN的比较
若是有一个操做数是NaN,则相等操做符返回 false; 两个操做数都是NaN,相等操做符也返回 false, NaN不与任何数相等, NaN不等于NaN

console.log(NaN == 0); //false
console.log(NaN == NaN); //false

(5) 两个对象的比较
若是两个操做数都是对象,则比较它们是否是同一个对象。
① 若是两个操做数都指向同一个对象,则相等操做符返回 true;不然, 返回false
② 对于引用类型的数据,比较的是地址

console.log([] == []); //false
console.log({} == {}); //false

let a = [];
let b = a;
console.log(a == b); //true

3.多益笔试题

console.log('' == 0); //true
空串转为数字为0

console.log([] == 0); //true
[]调用toString()返回空串,再转为数字为0

console.log({} == 0); //false
{}调用toString()返回[object Object],再转为数字为NaN

4.很绕的一题
(刚刚原本写了很详细的解析,没保存,此次不想再写了。)
关键在于:
!可将变量转换成boolean类型,null、undefined、NaN以及空字符串('')取反都为true,其他都为false。
{}调用toString()返回[object Object],再转为数字为NaN

console.log([] == ![]); //true
console.log(![]); //false
至关于
console.log([] == 0); //true

console.log({} == !{}); //false
console.log(!{}); //false
至关于
console.log({} == 0); //false

"==="全等运算符

(相比起来,全等运算符就没有那么多条条框框了,相等运算符整理到吐血)
(1)若是类型不一样,就必定不相等
(2)若是两个都是数值,而且是同一个值,那么相等;若是其中至少一个是NaN,那么不相等。(判断一个值是不是NaN,只能使用isNaN( ) 来判断)
(3)若是两个都是字符串,每一个位置的字符都同样,那么相等,不然不相等。
(4)若是两个值都是true,或者两个值都是false,那么相等
(5)若是两个值都引用同一个对象或是函数,那么相等,不然不相等
(6)若是两个值都是null,或者两个值都是undefined,那么相等

显示转换 VS 隐式转换

显式转换的数据类型

1.将非数值转换为数值类型的函数

  • Number():Number(mix),能够用于任何数据类型,该函数先将mix的数据类型转换为number类型,而后再将mix的值转换为数值。
    若mix的值能直接转换成数字,则直接显示。若不能则显示0或NaN.
  • parseInt():将字符串转换为数值,不遵循四舍五入。这里的string必须是数字类型的开头字符串,一直遍历到非数值的那个字符才中止。若不是数字开头,则会显示NaN.
  • parseFloat():将string转换为浮点数。从数字位开始看,直到非数字位结束,用法与parseInt(string)一致。

2.将其它类型的数据转换为字符串类型的函数

  • String(mix):将mix转换成字符串类型。该函数能够将任何数据类型的值转换为字符串。
  • toString()demo.toString()将demo转换成字符串类型。demo不能是null undefined

3.将值转换成布尔值类型
Boolean()方法把undefined、null、-0、+0、NaN、''(空字符串)六个值的转化为false,其余的值所有为true。

隐式的数据类型转换

隐式类型的转换是系统进行运算时自动进行的,可是调用的方法都是显式类型转换的方法。

1.递增和递减操做符
不只适用于整数,还能够用于字符串、布尔值、浮点数值和对象。
即先将变量经过Number()转换成number的数据类型,而后再进行递增、递减操做。

2.正负号
不只适用于整数,还能够用于字符串、布尔值、浮点数值和对象。
将变量经过Number()转换成number的数据类型。

3.isNaN(变量)
执行过程为:即先将变量经过Number()转换,再进行isNaN()判断 。

4.加号
加法有两个做用。

  • 若是没有运算过程当中没有字符串时,就将变量经过`Number()转换为number类型后,再进行运算。
  • 若是有字符串的话,加号两边起的就是字符串链接做用。

5.- * / % (减号,乘号,除号,取余)
运算时把数据转换成number类型后,再进行运算。

6.&& || ! (与或非运算)
将运算符两边的值转换成经过Boolean()函数转换成布尔类型,而后再进行运算。
不一样的是:&& || 返回的是比较后自身的原值,而 !运算返回的是布尔值.

7.< > <= >= == != 比较运算符
当数字和字符串比较大小时,会隐示将字符串转换成number类型进行比较。
而当字符串和字符串比较大小时,则比较的是ascii码的大小。最后返回的则是布尔值

几道很适合放这里的题

1.

var str = 1 + 2 + 'abc';
console.log(str); //3abc

2.

var a;
var b = a * 0;
//console.log(b); //NaN
//console.log(b === b); //false
if(b === b){
    console.log(b * 2 + "2" - 0 +4)
}else{
    console.log(!b * 2 + "2" - 0 +4)
} //26

3.

var a = 1;
//console.log(a); //1
var b = a * 0;
//console.log(b); //0
if(b === b){
  console.log(b * 2 + "2" -0 + 4)
}else{
  console.log(!b * 2 + "2" - 0 +4)
} //6

4.涉及精度问题

var a = 1.0 - 0.9;
if(a == 0.1){
  console.log(true);
}
else{
  console.log(false);
} // false

var b = 0.8 - 0.7;
if(a == b){
  console.log(true);
}else{
  console.log(false);
} // false

本文参考连接:
toString()方法的讨论参考到了这篇:
https://www.cnblogs.com/xiaoh...

==&===的比较参考了这两篇:
http://javascript.ruanyifeng.com/grammar/operator.html#toc6
https://blog.csdn.net/magic_xiang/article/details/83686224

参考图片来自:博主:cc_ccc

相关文章
相关标签/搜索