可检测基本数据类型和function,没法检测引用数据类型面试
var arr = [ null, // object undefined, // undefined true, // boolean 12, // number 'haha', // string Symbol(), // symbol 20n, // bigint function(){}, // function {}, // object [], // object ] for (let i = 0; i < arr.length; i++) { console.log(typeof arr[i]) }
没法检测基本数据类型,可检测function 、引用类型和继承关系数组
var arr = [ // { 'value': null, 'type': null}, ----> error // { 'value': undefined, 'type': undefined}, ----> error { 'value': true, 'type': Boolean}, // false { 'value': 12, 'type': Number}, // false { 'value': 'haha', 'type': String}, // false { 'value': Symbol(), 'type': Symbol}, // false { 'value': 20n, 'type': BigInt}, // false { 'value': function(){}, 'type': Function}, // true { 'value': {}, 'type': Object}, // true { 'value': [], 'type': Array}, // true ] for (let i = 0; i < arr.length; i++) { console.log(arr[i].value instanceof arr[i].type) }
instanceof 除了能够检测类型外,还能够在继承关系的检测中使用浏览器
function Aoo(){} function Foo(){} Foo.prototype = new Aoo(); // JavaScript 原型继承 var foo = new Foo(); console.log(foo instanceof Foo) // true console.log(foo instanceof Aoo) // true
提示:虽可检测,但 prototype 可被改写,constructor 会改变,不建议使用该方法判断。安全
var arr = [ // { 'value': null, 'type': Null}, ----> error // { 'value': undefined, 'type': Undefined}, ----> error { 'value': true, 'type': Boolean}, // true { 'value': 12, 'type': Number}, // true { 'value': 'haha', 'type': String}, // true { 'value': Symbol(), 'type': Symbol}, // true { 'value': 20n, 'type': BigInt}, // true { 'value': function(){}, 'type': Function}, // true { 'value': {}, 'type': Object}, // true { 'value': [], 'type': Array}, // true ] for (let i = 0; i < arr.length; i++) { console.log(arr[i].value.constructor == arr[i].type) }
通常类型都能检测,建议使用。函数
var arr = [ null, // [object Null] undefined, // [object Undefined] true, // [object Boolean] 12, // [object Number] 'haha', // [object String] Symbol(), // [object Symbol] 20n, // [object BigInt] function(){},// [object Function] {}, // [object Object] [], // [object Array] new Date(), // [object Date] new RegExp(),// [object RegExp] new Error(), // [object Error] ] for (let i = 0; i < arr.length; i++) { console.log(Object.prototype.toString.call(arr[i])) }
将值从一种类型转换为另外一种类型一般称为类型转换(type casting),这是显式的状况;隐式的状况称为强制类型转换(coercion)。this
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时(runtime)。spa
强制类型转换又分如下两种:prototype
“抽象操做”(即“仅供内部使用的操做”),是js的内置函数。code
处理非字符串到字符串的强制类型转换。对基本类型有效,对引用类型(object)无效。对象
String(12); // "12" String("haha"); // "haha" String(null); // "null" String(undefined); // "undefined" String(true); // "true" String({a: '12'}); // [object Object]
value值 | 原始类型 | 转换后 |
---|---|---|
12 | number | "12" |
haha | string | "haha" |
null | null | "null" |
undefined | undefined | "undefined" |
true | boolean | "true" |
{a: '12'} | object | [object Object] |
JSON 字符串化和 toString() 的效果基本相同,只不过序列化的结果老是字符串。
1. 安全的 JSON 值转换
JSON.stringify(12); // "12" JSON.stringify("str"); // ""str"" JSON.stringify(null); // "null" JSON.stringify(true); // "true" JSON.stringify({a: '12'}); // "{"a":"12"}"
value值 | 原始类型 | 转换后 |
---|---|---|
12 | number | "number" |
haha | string | ""haha"" (含有双引号的字符串) |
null | null | "null" |
true | boolean | "true" |
{a: '12'} | object | "{"a":"12"}" |
2. 不安全的 JSON 值转换
JSON.stringify(..) 在对象中遇到 undefined
、function
和 symbol
时会自动将其忽略,在
数组中则会返回 null
(以保证单元位置不变)。
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(..) 会出错
var o = { }; var a = { b: 42, c: o, // 循环引用 d: function(){} }; // 在a中建立一个循环引用 o.e = a; // 循环引用在这里会产生错误 // JSON.stringify( a ); // JSON.stringify( o );
3. 自定义 JSON 序列化
var a = { b: 42, c: 'haha', d: function(){} }; // 自定义的JSON序列化 a.toJSON = function() { // 序列化仅包含b return { b: this.b }; }; JSON.stringify( a ); // "{"b":42}"
处理非数字值到数字的强制类型转换, 处理失败时返回NaN。
Number("33"); // 33 Number(null); // 0 Number(undefined); // NaN Number(true); // 1 Number(false); // 0 Number({a: '12'}); // NaN Number(function(){}); // NaN
value值 | 原始类型 | 转换后value值 |
---|---|---|
"33" | string | 33 |
<span class="red">null</span> | null | <span class="red">0</span> |
undefined | undefined | NaN |
true | boolean | 1 |
false | boolean | 0 |
{a: '12'} | object | NaN |
八进制和十六进制
// 八进制的377 -> 十进制255 Number(0377); // 255 // 十六进制 -> 十进制的255 Number(0xFF); // 255
对象和数组
对象(包括数组)会首先被转换为相应的基本类型值,若是返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值,抽象操做会检查该值是否有 valueOf()
方法。若是有而且返回基本类型值,就使用该值进行强制类型转换。若是没有就使用 toString()
的返回值(若是存在)来进行强制类型转换。若是 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
从 ES5 开始,使用 Object.create(null) 建立的对象 [[Prototype]] 属性为 null,而且没有 valueOf() 和 toString() 方法,所以没法进行强制类型转换。
var a = { valueOf: function(){ return "42"; } }; var b = { toString: function(){ return "42"; } }; var c = [4,2]; c.toString = function(){ return this.join( "" ); // "42" }; Number( a ); // 42 Number( b ); // 42 Number( c ); // 42 Number( "" ); // 0 Number( [] ); // 0 Number( [ "abc" ] ); // NaN Number(['1']); // 1 Number(['1', '2']); // NaN
除了假值和假值对象,其余的均可以看作是真值。
// 假值 Boolean(""); // false Boolean(undefined); // false Boolean(null); // false Boolean(false); // false Boolean(+0); // false Boolean(-0); // false Boolean(0); // false Boolean(NaN); // false // 假值对象(浏览器本身建立的对象) Boolean(document.all) // false ... // 真值 Boolean([]); // true Boolean({}); // true Boolean(function(){}); // true Boolean(1) // true ...
toString() 是显式的,不过其中涉及隐式转换。由于toString() 对 number 这样的基本类型值不适用,因此 JavaScript 引擎会自动为 number 类型建立一个封装对象,而后对该对象调用 toString()。这里显式转换中含有隐式转换。
var a = 42; a.toString(); // "42"
+
和 -
一元运算 + 被广泛认为是显式强制类型转换
var c = "3.14"; var d = +c; var e = -c; // 会反转符号位 var f = - -c; // 中间要有空格 d; // 3.14 e; // -3.14 f; // 3.14 // 日期显式转换为数字 var d = new Date; +d; // 时间戳 1595836134918 // 更好的办法(建议使用) var timestamp = Date.now()
~
运算符(非)~
运算符(位非)用于对一个二进制操做数逐位进行取反操做。
~12; // -13
~
和 indexOf() 结合使用
var a = "Hello World"; if (~a.indexOf( "lo" )) { // -4 -> 真值 -> true // 找到匹配! } if (!~a.indexOf( "ol" )) { // -4 -> 真值 -> true // 没有找到匹配! }
var a = "42"; var b = "42px"; Number( a ); // 42 parseInt( a ); // 42 Number( b ); // NaN parseInt( b ); // 42 var c = '12.3333' parseInt( c ); // 12 parseFloat( c ); // 12.3333
!!
一元运算符 ! 显式地将值强制类型转换为布尔值,它同时还将真值反转为假值(或假值反转为真值)。
显式强制类型转换为布尔值最经常使用的方强制类型转换方法是 !!
,由于第二个 ! 会将结果反转回原值。
var a = "0"; var b = []; var c = {}; var d = ""; var e = 0; var f = null; var g; // undefined !!a; // true !!b; // true !!c; // true !!d; // false !!e; // false !!f; // false !!g; // false
value值 | Boolean()转换 | !!转换 |
---|---|---|
"" | false | false |
0 | false | false |
null | false | false |
undefined | false | false |
<span class="red">"0"</span> | <span class="red">true</span> | <span class="red">true</span> |
[] | true | true |
{} | true | true |
在 if(..).. 这样的布尔值上下文中,若是没有使用 Boolean(..) 和 !!,就会自动隐式地进行 ToBoolean 转换。
当 JavaScript 尝试操做一个 "错误" 的数据类型时,会自动转换为 "正确" 的数据类型。
5 + null // 返回 5 null 转换为 0 "5" + null // 返回"5null" null 转换为 "null" "5" + 1 // 返回 "51" 1 转换为 "1" "5" - 1 // 返回 4 "5" 转换为 5 "5" * true // 返回 5 "true" 转换为 1
当你尝试输出一个对象或一个变量时 JavaScript 会自动调用变量的 toString() 方法:
document.getElementById("demo").innerHTML = myVar; myVar = {name:"Fjohn"} // toString 转换为 "[object Object]" myVar = [1,2,3,4] // toString 转换为 "1,2,3,4" myVar = new Date() // toString 转换为 "Fri Jul 18 2014 09:08:55 GMT+0200"
数字和布尔值也常常相互转换:
myVar = 123 // toString 转换为 "123" myVar = true // toString 转换为 "true" myVar = false // toString 转换为 "false"
下表展现了使用不一样的数值转换为数字(Number), 字符串(String), 布尔值(Boolean):
原始值 | 转换为数字 | 转换为字符串 | 转换为布尔值 |
---|---|---|---|
false | 0 | ""false"" | false |
true | 1 | "true" | true |
0 | 0 | "0" | false |
1 | 1 | "1" | true |
"0" | 0 | "0" | true |
"000" | 0 | "000" | true |
"1" | 1 | "1" | true |
NaN | NaN | "NaN" | false |
"" | 0 | "" | false |
[ ] | 0 | "" | true |
function(){} | NaN | "function(){}" | true |
{ } | NaN | "[object Object]" | true |
null | 0 | "null" | false |
undefined | NaN | "undefined" | false |
Infinity | Infinity | "Infinity" | true |
-Infinity | -Infinity | "-Infinity" | true |
1 + '1' true + 0 {}+[] 4 + {} 4 + [1] 'a' + + 'b' console.log ( [] == 0 ) console.log ( ! [] == 0 ) console.log ( [] == ! [] ) console.log ( [] == [] ) console.log({} == !{})