打算从基础开始复习JavaScript,
顺便分享总结一下自己学过的知识
内置类型
JavaScript中有七种内置类型,包括六种基本类型和一种引用类型
-
基本类型
- number(数字)
- string(字符串)
- boolean(布尔值)
- undefined(未定义)
- null(空值)
- symbol(符号)【ES6规范新增】
-
引用类型
- object(对象)
注意:array数组与function函数是特殊的对象,也就是说他们是对象的“子类型”同样为引用值
其中基本类型是保存在栈内存中的简单数据段,在内存中有固定的空间
引用类型是保存在堆内存中的对象,按引用访问,栈内存保存着指向对象的指针(存有对象的访问地址)
之所以在内存中分堆栈,是因为它与浏览器的垃圾回收机制有关,保证运行时占内存最小
上面的话没看懂也不要紧,只要知道基本类型是栈数据,引用类型是堆数据就可以了
typeof运算符
说成是typeof操作符也可以,操作符运算符指的是同一个东西
通过这个typeof我们可以查看值类型
它返回类型的字符串(小写英文),但并不是所有类型它都能鉴别
console.log(typeof 123);// "number"
console.log(typeof '123');// "string"
console.log(typeof true);// "boolean"
console.log(typeof undefined);// "undefined"
console.log(typeof Symbol());// "symbol"
console.log(typeof null);// "object" <-注意看这里
console.log(typeof {demo: 123});// "object"
我们把这七种类型打印到控制台发现了问题
typeof null 居然返回“object”
嗯跟我们预想的不太一样啊
说好的返回“null”的呢
其实这是一个历史遗留问题,这个bug存在了二十多年了(比我岁数还大)
大概永远也不会修复了,因为它牵扯太多Web系统了,“修复”它的代价不可想象
不过我们可以这样判断null空值类型
var foo = null;
if(!foo && typeof foo === 'object'){
console.log('这是一个空值...');
}
因为无论什么对象,即便空对象,转换为布尔值都是true(以后我写类型转换的时候再说)
所以可以这样判断null,不过我好像没用过
回到typeof的问题上来,我们还发现了一个问题
console.log(typeof function(){});// "function"
typeof对于JavaScript中的一等公民 —— 可执行对象 —— 函数有着特别的待遇
所以虽然函数是对象,但是typeof操作符可以区分并且返回“function”
至于函数为什么可以调用,是因为它有一个内部属性[[call]],所以是“可调用对象”,以后再说
哦对了,虽然数组也是特殊的对象,但是typeof不认识它
想要区分数组,可以看看我写的如何鉴定数组
所以typeof返回值有这些字符串
number、string、boolean、undefined、object、function、symbol
既然说到了typeof,还有一个小知识点
console.log(typeof NaN)// "number"
同样容易出错,面试题可能会有
不过这可不是什么bug
非数NaN英文 Not a Number ‘不是一个数字’
那么也就是说:不是数字的数字是数字
看蒙没,没关系
现在只要记住NaN是number类型就好了
哦对了补充一句突然想起来的
typeof虽然可以这么用typeof(a + b)
但是它 不是函数 不是函数 不是函数(重要的事情说三遍)
而是一个一元运算符,切记
上面的用法只是对表达式中操作数运算的结果的类型检查
值与类型
这里我说明一个这样的问题
JavaScript中,变量没有类型,值才有类型
typeof操作符返回的也是变量所持有值的类型的字符串
因为我们是弱类型语言
所以我们可以改变变量持有值的类型
var foo = 123;
console.log(typeof foo);// "number"
foo = true;
console.log(typeof foo);// "boolean"
foo = 'abc';
console.log(typeof foo);// "string"
虽然变量值类型可以变,但是我们写项目时千万不要这么做
我们可以给变量加前缀或者加特殊符号让我们记得自己声明的是什么类型的变量
比如,retArr,bFlag,strLen之类的
typeof undeclared
这个undeclared当然是不存在的关键字
不过我为什么要这么写呢
来看一个问题
console.log(foo);
我没定义foo就打印,于是
果不其然,浏览器蒙圈了
给大家翻译成中文:未捕获引用错误: foo没有定义
可能大家都不会去注意,其实这是很容易让人误会的
在这了 is not defined != is undefind
因为我连声明都没声明,怎么谈定义
所以如果浏览器报出is not declared或许更准确
我们暂且把这种连定义都没定义的变量看作“undeclared”变量
但是对于这种“undeclared”未定义的变量,typeof有特殊的安全防范机制
console.log(typeof foo);// "undefined"
出乎意料的,它对于undeclared变量并没有报错,而是返回了“undefined”
虽然我们觉得它返回“undeclared”更容易理解一些(我们的要求太高了)
其实它没有报错就相当不错了
这种容错对于我们来说还是很有帮助的
比如说我们想知道全局空间有没有变量foo
if(foo){ //若不存在会报错
//...
}
if(typeof foo !== 'undefined'){ //不存在也不会报错
//...
}
if(window.foo){ //不存在同样不会报错
//...
}
最后一种通过window对象调用与undeclared变量不同
访问不存在的对象属性是不会报错的,而是返回undefined(是类型而不是字符串)
不过如果我们全局对象不是window的话,就不能使用这种方法了(比如,node.js)
总结
JavaScript内置类型:
- 基本类型(栈数据):number、string、boolean、undefined、null、object、symbol(ES6规范新增)
- 引用类型(堆数据):object
typeof操作符返回值:
- “number”
- “string”
- “boolean”
- “undefined”
- “object”
- “function”【sp】
- “symbol”
typeof null -> “object” 历史遗留bug
typeof NaN -> ‘number’ 注意
变量没有类型,其持有值有类型
typeof的容错机制可以用来检查undeclared(未声明)变量