1.JavaScript规定了几种语言类型
首先明确ECMAscript中的数据类型分为两种:基本类型和引用类型
基本类型:即简单的数据段,都是按值访问的,即将一个基本类型的数据赋值给另外一个变量,是通过将原数据拷贝一份赋值的,两变量之间互不影响。基本类型有:Undefined,Null,Boolean,Number,String;
引用类型:即保存在堆内存中的对象,按引用访问,即将一个引用类型的地址赋值给另一个变量,当该变量改变时,原变量也会随之改变。
引用类型有object,Array,Date(日期),RegExp(正则),Function
7种类型:undefined、null、String、Boolean、number、symbol、object
undefined:undefined类型表示未定义,它的值只有一个:undefined
任何变量赋值前都是undefined类型,值为undefined(而不是null)
undefined是一个变量,而非一个关键字
拓展:为什么有的编程规范要求使用void 0 代替undefined
因为undefined是一个变量,而非一个关键字,如果需要一个undefined类型,为了防止后面被改掉,所以使用void 0来代替
null:只有一个值,就是null,表示空值,是关键字,可以放心使用null关键字来获取null值。从逻辑上来讲,null其实是一个空对象指针,所以调用typeof才会返回object。
number: JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则,但是 JavaScript 为了表达几个额外的语言场景(比如不让除以 0 出错,而引入了无穷大的概念),规定了几个例外情况:
拓展:
NAN,Infinity(无穷大),-Infinity(无穷小)
NaN:是一个全局对象的属性,NaN如果通过 == 、 != 、 === 、以及 !==与其他任何值比较都将不相等 – 包括与其他 NAN值进行比较,
必须使用 Number.isNaN() 或 isNaN() 函数来判断它是不是NaN
拓展:为什么在 JavaScript 中,0.1+0.2 不等于0.3
因为在js中浮点数的计算精度很高,浮点值的精确度高可达 17位小数,所以在JavaScript中的二进制的浮点数0.1和0.2他们相加的结果并非正好等于0.3,而是一个比较接近的数字 0.30000000000000004 ,所以条件判断结果为false。
正确判断方法:console.log(Math.abs(0.1+0.2-0.3)<=Number.EPSILON);//true
,Number.EPSILON,是ES6为我们提供的一个属性。这个值正等于2^-52。这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近0,但不等于0,。这个时候我们只要判断(0.1+0.2)-0.3小于它即可
String:字符串,
注:因为 null 和 undefined 没有 toString()方法, 所以 String()方法就直接返回了这两个值的字面量文本
拓展:字符串有最大长度吗?
有,因为String 的意义并非“字符串”,所以字符串的最大长度,实际上是受字符串的编码长度影响的,字符串的最大长度是 2^53 - 1,
symbol:ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
Boolean:boolean的true和false是区分大小写的,下图为不同类型的值与boolean值得转化规则
Object:对象
语言类型的判断;使用type of会返回以下几种
"undefined"表示值未定义; "boolean"表示值为布尔值;"string"表示值为字符串;"number"表示值为数值;"object"表示值为对象(而不是函数)或 null; "function"表示值为函数; "symbol"表示值为符号。
由以上结果可知typeof在数组,正则,日期,对象上的判断并不好,都是返回object
typeof拓展:对于一个未声明的变量和声明了但是未赋值的值,调用typeof两者都会返回undefined
由此可以引出另一个判断方法Object.prototype.toString();在使用toString()方法检测对象类型时,常用Object.prototype.toString.call()或Object.prototype.toString.apply()来检测
instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
2. JavaScript对象的底层数据结构是什么
JavaScript基本类型数据结构都是直接按值存储在栈中的,每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。
JavaScript引用类型数据存储在堆中,但是引用类型数据的地址指针是存储在栈中的,当我们想要访问引用类型的值时,需要先从栈中获得对象的地址指针,然后通过地址指针去找到堆中所需要的数据
补充:栈是一种特殊的线性表,它只能在一个表的固定端进行数据结点的插入和删除操作。栈按照后进先出的原则来存储数据,读出数据时,从栈顶开始逐个读出。栈在汇编语言程序中,经常用于重要数据的现场保护。
堆是一种特殊的树形数据结构,堆的特点是根节点的值是所有结点中最小的或者最大的,并且根结点的两个子树也是一个堆结构。
3.Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol
概念:symbol创造的目的是为了保证属性名独一无二,防止属性名冲突,可以通过symbol()创建一个symbol类型,使用symbol函数不能使用new命令,因为生成的symbol是一个原始类型的值,不是对象,其类似于字符串的数据类型。
symbol()函数接受一个字符串作为参数,如果symbol的参数是一个对象,会自动调用toString方法,将其转为字符串,然后才生成一个symbol值。
应用:作为属性名的symbol,由于每一个symbol值都是不相等的,所以symbol可以作为标识符用于对象的属性名,这样就可以保证不会出现同名的属性,对由多个模块构成的情况非常有用,可以防止某一个键被不小心改写或覆盖。