【你不知道的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 ...
随机推荐
- VFP CursorAdapter 起步三(作者:Doug Hennig 译者:fbilo)
可重用数据类 VFP 的程序员们想要一个可重用的数据类已经很久了.尽管在过去的版本中也有许多解决这个问题的办法,不过总是有点美中不足.现在在 VFP 8里,我们有了真正的可重用数据类.这个月,Doug ...
- 开源堡垒机jumpserver的安装
开源跳板机jumpserver安装 简介 Jumpserver 是全球首款完全开源的堡垒机, 使用GNU GPL v2.0 开源协议, 是符合4A 的专业运维审计系统 Jumpserver 使用Pyt ...
- Vscode开发Python环境安装
VSCode 开发 Python 使用python,主要是做一些工具和爬虫的操作,语法简单,功能复杂,入手很快. 我们通过在 VSCode 中搜索 Python 插件,发现,开发 python 的话, ...
- 高并发之——不得不说的线程池与ThreadPoolExecutor类浅析
一.抛砖引玉 既然Java中支持以多线程的方式来执行相应的任务,但为什么在JDK1.5中又提供了线程池技术呢?这个问题大家自行脑补,多动脑,肯定没坏处,哈哈哈... 说起Java中的线程池技术,在很多 ...
- NPM install -save 和 -save-dev 区别
最近在写Node程序的时候,突然对 npm install 的-save和-save-dev 这两个参数的使用比较混乱.其实博主在这之前对这两个参数的理解也是模糊的,各种查资料和实践后对它们之间的异同 ...
- 让div充满整个body
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue 路由&组件懒加载(按需加载)
当打包构建应用时,Javascript 包会变得非常大,影响页面加载速度.使用Vue路由懒加载和组件懒加载可以提升页面加载速度,减少白屏时间,提升用户体验. 用法有如下三种:(路由懒加载与组件懒加载用 ...
- 跨域打开页面:Uncaught DOMException: Blocked a frame with origin
Uncaught DOMException: Blocked a frame with origin 使用postMessage()方法可以解决跨域传值的问题 Api: https://develop ...
- Python面试(网编+数据库)
第一部分 必答题 简述 OSI 7层模型及其作用?(2分) 应用层:与用户直接交互,软件.网站等 表示层:使用软件.网站可以查看的数据,图片等 会话层:保持登录状态,电脑中为cookie 传输层:选择 ...
- 04.JS逻辑结构
前言: 学习一门编程语言的基本步骤(01)了解背景知识(02)搭建开发环境(03)语法规范(04)常量和变量(05)数据类型(06)数据类型转换(07)运算符(08)逻辑结构8.逻辑结构——logi ...