7种内建类型
null / undefined / object / number / string / boolean
ES6 新增了一个 symbol 类型
typeof 操作符 (7个值)
返回的也是7个值,typeof 总是会返回字符串:
typeof undefined === 'undefined'
typeof 42 === 'number'
typeof '42' === 'string'
typeof { life: 420 } === 'object'
typeof true === 'boolean'
//ES6 新增的
typeof Symbol() === 'symbol'
//但是 typeof null 的结果 是令人吃惊的
typeof null === 'object'
所以我们判断null的时候不能简单的这样判断,需要像下面这样:
const a = null
const isNull = !a && typeof(a) === 'object'
但是并不如像上面说的那样 typeof 有7个值,只有6个,除了null的都有,我们看下第七个是什么:
typeof function test(){} === 'function'
javascript里面,变量没有类型,值才有。 变量在任何时候,持有任何值。
证明typeof返回的是一个字符串, 安全的防范机制,typeof var
无论var是否声明都不会报错,阻塞程序
typeof typeof 66 === 'string'
还有一个特殊的情况:
typeof NaN === 'number'
数组的小坑
数组也是对象,可以添加属性
const a = []
a[0] = 0
a['name'] = 'arr-name'
console.log(a) // [0, name: "arr-name"]
console.log(a.length) // 1
a['0'] = 'zero'
console.log(a) // ["zero", name: "arr-name"]
console.log(a.length) // 1
类数组的操作
比如DomList 我们需要对其做一些过滤操作什么的,但是它只是一个类数组【索引为数字,并且可以遍历】
// 在chrome控制台下可以做实验
var tempDomList = document.getElementsByTagName('ul')
// 我们是可以tempDomList[0]去获取第一个ul标签元素,但是没法使用数组的方法
我们以前是Array.prototype.METHOD.call(arr, params)…
比如想使用find方法这样使用:
const specialUl = Array.prorotyle.find.call(
tempDomList,
(item)=>{item.className.includes('special-class')
})
现在可以直接使用 Array.from(类数组对象)
Array.from(temp).find((item)=>{
item.className.includes('special-class')
})
小数的坑
因为0.1 和0.2 js里面,二进制表示也是不精确的,两个错误的值相加,肯定不会等于一个正确的值。
对所有使用IEEE754的语言的,都存在这个问题。
0.1 + 0.2 === 0.3 // false
NaN
注意: NaN === NaN 的结果是false
还有一个方法:isNaN
isNaN 的本意是判断值是否是 NaN , isNaN(NaN) 的结果是true
但是isNaN(‘foo’) 的结果也是true
这个bug在ES6 用新的方法来解决了: Number.isNaN
装箱
和 java有点类似,基础数据类型和包装类型,比如我们定义一个字符串:
var str = "kevin"
执行
str.length()
实际上js会自动封箱。
但是比如你想自己手动装箱,比如这样
const flag = new Boolean(false)
if(!flag) {
console.log('come here') //actualy never come here
}
开箱 或者拆箱
比如你有一个包装器对象,想取去底层的基本类型值,你可以使用valueOf方法。valueOf MDN地址在这里: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
const a = new String("str")
a == "str" // true
a ==== "str" // false
valueOf 可以构造一个比较奇怪的例子,当然仅限于 ==
运算符 :
const a = { name: "kevin", valueOf: "$2000M" }
a == "$2000M" // true
a === "$2000M" // false
JSON.stringify
基础类型直接转换为字符串
JSON.stringify(null) // "null"
JSON.stringify(true) // "true"
JSON.stringify(42) // "42"
JSON.stringify("42") // ""42""
当JSON.stringify()遇到 undefined function(){} symbol的时候 会自动忽略他们。
如果它们出现在对象里面,这些属性会自动的被忽略,请看例子:
const obj = {
name: undefined,
sayHi: function(){ console.log('hello') },
id: Symbol('Kevin')
}
console.log(JSON.stringify(obj))
// 输出的结果是 "{}"
如果它们出现在数组里面,这些值会被替换为null,请看例子:,请看例子:
const arr =["kevin", undefined, Symbol("kevin"), function(){}]
console.log(JSON.stringify(arr))
// 输出的结果是 "["kevin",null,null,null]"
有时候我们有这样的需求,需要将转换后的字符串格式化,加上换行/ 或者说只打印出想要的结果,这时候需要加上第二个参数和第三个,这个请直接移步 MDN-JSON.stringify
留意如果转换的目标有toJSON方法,那么这个方法首先会被调用,然后将该方法返回的值,作为序列化的参数。
布尔类型
被强制转换为boolean,然后结果是false 只有极少数,他们是
+0, -0, NaN
null, undefined
false
""
document.all
//dom对象
参考(MDN-Boolean)[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Boolean]
强制将其他数据类型转换为布尔类型,可以使用Boolean(xx),但是太繁琐,可以使用!!双否定操作符。
String <-> Number;String和Number的转换
数字转字符串
const a = 42
const aStr1 = a.toString()
const aStr2 = a + ''
字符串到数字
const a = "42"
const numberA = + a
const b = "42"
const numberB = b - 0
// 因为 - 仅为数字减法定义的,所以b - 0 强制b的值转换为数字。
// 当然用 b / 1 或者 b * 1 都是可以的。
对数组做一个减法操作
var a = [3]
var b = [1]
a - b // 结果是 2
两个数组因为 - 减号运算符必须转换为number,但是他们首先会被强制转换为string(使用toString()序列化),然后再强制转换为number。所以最后的结果是2。
转换为字符串的明确转换是这个
String(youVariable)
转换为字符串隐式转换是这个
yourVariable + ""
按照上面的数组来举例:
var a = [3]
a.toString() // "3"
String(a) // "3"
a + "" // "3"
这里有分割线,看了上面几个点,你可能以为String(a)
和a + ""
的结果是一样的,但是实际上内部使不同的。
a + ""
现在a值上面调用valueOf()
方法 然后调用toString()
方法
String(a)
是直接调用的toString()
方法
证明:
const a = {
valueOf: function() { return 42 },
toString: function() { return 4 }
}
a + "" // "42"
String(a) // "4"
so…
but 这里还有一个
[] + {} // "[object Object]"
{} + [] // 0
学不动了… 不学了!
真香分割线
比较:任何值与boolean
var a = "42"
var b = true
a == b // 肯定是false, 是的和你认为的一样 都是false
// 但是
a == false // 也是false
// 但是 + 1
// 会进入if语句
if(a) {
console.log("come here !")
}
首先我们来看这个a==b
如果typeOf(a)是Boolean,会返回ToNumber(a)==b的结果,对b来说也是这样,所以知道了吧?
然后我们看if语句,实际上if语句里面做了一个隐式转换。
// 隐式转换
if(a) {
//...
}
// 明确转换 * 1 强烈推荐~~~~
if(!!a) {
//...
}
// 明确转换 * 2
if (Boolean(a)) {
//...
}
比较:非object 与 object
如果一个 object / function / array 被与一个简单基本标量(string, number, boolean)进行比较。
ES5规范中是这样说的:
如果 Type(x)是一个String 或者Number而 Type(y)是一个Object,返回比较x == ToPrimitive(y)
的结果。
如果 Type(y)是一个String 或者Number而 Type(x)是一个Object,返回比较y == ToPrimitive(x)
的结果。
但是我们没有说Boolean的情况,你看我们上一点,已经说了Boolean的情况,这里就不在讨论。
所以就会有下面的结果:
var arr = [42]
arr == 24 // true
var obj = { valueOf: function() { return 42; } }
obj == 42 // true
请注意valueOf 和 toString方法。前面我们说了拆箱
,就是一个基本类型值的object包装器(例如new String(‘abc’)这样的形式)被展开,其底层的基本类型值(‘abc’)被返回。这种行为与 == 算法中的ToPrimitive强制转换有关:
var a = "abc"
var b = Object(a)
a === b // false
a == b // true
// 这里a == b 是true,是因为b通过ToPrimitive强制转换为
// 它的底层简单基本标量值 "abc", 它与a中的 "abc"是相等的。
这里a == b 是true,是因为b通过ToPrimitive强制转换为 它的底层简单基本标量值 “abc”, 它与a中的 "abc"是相等的。
但是 ==
也会存在意外的情况,上面说的拆箱情况也有例外。考虑下面的代码:
var a = null
var b = Object(a) // 与 Object() 相同
a == b // false
var c = undefined
var d = Object(a) // 与 Object() 相同
c == d // false
var e = NaN
var f = Object(e) // 与 new Number(e) 相同
e == f // false
重点:
值 null 和 undifiend 不能被装箱,他们没有等价的对象包装器。 所以Object(null), Object(undefined) 和 Object()一样,他们都仅仅产生一个普通对象。
NaN是可以被封箱到它等价的Number对象包装器中,但是拆箱之后NaN==NaN是false。
基于valueOf做奇怪的操作
我们已经知道了将一个对象和一个基本数据类型做 ==
比较,实际上对这个object做了一次拆箱操作,然后再做比较。
所以才会有下面的这些结果:
var a = ["42"]
a == "42" // true
var a = { valueOf: () => "42" }
a == "42" // true
因为拆箱动作是调用了一个函数,这个函数我们可以控制,所以我们可以做到怪戾的操作,看下面的代码。
if (a == 2 && a == 3) {
console.log("come here")
}
实际上是可以进入到if语句内部的,在知道valueOf之前,我是一脸懵逼的,但是我们可以用valueOf来达到这个效果。
var a = {
value: 1,
// 这里用箭头函数会报错,因为箭头函数内部this,指的是window
valueOf: function() {
this.value = this.value + 1;
return this.value
}
}
if ( a == 2 && a == 3 ) {
console.log('yep. come here ')
}
还有另外一个例子, 但是请永远不要在业务代码做这些骚操作:
Number.prototype.valueOf = function() {
return 3;
}
new Number(2) == 3 // true
一个对象转为原始值,可以调用toString, 也可以调用valueOf方法,valueOf的优先级高于toString()
** 还有一个优先级高于上面两个方法的设定 Symbol.toPrimitive**
var a = {
toString() {
return 12
}
}
a + 1 ;
var a = {
toString() {
return 12
},
valueOf() {
return 13
}
}
a + 1;
分割线,第五章文法的笔记较少,看了表达式的一堆概念性的东西。。
{} + [] 和 {} + [] 的区别
在前面我们说到了这两个表达式的值的结果:
{} + [] // 0
[] + {} // "[object Object]"
为什么会有这样的结果。
点击这个链接
浏览器环境下个定义一个有合法id的dom元素
我们可以直接通过id,来获取到这个dom元素。