JavaScript的数据类型:分为基本类型和引用类型,也分别称为原始类型和对象类型。

一、基本数据类型特点及其详解

基本类型包括:undefined、null、number、boolean、string

特点:

  • 按值访问,即可对保存在变量中的值进行操作,操作的是指针。
  • 值不可变,任何方法都无法改变其值,必须先销毁再赋新值。
  • 不可以添加属性和方法。
  • 值保存在栈内存中,占据固定大小的空间。

详解:

1、undefined,typeof返回undefined

  • 若变量只声明未初始化,则变量的值为undefined。
  • 对象上不存在的属性,则属性值为undefined。
  • 函数形参不传值,则参数值为undefined。
  • 函数无显式返回值,则返回undefined。
  • 数组中寻找某一项没有找到,则返回undefined。
  • JS严格模式下,this指undefined。
  • 使用void对表达式求值,结果为undefined。

2、null,typeof返回object(属于误判,应该为null)

  • 手动设置
  • DOM元素获取时没有获取到指定的元素对象,结果为null。
  • 正则捕获时没有捕获到指定结果,返回null。
  • Object.prototype._proto_的值为null,即对象原型链的终点。
  • 定义一个变量,若要当作对象来使用,初始化为null。

null和undefined的区别:null表示空对象,对象暂不赋值时使用null;undefined表示空非对象,非对象暂不赋值时使用undefined

3、number,typeof返回number

      1)包括整数和浮点数

  • 整数:JS中的整数表示形式有:十进制、二进制(前缀0b或0B,由0、1组成)、八进制(以数字0开头,由0~7组成)、十六进制(以0X或0x开头,由0~9,A~F或a~f 组成)。默认情况下,JS内部都将转化为十进制。
  • 浮点数:JS的浮点数必须包含一个小数点且小数点后至少有一位数字,浮点数会自动转为整数。它的最高精度为17位。如:0.1+0.2并不等于0.3(精度丢失)。
  • NaN:非数字类型,任何涉及到NaN的操作都会返回NaN。isNaN()用于判断是否是非数字类型,是返回true,否返回false。isNaN()先将传入的参数转为数值。如果参数为对象类型,则先调用对象的valueOf(),再确定该方法返回的值是否可以转数值,若不能,再调用toString()并返回值。

      2)数值转化的方法有:

  • Number(),将任何类型参数转为数字;
  • parseInt(),将字符型参数转为整型数字。两个参数,第一个表示要转换的参数,第二个用来指定转换基数;
  • parseFloat(),将字符型参数转为浮点型数字。只有一个参数,即要转换的参数,只解析十进制且只取第一个小数点为有效。

       3)常用方法:

  • 无穷大(小)值:Infinity(-Infinity),如果超过最大(小)值就会返回该值
  • 最大(小)值:Number.Max(Min)_VALUE // 5e-324 ~ 1.7976931348623157e+308(5e-324)
  • 判断是否有穷:isFinite(),在范围内返回true
  • 四舍五入:ceil()、floor()、round()、toFixed()—固定精度、toprecision()—固定长度
  • abs()、random()、max()、min()
  • 取整:parseInt()、位运算(按位非(NOT):~ 、按位与(AND):& 、按位或(OR): |、按位异或(XOR):^、左移:<<、有符号右移:>> 、无符号右移:>>>)

       4)转为number

  • 使用转化方法,结果如下:
//1.字符串转数字
var str1 = '666';
console.log(Number(str1));//666
//如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
var str2 = '';
console.log(Number(str2));//0
var str3 = '     ';
console.log(Number(str3));//0
var str4 = '1.23';
console,log(Number(str4));//1.23
var str5 = '6d66';//如果字符串中有除了以上格式外的内容,则转换为NaN
console.log(Number(str5));//NaN

//2.undefined转数字
var str6 = undefined;
console.log(Number(str6));//NaN

//3.null转数字
var str7 = null;
console.log(Number(str7));//0

//4.布尔转数字
var bool1 = true;
console.log(Number(bool1));//1
var bool2 = false;
console.log(Number(bool2));//0

//5.对象转数字
//先调用valueOf(),再按规则转换;若转换的结果是NaN,则调用对象的toString(),再按规则转换。

//6.NaN转数字
var str=NaN;
console.log(Number(str));//NaN
//只适用于字符串
var a = "100.0px";
console.log(parseFloat(a));//100.0
console.log(parseInt(a));//100
var b = ".100.0px";
console.log(parseFloat(b));//0.1
console.log(parseInt(b));//NaN
var c = ".";
console.log(parseInt(c));//NaN
  • 隐式转换:+或-

若使用负号,浏览器会对值取反,所以应该写成:-(-a)或-a+1;

会返回NaN的情况:对象、undefined、NaN,不可以使用此方法。主要针对字符串类型。

var a = "123";
console.log(+a);//123
var b = null;
console.log(+b);//0
var c = 123;
console.log(+c);//123
var d = true;
console.log(+d);//1
  • 隐式转换:-、*、/

针对字符串,与number类型的值运算,但不可改变原值。+不可以,如果+用以运算,将拼接成为字符串。

4、Boolean:typeof返回boolean

  • 任何非零数字都是真,任何非空字符串都是真,任何对象都是真。
  • 只有0和NaN是假,只有空字符串是假,只有null和undefined是假。

5、string:typeof返回string

      1)注意点:

  • 字符串类型需用单双引号将内容包裹住,单双引号作用相同(相同引号不可嵌套,不同引号可以嵌套);
  • 有length属性,空格计为一个字符,多个字符的转义序列计为一个字符;
  • 多行字符串建议使用字符串拼接。

       2)常用方法

  • String(),转为字符型。若参数有toString(),则返回对应结果;若为null,则返回null;若为undefined则返回undefined。
  • toString(),将数值、布尔值、对象和字符串转为字符型,null和undefined不可使用该方法。
  • 大小写转换:toLowerCase() / toLocaleLowerCase(),转为小写 / 针对特定地区转为小写;toUpperCase() / toLocaleUpperCase(),转为大写 / 针对特定地区转为大写。
  • 字符操作:charAt()、charCodeAt()—获取字符的Unicode编码、fromCharCode()—根据Unicode编码返回对应字符
  • 字符串提取:substr()、substring()、slice()
  • 模式匹配:match()、search()、replace()、split()
  • 其他:concat()、trim()等

       3)字符串为什么可以调用方法:

       在JS中,字符串本身不存在任何方法。但是每当JS引擎读取一个字符串时,就会在内部创建一个对应的String对象(一种特殊的引用类型),该对象提供的操作方法使得字符串可以调用方法。引擎内部的具体操作大概为:创建一个String类型的实例,在实例上调用指定方法,销毁实例。

       4)转为string

  • 使用转换方法:String()、toString()
  • 使用+:把要转换的值与一个字符串" "相加

二、引用数据类型特点及其详解

引用类型有:Object、Date、Array、RegExp、Function、内置对象Global、内置对象Math、String

特点:

  • 按址访问,操作的是对象的引用而不是指针。
  • 可以添加属性和方法。
  • 其变量只存指针,值是保存在内存中的变量,对象本身存储在堆内存中。

详解一:

1、数据属性

  • [[Configurable]],能否通过delete删除属性从而重新定义属性,或者能否把属性修改为访问器属性。默认值为true。
  • [[Enumerable]],能否通过for-in循环返回属性。默认值为true。
  • [[Writable]],能否修改属性的值。默认值为true。
  • [[Value]],包含这个属性的数据值。读取属性值时,从这个位置读;写入属性值时,把新值保存在这个位置。默认值为undefined。

       要修改属性默认的特性,必须使用Object.defineProperty(属性所在对象, 属性名, 一个描述符对象)。调用此方法时,如果不指定描述符对象的特性值,默认值都为false。

2、访问器属性:包含一对getter和setter函数(不必需)。

  • [[Configurable]],能否通过delete删除属性从而重新定义属性,或者能否把属性修改为数据属性。默认值为true。
  • [[Enumerable]],能否通过for-in循环返回属性。默认值为true。
  • [[Get]],在读取属性时调用的函数。默认值为undefined。
  • [[Set]],在写入属性时调用的函数。默认值为undefined。

    同样,访问器属性也必须使用Object.defineProperty()来定义。

 3、方法

  • constructor,构造函数。
  • hasOwnProperty(propertyName),用于检查给定的属性是否在当前的实例中。
  • isPrototypeOf(object),用于检查传入的对象是否是传入对象的原型。
  • propertyIsEnumerable(propertyName),用于检查给定的属性是否能使用for-in语句进行枚举。
  • toLocaleString(),返回对象的字符串表示。
  • toString(),返回对象的字符串表示。
  • valueOf(),返回对象的字符串、数值或布尔值表示,结果通常与toString()一致。

4、新增API:

  • create(prototype[descriptors]),用于原型链继承。
  • defineProperty(O,Prop,descriptor),用于定义对象属性的特性。
  • defineProperties(O,descriptors),用于同时定义多个属性的特性。
  • getOwnPropertyDescriptor(O,property),获取defineProperty()设置的property特性。
  • getOwnPropertyNames(),获取所有属性名,但不包括prototy中的属性,返回一个数组。
  • keys(),和getOwnPropertyNames()类似,但能够获取所有可枚举的属性,返回一个数组。
  • preventExtensions(O),用于锁住对象,使其不能增加新属性,但可以删改属性。
  • Object.seal(O),用于密封对象,使其不能增删改属性,但单数属性值可以修改。
  • Object.freeze(O),用于完全冻结对象,使其不能增删改属性。

5、对象的引用一般为obj[ ' ' ],特例情况也可以使用obj.(点方法)

6、操作符:

  • delete,删除对象的属性,属性删除后,属性值自然为undefined。
  • in,用于检测一个key是否存在于一个对象中。
  • for-in,用于遍历对象,但输出值的顺序不一定。
  • typeof,打印出数据类型,结果都用引号包住。
var fn = function(){};
typeof fn;//"function
//function类型并不存在,但仍然可以打印出来

详解二:

1、Object类型

//创建方式一:new Object
var o1 = new Object();
//创建方式二:对象字面量
var o2 = {name:"cd",age:21,sex:"m"};

2、Array类型

//创建方式一:使用new 构造函数
var a1 = new Array();
var a2 = new Array(4);
var a3 = new Array("lu",true,100);

//创建方式二:使用数组字面量
var a4 = [];
var a5 = [10];
var a6 = [1,2,3];

3、Date类型

//创建方式
var d = new Date();

4、RegExp类型

//创建方式一:使用new 构造函数
var e1 = new RegExp("pattern","flags");

//创建方式二:使用正则表达式字面量
var e2 = / pattern / flags;
  •   pattern模式部分是正则表达式,每个正则都可带有一个或多个flags标志。
  • 实例方法:exec(),参数为将要使用该模式匹配的字符串,返回第一个匹配项信息的数组。在全局情况下,每次调用都会在字符串中继续查找新的匹配项;非全局情况下,始终返回第一个匹配项。test(),参数为将要使用该模式匹配的字符串,匹配返回true,反之false。
  • 实例属性:source(正则表达式的字符串表示)、lastIndex(开始搜索下一个匹配项的字符位置从9开始)、multiline(m标志:匹配多行)、ignoreCase(i标志:不区分大小写)、global(g标志:全局)

5、Function类型

//创建方式一:函数声明
function f1(){};
//创建方式二:函数表达式
var f2 = function (){ };
//创建方式三:使用构造函数
var f3 = new Function();

6、Global对象

所有在全局作用域定义的属性和方法都是Global的属性。

编码方法:

  • encodeURI(),对URI进行编码,将无效的字符串使用utf-8编码替换,然后发送给浏览器,以便浏览器接受和理解。作用于整个URI,不会对本身属于URI的特殊字符编码。对应的解码方法为decodeURI()。
  • encodeURIComponent(),对URI的某一段进行编码,会对它认为的所有非标准字符进行编码。对应的解码方法为decodeURIComponent()。

7、Math对象

     属性和方法,大都与number类型的方法有关。

三、ES6新增类型:Symbol,属于原始数据类型。

       本段参考曾看过的一篇博文,但不记得地址了。

  • Symbol类型可以作为对象属性名,凡属性名是Symbol类型,就代表独一无二,不会与其他属性名产生冲突。
  • 作为基本类型,它没有对应的包装类型,因此它本身不是对象,而是一个函数,生成Symbol类型的值时,不能使用new操作符。
let s=Symbol();
  • Symbol函数可以接受一个字符串作为参数。参数表示对当前Symbol值的描述,故相同参数的Symbol函数的返回值不相等
let s1 = Symbol('s1');
let s2 = Symbol('s2');
console.log(s1, s2);
  • 但作为对象属性名时,不能直接通过点的方式访问属性和设置属性值,因为引擎会把点后的属性名解析成字符串;
let s = Symbol();
let obj = {};
obj.s = 'a';
console.log(obj); // {s: "a"}
obj[s] = 'b';
console.log(obj) ; //{Symbol(): "b"}
  • 作为对象属性名,该属性不会出现在for-in、for-of循环中,也不会被对象的keys()、getOwnPropertyNames()、JSON.stringify()返回。
  • 但它不是私有属性,对象的getOwnPropertySymbols()专门获取指定对象的所有Symbol属性名。
let obj = {};
let s1 = Symbol('s1');
let s2 = Symbol('s2');
obj[s1] = 'Jack';
obj[s2] = 'Tom';
Object.keys(obj); //[]
for(let i in obj){
    console.log(i); 
}
Object.getOwnPropertySymbols(obj); //[Symbol(s1), Symbol(s2)]
  • Reflect.ownKeys()可以返回所有类型的键名。
let obj = {};
let s1 = Symbol('s1');
let s2 = Symbol('s2');
obj[s1] = 'Jack';
obj[s2] = 'Tom';
obj.name = 'Nick';
Reflect.ownKeys(obj); //[Symbol(s1), Symbol(s2),"name"]
  • Symbol.for()接收一个字符串作为参数,再全局搜索有无以该参数作为名称的Symbol值。有就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。也可以生成Symbol值,与Symbol()的区别在于:Symbol.for()生成的Symbol会登记在全局环境中供搜索,而Symbol()不会。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 //true

let s3 = Symbol('foo');
let s4 = Symbol.for('foo');
s3 === s4; // false
  • Symbol.keyFor()返回一个已在全局环境中登记的Symbol类型的key。
let s1 = Symbol.for('s1');
Symbol.keyFor(s1); //foo
let s2 = Symbol('s2'); //未登记的 Symbol 值
Symbol.keyFor(s2); //undefined