【你不知道的javaScript 中卷 笔记2】javaScript中的类型转换
1.1 对象内部属性 [[Class]]
常见的原生函数:
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()——ES6
var a = new String( "abc" );
typeof a; // 是"object",不是"String"
a instanceof String; // true
Object.prototype.toString.call( a ); // "[object String]"
typeof 在这里返回的是对象类型的子类型。
chrome下console.log( a );
new String("abc") 创建的是字符串 "abc" 的封装对象,而非基本类型值 "abc"。
Object.prototype.toString(..)
查看对象的内部 [[Class]] 属性,通常对象的内部 [[Class]] 属性和创建该对象的内建原生构造函数相对应,但 null 和 undefined除外
Object.prototype.toString.call( null );// "[object Null]"
Object.prototype.toString.call( undefined ); // "[object Undefined]"
Object.prototype.toString.call( "abc" ); // "[object String]"
Object.prototype.toString.call( 42 ); // "[object Number]"
Object.prototype.toString.call( true ); // "[object Boolean]"
Null() 和 Undefined() 这样的原生构造函数并不存在,但是内部 [[Class]] 属性值仍 然是 "Null" 和 "Undefined";基本类型值被各自的封装对象自动包装。
1.2 封装对象
基本类型值没有 .length
和 .toString()
这样的属性和方法,javaScript
会自动为基本类型值包装一个封装对象,浏览器为 .length
这样的常见情况做了性能优化,直接使用封装对象来“提前优化”代码反而会降低执行效率。
var a = new Boolean( false );
if (!a) {
console.log( "Oops" ); // 执行不到这里,a始终为真值
}
可以使用 Object(..) 函数,自行封装基本类型值
var a = "abc";
var b = new String( a );
var c = Object( a );
typeof a; // "string"
typeof b; // "object"
typeof c; // "object"
b instanceof String; // true
c instanceof String; // true
Object.prototype.toString.call( b ); // "[object String]" Object.prototype.toString.call( c ); // "[object String]"
拆封
使用 valueOf() 函数,得到封装对象中的基本类型值
var a = new String( "abc" );
var b = new Number( 42 );
var c = new Boolean( true );
a.valueOf(); // "abc"
b.valueOf(); // 42
c.valueOf(); // true
隐式拆封(强制类型转换)
var a = new String( "abc" );
var b = a + ""; // b的值为"abc"
typeof a; // "object"
typeof b; // "string"
Symbol(..)
- 符号是具有唯一性的特殊值(并 非绝对),用它来命名对象属性不容易导致重名。
- 使用 Symbol(..) 原生构造函数来自定义符号不能带 new 关键字,否则会出错
- 论是在代码还是开发控制台中都无法查看和访问它的值,只会 显示为诸如 Symbol(Symbol.create) 这样的值。
- ES6 中有一些预定义符号,以 Symbol 的静态属性形式出现,如 Symbol.create、Symbol. iterator 等
1.3 原生对象的原型
typeof Function.prototype;
Function.prototype();// "function" // 空函数!
RegExp.prototype.toString(); // "/(?:)/"——空正则表达式
"abc".match( RegExp.prototype );// [""]
Array.isArray( Array.prototype ); // true
Array.prototype.push( 1, 2, 3 );// 3
Array.prototype;// [1,2,3]
Function.prototype
是一个函数,RegExp.prototype
是一个正则表达式,而 Array. prototype
是一个数组
1.4 值类型转换
将值从一种类型转换为另一种类型通常称为类型转换(type casting),这是显式的情况;隐式的情况称为强制类型转换(coercion)。
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时。
var a = 42;
var b = a + ""; // 隐式强制类型转换
var c = String( a ); // 显式强制类型转换
1.4 .1 类型转换的基本规则
**ToString **处理非字符串到字符串的强制类型转换。
如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。
JSON 字符串化
工具函数JSON.stringify(..)
在将 JSON
对象序列化为字符串时也用到了 toString
。
JSON.stringify(..)
在对象中遇到 undefined、function 和 symbol 时会自动将其忽略,在
数组中则会返回 null
不安全的 JSON
值:
- undefined
- function
- symbol
- 包含循环引用的对象
JSON.stringify( undefined ); // undefined
JSON.stringify( function(){} );// undefined
JSON.stringify( [1,undefined,function(){},4]//"[1,null,null,4]"
);
JSON.stringify({ a:2, b:function(){} })//"{"a":2}"
//对包含循环引用的对象执行 JSON.stringify(..) 会出错。
JSON.stringify(..) 并不是强制类型转换,它涉及 ToString 强制类型转换,具体表现在以下两点:
(1) 字符串、数字、布尔值和 null 的 JSON.stringify(..) 规则与 ToString 基本相同。
(2) 如果传递给 JSON.stringify(..) 的对象中定义了 toJSON() 方法,那么该方法会在字符串化前调用,以便将对象转换为安全的 JSON 值。
ToNumber处理非数字到当作数字的强制类型转换
- true 转换为 1,false 转换为 0。undefined 转换为 NaN,null 转换为 0
- 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再强制转换为数字。
- 在获取对象的基本类型时,检查该值是否有 valueOf() 方法。 如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString()的返回值(如果存在)来进行强制类型转换。,如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
- 使用 Object.create(null) 创建的对象 [[Prototype]] 属性为 null,并且没有 valueOf() 和 toString() 方法,因此无法进行强制类型转换。
日期显式转换为数字
一元运算符 + 的另一个常见用途是将日期(Date)对象强制类型转换为数字,返回结果为 Unix 时间戳,以微秒为单位(从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间):
var d = new Date( "Mon, 18 Aug 2014 08:53:06 CDT" );
+d; // 1408369986000
var timestamp = Date.now();
var timestamp = new Date().getTime();
显式解析数字字符串
var a = "42";
var b = "42px";
Number( a ); // 42
parseInt( a ); // 42
Number( b ); // NaN
parseInt( b ); // 42
解析允许字符串中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停 止。而转换不允许出现非数字字符,否则会失败并返回 NaN。 ES5 开始 parseInt(..) 默认转换为十进制数
var a = {
num: 21,
toString: function() { return String( this.num * 2 ); }
};
parseInt( a ); // 42
parseInt(..) 先将参数强制类型转换为字符串再进行解析
ToBoolean
假值(falsy value)
• undefined
• null
• false
• +0、-0 和 NaN
• ""
Boolean(..) 和 !! 来进行显式转换
var a = "0";
var g;
!!a; // true
!!g; // false
// 不常用
Boolean( a ); // true
Boolean( g ); // false
字符串和数字之间的显式转换
var a = 42;
var b = String( a );
var c = "3.14";
var d = Number( c );
b; // "42"
d; // 3.14
字符串和数字之间的转换是通过 String(..) 和 Number(..) 来实现的,不用 new 关键字,并不创建封装对象。
var a = 42;
var b = a.toString();
var c = "3.14";
var d = +c;
b; // "42"
d; // 3.14
a.toString() 中涉及隐式转换。因为 toString() 对 42 这样的基本类型值不适用,所以 JavaScript 引擎会自动为 42 创建一个封 装对象然后对该对象调用 toString()
字符串和数字之间的隐式强制类型转换
var a = 42;
var b = a + "";
b; // "42"
a + "" 会对a调用valueOf()方法,然后通过ToString抽象 操作将返回值转换为字符串。而 String(a) 则是直接调用 ToString()。
var a = "3.14";
var b = a - 0;
b; // 3.14
-是数字减法运算符,因此a - 0会将a强制类型转换为数字。也可以使用a * 1和a /1,这两个运算符也只适用于数字
布尔值到数字的隐式强制类型转换
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
// 跳过假值,和处理0一样,但是避免了NaN
if (arguments[i]) {
sum += arguments[i];
}
}
return sum == 1;
}
var a = true;
var b = false;
onlyOne( b, a );// true
onlyOne( b, a, b, b, b );// true
|| 和 &&
&& 和 || 运算符的返回值并不一定是布尔类型,而是两个操作数其中一个的值。
var a = 42;
var b = "abc";
var c = null;
a || b; // 42
a && b;// "abc"
c || b; // "abc"
c && b;// null
- || 和 && 首先会对第一个操作数(a 和 c)执行条件判断,如果其不是布尔值(如上例)就 先进行 ToBoolean 强制类型转换,然后再执行条件判断。
- 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数(a 和 c)的值,如果为 false 就返回第二个操作数(b)的值。
- && 则相反,如果条件判断结果为 true 就返回第二个操作数(b)的值,如果为 false 就返回第一个操作数(a 和 c)的值。
var a = 42;
var b = null;
var c = "foo";
if (a && (b || c)) {
console.log( "yep" );
}
a && (b || c)的结果实际上是"foo"而非true,然后再由if将foo强制类型转换为布尔值,所以最后结果为 true。
宽松相等和严格相等
- “== 允许在相等比较中进行强制类型转换,而 === 不允许。”
- 如果两个值的类型不同,就需要考虑有没有强制类型转换的必要,有就用 ==,没有就 强制类型转换用 ===,不用在乎性能。
- null == undefined //true
对象和非对象之间的相等比较
(1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
(2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
var a = 42;
var b = [ 42 ];
a == b; // true
[ 42 ] 首先调用 ToPromitive 抽象操作,返回 "42",变成 "42" == 42,然后又变成 42 == 42,最后二者相等。
Number.prototype.valueOf = function() { return 3;};
new Number( 2 ) == 3; // true
Number(2) 涉及 ToPrimitive 强制类型 转换,因此会调用 valueOf()。
安全运用隐式强制类型转换
- 如果两边的值中有 true 或者 false,千万不要使用 ==。
- 如果两边的值中有 []、"" 或者 0,尽量不要使用 ==。
- typeof x == "function"是100%安全的
- 要避免a < b中发生隐式强制类型转换,确保a和b为相同的类型
总结
对于强制类型转换,取其精华,去其糟粕
【你不知道的javaScript 中卷 笔记2】javaScript中的类型转换的更多相关文章
- 【你不知道的javaScript 中卷 笔记1】javaScript中的类型与值
一.类型与值 1.0 javaScript 七种内置类型: 空值(null) 未定义(undefined) 布尔值( boolean) 数字(number) 字符串(string) 对象(object ...
- 《高性能JavaScript》学习笔记——日更中
------------------2016-7-20更------------------ 最近在看<高性能JavaScript>一书,里面当中,有讲很多提高js性能的书,正在看的过程中 ...
- 《你不知道的JavaScript(中卷)》读书笔记
中卷有点无聊,不过也是有干货的,但是好像要背一下的样子.不过作者大大都夸我是“优秀的开发人员”了,肯定要看完呀~~ 开发人员觉得它们太晦涩,很难掌握和运用,弊(导致bug)大于利(提高代码可读性).这 ...
- 从头开始学JavaScript 笔记(一)——基础中的基础
原文:从头开始学JavaScript 笔记(一)--基础中的基础 概要:javascript的组成. 各个组成部分的作用 . 一.javascript的组成 javascript ECMASc ...
- 《编写可维护的javascript》读书笔记(中)——编程实践
上篇读书笔记系列之:<编写可维护的javascript>读书笔记(上) 上篇说的是编程风格,记录的都是最重要的点,不讲废话,写的比较简洁,而本篇将加入一些实例,因为那样比较容易说明问题. ...
- 学习笔记:JavaScript传参方式———ECMAScript中所有函数的参数都是按值传递
我们把命名参数(arguments)视为局部变量,在向参数传递基本类型值时,如同基本类型变量的复制一样,传递一个副本,参数在函数内部的改变不会影响外部的基本类型值.如: function add10( ...
- 编程笔记:JavaScript 中的类型检查
在Badoo的时候我们写了大量的JS脚本,光是在我们的移动web客户端上面就有大概60000行,可想而知,维护这么多JS可是相当具有挑战性的.在写如上规模js脚本客户端应用的时候我们必须对一件事保持警 ...
- 《你不知道的javascript》读书笔记2
概述 放假读完了<你不知道的javascript>上篇,学到了很多东西,记录下来,供以后开发时参考,相信对其他人也有用. 这篇笔记是这本书的下半部分,上半部分请见<你不知道的java ...
- 【译】用jQuery 处理XML--浏览器中的XML与JavaScript
用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...
随机推荐
- Spark RDD基本概念、宽窄依赖、转换行为操作
目录 RDD概述 RDD的内部代码 案例 小总结 转换.行动算子 宽.窄依赖 Reference 本文介绍一下rdd的基本属性概念.rdd的转换/行动操作.rdd的宽/窄依赖. RDD:Resilie ...
- Django (二) 常用字段及 ORM
MVC介绍 Django生命周期 many-to-many One-to-many Django常用字段 CharFiled 需要有max_length unique=True(代表不能重名) Ema ...
- Samba搭建Linux和Windows文件共享服务
一.Samba简介 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享 ...
- 前缀和&差分
一:差分数组概念 一.差分数组的定义及用途 1.定义:对于已知有n个元素的数列d,建立记录它每项与前一项差值的差分数组f:显然,f[1]=d[1]-0=d[1];对于整数i∈[2,n],我们让f[i ...
- nginx启动报错nginx: [error] open() "/usr/local/etc/nginx/logs/nginx.pid" failed
问题:nginx启动的时候会报丢失pid的错误 nginx: [error] open() “/usr/local/var/run/nginx.pid” failed 解决方案: sudo nginx ...
- 前端vue开发中的跨域问题解决,以及nginx上线部署。(vue devServer与nginx)
前言 最近做的一个项目中使用了vue+springboot的前后端分离模式 在前端开发的的时候,使用vue cli3的devServer来解决跨域问题 上线部署则是用的nginx反向代理至后台服务所开 ...
- 一招教你用数据可视化BI软件创建网店运营监控大屏
灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件. 本文以网店运营监控大屏为例为大家演 ...
- 解决egg-mysql连接数据库报错问题
遇到这个问题,我在网上找了好多资料,最终于解决了!!!★,°:.☆( ̄▽ ̄)/$:.°★ . 我遇到的问题是这样的:链接mysql完全按照官网上做的,但是在yarn dev 时就是一直报错,错误我就不 ...
- Git 工作流程和Git分支管理策略
git-flow 阮一峰大佬写的文章真不错 git-flow, github-flow, gitlab-flow 阮一峰大佬写的文章真不错
- Github上优秀的.NET Core项目
Github上优秀的.NET Core开源项目的集合.内容包括:库.工具.框架.模板引擎.身份认证.数据库.ORM框架.图片处理.文本处理.机器学习.日志.代码分析.教程等. Github地址:htt ...