Javascript学习笔记-强制类型转换

Javascript类型转换.png

1. 基本类型转换

由于Javascript中存在七种基本类型:number, string , boolean , object, null, undefined, symbol,在使用过程中会有意识和无意识的在 运行时 存在相互转换。

1.1 toString

1.1.1 较大数和较小数

当数字处于较大或较小时,由于Javascript会将数字转换为科学记数法方式记录,这个时候如果对其进行转换为字符串,那么显示结果是科学记数法的字符串

console.log(String(0.0000000001)); // '1e-10'
console.log(String(10000000000000000000000)); // '1e+22'
1.1.2 对象的toString

一般对象的toString方法,将会显示该对象的[[class]]

Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call(function(){}) // '[object Function]'
1.1.3 数组的toString

数组由于自身重写过toString方法,数组的toString方法会返回逗号连接的字符串

Array.prototype.toString.call(['1', 'a', {'a': 1}]); // '1,a,[object Object]'
1.1.4 JSON.stringify()

JSON.stringify()方法用于将数据转换为JSON格式的字符串,但是对于undefined, function, symbol类型的数据,在转换时会选择抛弃,从而返回undefined

JSON.stringify(undefined); // undefined
JSON.stringify(function(){}); // undefined
JSON.stringify(Symbol('test')); // undefined

转换对象在数组中时,这些值会被赋值为null

JSON.stringify([undefined, 1, function(){}]); // [null, 1, null]    

如果转换对象出现循环引用,那么在转换的时候会抛出异常。
为了使得我们所有的对象在转换成JSON字符串的时候可以正常转换,我们可以定义toJSON方法,该方法在JSON.stringify调用前会进行调用,对数据进行处理

var a = {a: 1, b: 2};
a.toJSON = function() {
    return {a: 1}
}
JSON.stringify(a); // "{"a": "1"}"

JSON.stringify一共可以接受三个参数,除了第一个参数为转换对象以外,第二个参数可以接收了一个数组或者方法对转换对象属性进行过滤,第三个参数则可以将JSON字符串进行格式化

var a = {a: 1, b: 2};
// 第二个参数使用数组进行过滤
JSON.stringify(a, ['a']); // "{"a": "1"}"
// 第二个参数使用function,自身对象会先调用方法一次后,每个属性调用一次,返回undefined时则过滤掉该属性
JSON.stringify(a, (k, v)=>{
    if (k!=='a') {
      return v;
    }
}); // "{"b": 2}"
// 第三个参数进行格式化,接收数字时每个层级添加相应数目空格
JSON.stringify({a:1, b:2, c: {a: 1}}, null, 2);
// 第三个参数如果为字符串,则每个层级添加该字符串,能添加的字符串最大长度为10
JSON.stringify({a:1, b:2, c: {a: 1}}, null, '--');

1.2 toNumber

1.2.1 基本类型转Number

基本类型转为number,按照以下规则转换:

// null , false , '' 转换为0
console.log(Number(null)); // 0
console.log(Number(false)); // 0
console.log(Number('')); // 0
// true转换为1
console.log(Number(true)); // 1
// undefined转换为NaN 
console.log(Number(undefined)); // NaN
// 字符串如果是数字格式则会进行转换
console.log(Number('123')); // 123
1.2.2 对象转Number

遵循toPrimitive的规则,如果对象存在valueOf方法,则调用该方法,如果调用后返回的结果为基本类型,则按照 1.2.1 基本类型转Number 规则进行转换;如果返回不为基本类型或者不存在valueOf方法,则调用toString方法后,按照 1.2.1 基本类型转换Number 规则进行处理

var a = [1]; 
// 转为Number,首先使用a.valueOf()方法,返回[1] 
// 继续调用toString方法,返回'1' 
// 再将字符串转为数字1
console.log(Number(a)); // 1
// 如果重写valueOf方法,则会返回超乎想象的结果
a.valueOf = () => {return 2};
console.log(Number(a)); // 2

1.3 toBoolean

boolean类型转换过程只会进行真假值的检查,其中假值包括: false, '', null, undefined, NaN, +0, -0,假值将会转换为false,假值以外的其他值均为真值,转换为true

console.log(Boolean(false)); // false
console.log(Boolean('')); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(+0)); // false
console.log(Boolean(-0)); // false

1.4 特殊

对于一个特殊的对象Object.create(null),由于原型链的继承关系,该对象不继承Object,所以不存在valueOftoString方法,那么在进行转换的时候将抛出异常

var a = Object.create(null);
console.log(Number(a)); // Uncaught TypeError: Cannot convert object to primitive value

2. 类型转换

类型转换可以分为显示类型转换和隐式类型转换,但显示和隐式只是相对的,在我们知道会进行转换的时候他就是隐式,当我们知道会进行转换以后其实就变为了显式转换了。

2.1 显示类型转换

2.1.1 String()和Number()转换

按照 1. 基本类型转换 的toString和toNumber的规则进行转换

2.1.2 一元运算符转换

使用一元运算符(+, -)会将数据转换为number类型,相当于Number(data)

console.log(+[]); // 0 ,使用toNumber的规则,相当于Number([])
2.1.3 位反运算符转换

使用位反运算符(~)会将数据转换为number类型,相当于-(Number(data) + 1)

console.log(~[]); // -1

利用位反运算符,可以一些特定方法返回值进行处理后,简化判断

// 例如indexOf匹配失败会返回-1,就可以利用位反运算简化判断条件
if('abc'.indexOf('a') > -1) {}
// 相当于
if(~'abc'.indexOf('a')){}
2.1.4 字符串解析

使用parseIntparseFloat可以将字符串(非字符串会优先转换为字符串)解析为number类型,不同于Number()的强制类型转换,解析过程会进行到不能解析为止,而Number()转换在判断不能转换到时候直接返回NaN

console.log(parseInt('12ab')); // 12
console.log(Number('12ab')); // NaN

在ES5以后,parseInt默认使用了10进制作为基数进行转换,可以通过第二个参数指定基数,此时对字符串解析过程会按照指定进制进行

console.log(parseInt('1a', 19)); // 29 因为按照19进制1和a都是有效的字符,返回结果为29
2.1.5 !转换

使用'!',可以转换为boolean类型,转换相当于Boolean(data)

console.log(!0); // true
console.log(!!0); //false
2.1.6 Symbol()对象转换

Symbol对象不能通过隐式转换进行,如果要进行转换必须使用构造方法来显示转换(似乎只能转为字符串)。

var a = Symbol('1');
console.log(a + 1); Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(String(a) + 1); // 'Symbol(1)1'

2.2 隐式类型转换

2.2.1 算数运算转换

在算数运算的过程中会进行数据转换:
对于+运算来说,如果两个操作数中存在字符串,则会尝试进行字符串连接操作,如果操作数为对象,则会使用toPrimitive(使用valueOf方法和toString方法)转为基本类型后,再进行判断。如果不存在字符串,则全部转为数字进行加法操作。

console.log(1 + ['1']); // 11 , 先将对象['1']根据toPrimitive规则转为'1',操作变为 1 + '1' , 进行字符串拼接

对于-运算来说,直接将所有操作数进行toNumber操作后进行计算

console.log(1 - ['1']); // 0
2.2.2 逻辑语句中的类型转换

作为逻辑语句中的判断条件,将转换为boolean值进行处理

if(1) { console.log(1)}; //  由于Boolean(1)是true,所以会打印1
if(0) { console.log(1)}; //  由于Boolean(0)是false,所以不会打印1
2.2.3 ||和&&

||&&的操作,返回结果并不是boolean值,而是根据短路规则,判断操作数的Boolean()结果,返回两个操作数的其中之一,其中||true时进行短路返回,&&false时进行短路返回

var a = 1 && 0;
console.log(a); // 0 , 由于第一个操作数Boolean(1)是true,所以返回第二个操作数
a = 0 && 1; 
console.log(a); // 0 , 由于第一个操作数Boolean(0)是false,所以返回第一个操作数
a = 1 || 0; 
console.log(a); // 1, 由于第一个操作数Boolean(1)是true,所以返回第一个操作数
a = 0 || 1; 
console.log(a); // 1, 由于第一个操作数Boolean(0)是false,所以返回第二个操作数

3. 数据比较

3.1 宽松等于

使用==进行比较的称做宽松等于,区别于===的严格等于,在于进行比较的时候,等式两边的数值在类型不相等的时候会尝试进行强制转换,而严格等于不会进行类型的转换。
宽松等于的转化规则如下:

  • 如果两个比较数类型一致且为基本类型,则直接进行比较,数字按照大小,字符串按照字母表顺序比较。
  • 如果两个比较数类型不一致且为基本类型,则转换为number进行比较。
  • 如果两个比较数据均为对象类型,则比较对象的引用是否相等
  • 如果两个数据中一个为对象,则根据toPrimitive规则,将其转换为基本类型后,进行比较。

console.log('a' == 'a'); // true , 类型相同且为基本类型,则直接比较
console.log('1' == 1); // true , 类型不同但均为基本类型,将'1'转为number进行比较
console.log({} == {}); // false , 两个比较数均为对象,判断引用是否相等
console.log('a' == ['a']); // true,一个比较数为对象,则将['a']转换为'a'后进行比较

对于特殊的undefinednull

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

3.2 抽象比较

抽象比较也就是非等于比较,比较规则和宽松等于规则相同

console.log('a' < 'b'); // true, 类型相同,直接进行比较,字符串按照字母表顺序
console.log('0' < 1); // true, 类型不同但均未基本类型,将'0'转为number后进行比较
console.log('a' < ['b']); // true, 一个比较数为对象,则将['b']转换为'b'后进行比较

4. 参考

《你不知道的Javascript(中卷)》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容