这是一篇读书笔记
出自《你不知道的JavaScript中卷》
一:类型
1、七中内置类型
Number、String、Boolean、Object、Undefined、Null、Symbol
除对象外,其他统称为“基本类型”
2、typeof运算符
typeof 1 // "number"
typeof '1' // "string"
typeof true // "boolean"
typeof {} // "object"
typeof undefined // "undefined"
typeof Symbol() // "symbol"
typeof function(){} // "function"
typeof null // "object"
typeof [] // "object"
判断null
var a = null
!a && typeof a === 'object'
typeof运算符总会返回一个字符串
typeof typeof 42 // string
3、undefined和undeclared
undefined: 声明未赋值
undeclared: 未声明
var a;
a; // undefined
b; // ReferenceError: b is not defined
二:值
1、数组
- 可以容纳任何类型的值;不需要预先设定大小。
- 使用delete可以删除数组中的元素,但是length属性不变:
var a = [1,2,3]
delete a[2] // [1, 2, empty]
a.length // 3
- 可以包含字符串键值和属性,但这些不计算在数组长度内
var arr = [1]
arr['name'] = 'ming'
arr.length // 1
arr // [1, name: "ming"]
- 如果字符串的键值能够被强制转换成十进制数字的话,会被当做数字索引:
arr['10']=3
arr.length // 11
2、类数组
2.1 类数组的定义:
- 拥有length属性,索引为非负整数;
- 不具有数组所具有的方法;
2.2 常见的类数组有
arguments对象和 DOM方法的返回结果(document.getElementsByTagName())。
2.3 将类数组转为数组:
1)通过数组工具函数 Array.prototype.slice.call(arguments)
2)Array.from(arguments)
3、字符串
字符串是不可变的,创建并返回一个新的字符串;
数组是在原始值上进行操作。
var a = 'foo'
var b = ['f', 'o', 'o']
d = a.toUpperCase()
a === d // false
b.push('!')
b // ["f", "o", "o", "!"]
4、数字
- 特别大和特别小的数字默认用指数格式显示
var a = 5E10
a // 50000000000
var b = 1/a
b // 2e-11
- .运算符会被优先识别为数字字面量的一部分
42.toFixed(2) // SyntaxError 视为42.的一部分
(42).toFixed(2) // "42.00"
0.42.toFixed(2) // "0.42"
42..toFixed(2) // "42.00" 第一个.是42.的一部分;第二个.属性访问运算符
- 进制
0b // 2进制
0o // 8进制
0x // 16进制
- 较小的数值 -- 不精确
0.1 + 0.2 === 0.3 // false
- 怎么判断0.1 + 0.2 === 0.3?
设置一个误差范围-机器精度:
if(!Number.EPSILON){
Number.EPSILON = Math.pow(2,-52)
}
function compareEqual(a,b){
return Math.abs(1-b) < Number.EPSILON
}
var a = 0.1 + 0.2
var b = 0.3
compareEqual(a,b) // true
compareEqual(0.0000001,0.0000002) // false
- 整数的安全范围:Number.MIN_SAFE_INTEGER ~ Number.MAX_SAFE_INTEGER。
整数检测、安全整数检测:
Number.isInteger(42) // true
Number.isSafeInteger(Math.pow(2, 53)) // false
Number.isSafeInteger(Math.pow(2, 53) - 1) // true
- 不是数字的数字NaN:
var a = 1/'a'
a // NaN
typeof a // "number"
NaN == NaN // false 跟自身不相等
isNaN(a) // true
if(!Number.isNaN){ // 唯一一个不等于自身的值
Number.isNaN = function(n){
return n !== n
}
}
- 零值
var a = 0/-3 // -0
为什么需要-0呢?数字的符号代表其他信息:移动的方向
- 特殊等式
var a = 1/'name'
var b = -3 * 0
Object.is(a, NaN) // true
Object.is(b, -0) // true
Object.is(b, 0) // false
6、值和引用
简单值-基本类型值:通过值复制的方式来赋值/传递(null、undefined、字符串、数字、布尔值、symbol);
复合值-对象(数组和封装对象)和函数:通过引用复制的方式来赋值/传递。
三:原生函数
1、常见原生函数
String()
Number()
Boolean()
Array()
Object()
Function()
RegExp()
Date()
Error()
Symbol()
封装了基本类型的封装对象:
var a = new String('abc')
typeof a // "object"
a instanceof String // true
Object.prototype.toString.call(a) // "[object String]"
2、封装对象包装
JS会自动为基本类型值包装一个封装对象
var a = 'abc'
a.length // 3
a.toUpperCase() // "ABC"
3、拆封
想要得到封装对象的基本类型值,可以使用valueOf()函数
var a = new String('a')
var b = new Number(1)
var c = new Boolean(true)
a.valueOf() // "a"
b.valueOf() // 1
c.valueOf() // true
Array构造函数只有一个参数时,会被作为数组的预设长度:
var arr = Array(10)
arr // (10) [empty × 10]
-- 至少包含一个空单元的数组称为稀松数组。
4、Symbol
符号-Symbol是具有唯一性的特殊值,用它命名对象属性不容易导致重名。
5、原生原型
String.prototype.XYZ可以简写为String#XYZ。
String#indexOf(...) 查找字符串中指定字符串的位置。
String#charAt(...) 获得字符串指定位置上的字符。
String#substr(...)/String#substring(...)/String#slice(...) 获得字符串的指定部分。
以上方法不改变原字符串的值,返回新的字符串。
四:强制类型转换
1、值类型转换
类型转换:将值从一种类型转换为另一种类型。
var a = 42
var b = a + '' // 隐式
var c = String(a) // 显式
2、抽象值操作
2.1 toString:会调用Object.prototype.toString()方法
var a = 1.1 * 1000* 1000* 1000* 1000* 1000* 1000* 1000
a.toString() // "1.1e+21"
数组的toString()方法进行了重新定义,先用,连接
var a = [1,2,3]
a.toString() // "1,2,3"
JSON.stringify()在对象中遇到undefined、function、symbol会忽略;
对包含循环引用的对象执行JSON.stringify()会报错。
JSON.stringify()可选参数replacer:
var a = {b: 42, c: "42", d: [1,2,3]}
JSON.stringify(a, ['b', 'c']) // "{"b":42,"c":"42"}" ,除'b'\'c'属性外忽略
JSON.stringify(a, function(k,v){if(k!=='c') return v}) // "{"b":42,"d":[1,2,3]}" 对对象本身调用一次
JSON.stringify()另一个可选参数space,指定输出的缩进格式:
JSON.stringify(a, null, 3)
"{
"b": 42,
"c": "42",
"d": [
1,
2,
3
]
}"
JSON.stringify(a, null, '---')
"{
---"b": 42,
---"c": "42",
---"d": [
------1,
------2,
------3
---]
}"
2.2 toNumber
Number(true) // 1
Number(false) // 0
Number(undefined) // NaN
Number(null) // 0
对象(包含数组)首先会被转换成响应的基本类型;如果返回的是非数字,再将其强制转换为数字。
先检查valueof()方法;再检查toString()方法,如果均不返回基本类型,则报错。
var a = {valueOf: function(){return '42'}}
var b = {toString: function(){return '42'}}
var c = [4,2]
c.toString = function(){return this.join("")}
Number(a) // 42
Number(b) // 42
Number(c) // 42
Number('') // 0
Number([]) // 0
Number(['abc']) // NaN
Number(['42']) // 42
2.3 toBoolean
假值
Boolean(undefined) // false
Boolean(null) // false
Boolean(false) // false
Boolean('') // false
Boolean(0) // false
Boolean(NaN) // false
假值列表以外的都是真值。
假值对象:
var a = new Boolean(false)
var b = new Number(0)
var c = new String('')
var d = Boolean(a && b && c) // true
3、显示强制类型转换
字符串和数字间的转换:
var a = 2
String(a) // "2"
var b = '1'
Number(b) // 1
var c = +b
c // 1 一元运算符
~运算符:~X 即 -(X+1)
var str = 'abcd'
~str.indexOf('bc') // -2
~str.indexOf('cb') // 0
显式解析数字字符串
var a = '22px'
parseInt(a) // 22
Number(a) // NaN
解析允许字符串中有非数字字符;
转换不允许,否则会失败并返回NaN。
parseInt(string, radix) 解析一个字符串并返回指定基数的十进制整数, radix 是2-36之间的整数,表示被解析字符串的基数。
parseInt(11, 2) // 3
解析非字符串
parseInt(1/0, 19) // 18
// 即:
parseInt(Infinity, 19) // 18
显式转换为布尔值
Boolean('0') // true 显式
Boolean('') // false 显式
!!'0' // true 显式
!!'' // true 显式
if('0'){...} // if语句中
var a = 42? true: false // 三元运算符
4、隐式强制类型转换
• 作用是为了减少冗余,让代码更简洁
• 字符串与数字之间的隐式强制类型转换
var a = 1
var b = '1'
var c = a + b
c // "11"
var a = [1,2]
var b = [3,4]
var c = a + b // '1,2' + '3,4' => 1,23,4
c // "1,23,4"
一个常见的坑:
[]+{} // "[object Object]" => '' + "[object Object]"
[]+[] // "" => '' + ''
{}+[] // 0 => 代码块 +'' => 代码块 0
{}+{} // "[object Object][object Object]"
其他: - * /
var a = '1'
a-0 // 1
var a = '2'
a*1 // 2
var a = '3'
a/1 // 3
• 布尔值到数字的强制类型转换
// 判断条件a/b/c/d/e只有一个为真时
function(a,b,c,d,e){
var sum = 0
// 将条件转为数字,true=>1; false=>0,如果sum为1则符合条件
return sum===1
}
• 转换为布尔值
if(...) // 语句
for(..., ..., ...) // 第二个判断条件
while(...) 和 do...while(...) // 表达式
? ... : ... // 三元运算符
|| 和 && // 逻辑或、逻辑与
• 选择器运算符 || &&:返回的是两个操作符中的一个
var a = 22
var b = null
a || b // 22
a && b // null
5、宽松相等和严格相等
• '==' 和 '===' 相比:允许在比较中进行强制类型转换
• 字符串和数字之间的比较
var a = 2
var b = '2'
a == b // true 将string转为number
• 其他类型和布尔类型之间的比较
var a = '2'
var b = true
a == b // false, 因为b会转为1。如果是布尔类型,则ToBumber(布尔)
• null和undefined之间的相等比较
null == undefined
• 对象和非对象之间的相等比较
var a = 2
var b = [2]
a == b // true 对象会调用ToPrimitive(...)
• 比较少见的情况
[] == ![] // true (![]=>false) => ([] == false) => true
0 == '\n' // true
0 == ' ' // true 会被转成0