之前一直有个想法,好好读完JS权威指南,便于自己对于JS有个较为全面的了解。毕竟本人非计算机专业出生,虽然做着相关行业的工作,但总觉得对于基础的掌握并没有相关专业学者扎实,正好因为辞职待业等原因,还是下定决心来好好读一读这本厚厚的‘词典’。在阅读原书过程中,本人也发现了不少概念问题,可能因为汉化区别,导致实际情况与概念描述并不相符的情况,这里就全当做下笔记了。
记录从书籍第三章开始,如果有幸有人看到了本人博客并对前两章有兴趣,可以通过其它途径去了解,这里就当权威指南概念的缩减版,以及作为自己待业中激励自己坚持下去的一种方式了。
3.类型、值和变量
Javascript的数据类型分为两类,原始类型(或基本类型),与对象类型(或引用类型)。
其中,原型类型包括数字,字符串,布尔值以及两个特殊的原始值null与undefined五类,对象类型就是常见的无序名值对{a:1,b:2},带编号的有序集合--数组[1,2,3,4],以及函数function ab(){xx}了。
---一个面试疑虑---
在面试中,曾遇到面试官提问,基本类型是哪几类,我在答完以上五类后,面试官表示我的答案是错的,基本类型还包括了object,因为null的类型是object,null被划入了基本类型,object也该划入,如下
问题来了的,难道书上写错了?直到我看到了NMD上的解释,明白原因了,这里直接引入:
typeof null === 'object'; // 从一开始出现JavaScript就是这样的
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于
null
代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null
就错误的返回了"object"
。
ECMAScript提出了一个修复(通过opt-in),但被拒绝。这将导致typeof null === 'object'。点击查看原文地址
由此可以知道,null类型为object只是因为早期js规范所导致的错误显示,null并没有对象的方法,而object有,所以object不该划入原始类型。
对象是属性的集合,每个属性都由名/值构成,值可以是原始值,比如数字{a:1},字符串{a:'nice'}之类,也可以是对象[{a:1},{b:2}]。
函数是具有与它相关联的可执行代码的对象,是类方法的封装体,调用函数可运行执行代码,并返回运算结果。
如果函数使用new运算符来初始化一个新建对象,这里称之为构造函数,每个构造函数定义了由构造函数初始化的对象组成的合集。对于new运算符的使用,我们除了可以new一个数组,new一个函数之外,我们还可以new一个日期Date,new一个正则表达式RegExp以及错误类Error.
垃圾回收站机制:js解释器都有自己的内存管理机制,可以自动对内存进行及时释放,当一个对象不被任何地方指引需要,解释器就会自动释放掉它,从而回收它所占用的内存资源。我们可以这样理解,在快餐店吃饭时,负责清理桌子的阿姨总会即使清理掉客人刚离开的桌子,方便后面的客人继续使用(内存释放)。
Javascript是一种面向对象语言,简单点说,我们不需要定义全局函数去操作不同的值,而是数据本身去使用方法,例如数组a排序,我们不需要将a传入到函数sort(),像这样sort(a);而是直接使用a调用方法,像这样a.sort(),在这里,a.sort()就是sort(a)的面向对象版本。
从技术上讲,只有JS对象才能拥有方法,但是数字,字符串以及布尔值也能有自己的方法,比如字符串转换,数组切割等等,在JS中只有null与undefined是没有方法可以使用的值。
我们在前面说,JS数据类型可以分为原始类型--字符串,数字,布尔,null,undefined和对象类型--函数,数组等,其实也可以分为拥有方法类型和不可拥有方法类型,上面说了,null和undefined是不可拥有方法,其余都可以;当然,我们还可以将数据分为可变类型和不可变类型,原型数据类型都不可变,对象类型可变,比如我们可以修改一个数组的长度,为它新增子元素等等。这里我们会纳闷,字符串不是也可以读取长度,获取以及替换字节吗,其实对于字符串的方法而言,所有字符串的操作都是返回的新变量,并非有修改原字符串,如下:
var str = 'string', str1 = str.replace('s','S'); console.log('修改前为'+str,'修改后为'+str1)
可以看到,原字符串并未被修改,类似的数字也一样,虽然有对应的方法,但这些方法并不是影响本身。
JS变量是无类型的,直白点,变量可以被赋予任何类型的值,在赋予一个类型值后也可以任意修改为其它类型的值,比如我申明一个变量var a= 1,此时变量a的值类型为数字,我们紧接着使用a='str',那么变量a的值类型由数字被替换成了字符串类型了。在JS中使用var来申明一个变量,在ES6中我们又知道了let以及常量申明const,这些后续再做描述。
JS采用词法作用域,变量分为全局变量与局部变量。不在任何函数体内申明的变量称之为全局变量,它在JS程序中的任意处都是可见可被调用的,例如:
console.log(num) var num =1;
输出为undefined,并不会报错,这里就牵扯到了变量提升。正如我们前面说,var num并未在函数体内申明,没有东西限制住它,虽然申明在了console后面,但是num是随处可见的,其实它的身影在整个程序中都是可被调用的,只是说num的赋值是在console后,但是num申明却可以被修改到任何位置,随处可见,随处可用。上面代码等同于
var num; console.log(num) num =1;
而局部变量就显得比全局变量要矜持的多,在函数体内神明的变量,它始终只能在函数体内可见,函数外部是没有权限访问这个变量的。如下:
function num(){ console.log(nummber) var nummber =1; } num();//undefined console.log(nummber)//报错
可以这样理解,函数num是一个小世界,变量number相对于函数num而言是可以任意调用的,但在函数体外,我们是无权直接访问使用这个变量的。