- 空值(null)
- 未定义(undefined)
- 布尔值(boolean)
- 数字(number)
- 字符串(string)
- 对象(object)
- 符号(symbol,ES6 新增)
除对象外,其他属于统称基本类型了。
null 有点特殊, typeof对它的处理有点问题:正确的返回结果应该是 null,但这个 bug 由来已久,也许永远不会恢复,因为牵扯到太多的 Web系统,“修复”它会产生更多 bug。
typeof function a(){} ==> “function”
Function 函数,实际上 object 一个”子类型“ 函数是“可调用对象”。它有个内部属性 [[call]] ,该属性使它可以被调用。
函数不仅是对象,还有属性 比如 length
数组也是对象确切地说,它是 object 的一个 “子类型”
delete
使用 delete删除数组元素要注意,数组属性length 不会发生改变。
在稀缺数组(含有空白单元的数组)空白数组可能会导致出人意料的结果。
数组也是对象,当包含字符串键值和属性的时候,(不计算在数组长度中。)
值得注意的是当字符串键值可以强制类型转换为 10进制数字的时候,它是会当成数字索引来对待。
字符串
JS 中的字符串和字符数组并不是一回事,只是看上去相似。
它们都是类数组,都有 length 属性 以及 indexoF concat 方法。
字符串不可变是指字符串的成员函数不会改变原始值,而是创建并返回一个新的字符串,数组成员函数都是在原始值上操作··
let a = '123';
c = a.toUpperCase();
a === c //false
虽然字符串没有这些函数但字符串可以“借用”数组的非更方法处理字符串。
let a = '123';
let c = Array.protoype.join.call(a,'-')
数组
JavaScript 引用指向的是值,如果一个值有 10 个引用,这些引用指向的都是同一个值,它们相互之间没有什么关系。
let a = ['123'];
let b = a;
b.push('4');
console.log(a,b) // ['123','4'] ['123','4']
b a 是[‘123’] 的两个不同引用,它们仅仅是指向值,而不是持有,当 push,它们都将指向新值 [‘123’,'4]
let a = ['123'];
let b = a;
b= ['345']
console.log(a,b) //123 345
引用指向的是值,而不是变量,所以一个引用无法更改另外一个引用的指向。
原生函数
常见的原生函数有:
- String()
- Number()
- Boolean()
- Array()
- object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()
构造函数
var a = new Array(3);
console.log(a.length) //3
构造函数Array 不要求必须带 new 关键字,Array 构造函数只带一个数字参数时,该参数会被作为数组的预设长度(length)。
var a = new Array(3);
var b = [undefined,undefined,undefined]
在谷歌浏览器中。
Symbol
基本数据类型 --符号(Symbol).符号是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。不是对象
var a = Symbol("abc") //不带new
var sol = Symbol('hello');
var a = {};
a[sol] = 'foobar';
JavaScript 为基本数据类型值提供了封装对象,称为原装函数(如 string,Number,Boolean)等.它们为基本数据值提供了该子类型所特有的方法和属性(如:String#trim()和Array#concat())
强制类型转换
值类型转换
将值从一种类型转换为另一种类型通常称为类型转换,这是显示的情况,隐式的情况称为强制类型转换
var a = 42;
var b = a + '';//隐式强制类型转换
var c = String( a );//显示强制类型转换
JSON.stringify(undefined) undefined
JSON.stringify(null) null
JSON.stringify(function(){}) undefined
JSON.stringify([1,undefined,function(){},4]) // [1,null,null,4]
JSON.stringify({a:2,b:undefined,c:function(){},undefined,c:['123']}) //{"a":2,"c":["123"]}
JSON.stringfy(…) 在对象中遇到 undefined,function,和 symbol 时会自动将其忽略,在数组中则会返回 null (以保证单元位置不变)。
对包含循环引用的对象执行 JSON.stringfy() 会出错。
如果要对非法JSON值对象做字符串化,或者对象中的某些值无法被序列号,就需要定义 toJSON() 方法来返回一个安全的 JSON值
var o = {}
var a = {
c:1,
b:'123',
d:['123'],
o:a,
toJSON:function(){
return {c:this.c}
}
}
o.e = a;
console.log( JSON.stringify(a))
toJSON 是个自定义的方法,它只是帮我们返回一个适当的值,或者是我们想要的值,然后再用 JSON.stringfy() 对其进行字符串化。
**我们可以向 JSON.stringfy() 传递一个可选参数,它可以是数组,或者是函数 **
如果是数组,那么它必须是一个字符串数组,包括序列号处理的对象名称。除此之外其他的属性则被忽略。
如果是函数,它会对对象本身调用一次,然后对对象中的各个属性各调用一次,每次传递两个参数,键和值。如果要忽略某个键就返回 undefined,否则返回值得的值。
var a = {
c:1,
b:'123',
d:['123']
}
console.log(JSON.stringify(a,['c','b']))
console.log(JSON.stringify(a,function(v,h){
if(v !== "c"){
return h
}
}))
JSON.stringify 还可以传递第三个参数
console.log(JSON.stringify(a,null,"---"))
{
---"c": 1,
---"b": "123",
---"d": [
------"123"
---]
}
JSON.stringify() 并不是强制类型转换。在这里介绍是因为它涉及 ToString 强制类型转换。
- 字符串,数字,布尔值和 null 的JSON.stringfy() 规则与 ToString 基本相同。
- 如果传递 JSON.stringfy() 的对象中定义了 toJSON() 方法,那么该方法会在字符串化前调用,以便将对象转换为安全的 JSON 值。
toBoolean
JavaScript 有两个关键词 true,false,分别代表布尔类型的真和假,我们常误以为数值 1 和 0 分别等同与 true 和 false。在有些语言可能是这样的,但在 JavaScript 中布尔值和数字是不一样的。
var a = new Boolean(false);
var b = new Number(0);
var c = new String("");
字符串和数字之间的显示转换
var a = 42;
var b = a.toString();
a.toString()是显示的,不过其中涉及隐式转换。因为 toString() 对42 这样的基本数据类型不适用,所以 JavaSctipt 引擎会自动 42 创建一个封装对象,然后对该对象调用 toString()。这里显式转换中含有隐式转换。
小方法
我们常用下面的方法来获得当前的时间戳:
var time = +new Date();
不过最好还是使用 ES5 中新加入的静态方法 Date.now()
var a = 42;
if(Boolean(42)){
console.log('123')
}
建议使用 Boolean 和 !! 来进行显示强制类型转换。
逻辑运算符 || 和 &&
逻辑运算符 ||或 &&与 ,在 JavaScript 中的表现有一些非常重要但却不太为人所知的细微差别。
我其他不太赞同将它们称为 “逻辑运算符”和 “选择器运算符”
为什么? 因为和其他语言不同,在 JS 中它们返回的并不是布尔值。
&& 和 || 运算符的返回值并不一定是布尔类型,而是两个操作数其他一个的值。
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就返回第一个操作数 (a,c)的值
&&则相反
符号的强制类型转换
symbol 不能被强制类型转换为数字,会报错,但是可以被强制类型转换为布尔值。
宽松相等 和 严格相等
**常见的误区是 “== 检查值是否相等” === 检查值和类型是否相等。**听起来蛮有道理的,然而不够准确,很多的 JavaScript 书籍和博客也是这样来解释的,但是很遗憾他们都错了
👂这是不是在说我 =-=
正确的解释是: == 允许是相等比较中可以进行强制类型转换, === 是不允许
相等比较操作的性能
两种解释
- === 似乎比 == 做的事情更多,因为它还要检查值的类型。
- == 的工作量更大一些,因为如果值的类型不同还需要进行强制类型转换
如果进行比较的两个值类型相同,则 == 和 === 使用相同的算法,所以除了 JavaScript 引擎 实现上的细微差别之外,它们之间并没用什么不同。
如果两个值的类型不同,我们就需要考虑有没有强制类型转换的必要,有就用 ==,没有就3个 = ,不用在乎性能。
== 最容易出错的地方
var a = "32";
var b = true;
a == b //false
我们都知道 "32"是一个真值,为什么 == 的结果不是 true 呢 ? 原因既简单又复杂,让人很容易掉坑里,很多 JavaScript 开发人员对这个地方并未引起足够的重视。
- 如果 type(x) 是布尔类型,则返回 ToNumber(x) == y的结果
- 如果 type(y)是布尔类型,则返回 x == ToNumber(y) 的结果
b 强制类型转换为 1 , a 强制类型转换为 32 1 == 32 //false
不要这样判断
var a = '32';
if( a ==true )
if ( a === true )
if (a)
if(!!a)
if(boolean(a))
null 和 undefined 之间的相等比较
null 和 undefined 之间也涉及隐式类型转换
null == undefined // true
undefined== null //true
在 == 中,null 和 undefined相等,它们与其自身相等,除此在外,它们与其它值都不相等
对象和非对象之间的比较
var a = 42;
var b = [42];
a ==b ;// true
[ 42 ] 首先会调用 ToPrimitive 抽象操作, 返回 “42” “42” == 42 然后 42 == 42
ToPrimitive 抽象操作 特性(toString,valueOf)
**关于显式和隐式就介绍到这里了,总结 **
==是相等比较下允许使用强制类型转换,三个=是不允许
这为一篇,因为 《《你不知道的JS》》中册有 358页,也算很厚的了,所以我是打算分为 4 篇来做,本人只是记录一些我比较感兴趣的知识,和一些我知识点的错误,推荐大家还是看原书。