1. 数据类型
为什么需要数据类型 ?
在计算机中,不同的数据所占用的存储空间是不同的充分利用存储空间,于是定义了不同的数据类型。
JS数据类型
- 变量是用来存储值的所在处,它们有名字和数据类型。
- 变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。
- JavaScript是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定(根据等号右边的值来确定的)。
- JavaScript拥有动态类型,同时也意味着相同的变量可用作不同的类型。
var age = 10; //这是一个数字型
var str = "hello"; //这是一个字符串
数据类型的分类
JS把数据类型分为两类:
- 简单数据类型(基本数据类型/值类型): Number, String, Boolean, Undefined, Null
- 复杂数据类型(引用类型): Object、 Array、 Date、RegExp、Symbol
数据类型的存储
- 简单数据类型:存放在栈里,直接开辟一个空间存放的是值,因此叫做值类型
- 复杂数据类型:首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据,变量中存储的仅仅是地址(引用)
堆和栈:
- 栈和堆是两种基本的数据结构。
- 栈 由操作系统自动分配释放内存空间
- 堆 在内存中动态分配内存空间,不一定会自动释放,一般由程序员分配释放(在项目中将对象类型手动置为null),若程序员不释放,由垃圾回收机制回收。
2. 简单数据类型
数字型 Number
Number:数字型,包含整型值和浮点型值,如21,0.21 。默认值:0
var num = 10;// num 数字型
var PI = 3.14;// pI 数字型
// 1. 八进制,在数字前面加0表示八进制
var num1 = 010;//转化为十进制就是 8
// 2. 十六进制 在数字前面加0x 表示十六进制
var num2 = 0xa;// 转化为十进制为 10
// 3. JavaScript中数值的最大值和最小值
alert(Number.MAX_VALUE);
alert(Number.MIN_VALUE);
// 4. 无穷大
alert(Infinity);
// 5. 无穷小
alert(-Infinity);
// 6. 非数字(Not a Number)
alert('hello' - 2);//NaN
// 7. isNaN() 这个方法用来判断非数字 是数字返回false 不是数字 返回true
布尔型 Boolean
Boolean:布尔值类型,如true、false。默认值:false
字符串型 String
String:字符串型,字符串都带引号,如"张三"。默认值:""
- 字符串型可以是引号中的任意文本,其语法为双引号"" 和单引号’’, 因为HTML标签里面属性使用的是双引号,JS中推荐使用单引号。
- 字符串转义符
\n:换行符,n 是newline的意思
\\: 斜杠\
\’: 单引号
\": 双引号
\t: tab 缩进
\b: blank 空格 - 字符串长度
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的length属性可以获取整个字符串的长度。
var str = "哈哈哈";
alert(str.length);//显示3
- 字符串拼接
- 多个字符串之间可以使用 + 进行拼接,其字符串 + 任何类型 = 拼接后的新字符串
- 经常会将字符串与变量来拼接,因为变量可以很方便的修改里面的值
- 变量是不能添加引号的,因为加引号的变量会变成字符串。
var age = 18;
console.log('我' + age + '岁啦');
Undefined
Undefined:声明未赋值,如var a; 此时a = undefined。默认值:undefined
var variable;
console.log(variable);//undefined
console.log('你好' + variable);//你好undefined
console.log(11 + variable);//NaN
console.log(true + variable);//NaN
Null
Null:声明了变量为空值,如var a = null; 默认值:null
var vari = null;
console.log('你好' + vari);//你好null
console.log(11 + vari);//11
console.log(true + vari);// 1
3. 数据类型检测
- typeof
- instanceof
- constructor
- Object.prototype.toString.call()
typeof
typeof是一元运算符,同样返回一个字符串类型。一般用来判断一个变量是否为空或者是什么类型。
typeof undefined // 'undefined'
typeof '10' // 'String'
typeof 10 // 'Number'
typeof false // 'Boolean'
typeof Symbol() // 'Sysbol'
typeof Function // 'function'
typeof null // 'Object'
typeof [] // 'Object'
typeof {} // 'Object'
instanceof
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的prototype属性。可以使用instanceof来进行判断某个对象是不是另一个对象的实例
instanceof 的原理是通过判断该对象的原型链中是否可以找到该构造类型的prototype类型
function Foo() {}
var f1 = new Foo();
console.log(f1 instanceof Foo); // true
constructor
对于引用类型,除此之外,还可以使用xx.constructor.name
构造函数来判断。
// constructor 构造来判断
console.log(fn.constructor.name) // Function
console.log(date.constructor.name)// Date
console.log(arr.constructor.name) // Array
console.log(reg.constructor.name) // RegExp
Object.prototype.toString.call()
一种最好的基本类型检测方式,它可以区分null、sring、boolean、number、undefined、array、function、object、date、 math数据类型
// 判断基本类型
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(“abc”);// "[object String]"
Object.prototype.toString.call(123);// "[object Number]"
Object.prototype.toString.call(true);// "[object Boolean]"
// 判断引用类型
function fn() {
console.log(“xiaolu”);
}
var date = new Date();
var arr = [1,2,3];
var reg = /[hbc]at/gi;
Object.prototype.toString.call(fn); // "[object Function]"
Object.prototype.toString.call(date); // "[object Date]"
Object.prototype.toString.call(arr); // "[object Array]"
Object.prototype.toString.call(reg); // "[object RegExp]"
应用
如何判断数组?
**使用instanceof方法: ** 用于判断一个变量是否某个对象的实例
var arr = []
console.log(arr instanceof Array) // true
**使用constructor方法: **
console.log([].constructor == Array) // true
使用Object.prototype.toString.call()方法:
var arr = []
console.log(Object.prototype.toString.call(arr) === '[object Array]') // true
ES5的Array.isArray :
console.log(Array.isArray([])) // true
4. 数据类型转换
什么是数据类型转换
使用表单、prompt获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,因此需要转换变量的数据类型。通俗来说,就是把一种数据类型转化为另一种数据类型。
通常会实现3种方式的转换:
- 转换为字符转类型
- 转换为数字型
- 转换为布尔型
转换为字符串类型
- toString()
var num = 1;
alert(num.toString());//'1'
- String() 强制转换
String(123); // "123"
String(true); // "true"
String(null); // "null"(报错)
String(undefined);// "undefined"(报错)
String([1,2,3]) // "1,2,3"
String({}); // "[object Object]"
- 加号拼接字符串
var num = 1;
alert(num + '');//'1'
转换为数字型(重点)
- parseInt(string) 函数
parseInt('78');//78
parseInt('78.21');//78 取整
parseInt('78px');//78会去掉px 单位
parseInt('rem78px');//NaN,不能以字母开头
- parseFloat(string)
parseFloat('78.21')//78.21
- Number() 强制转换函数
Number(10); // 10
Number('10'); // 10
Number(null); // 0
Number(''); // 0
Number(true); // 1
Number(false); // 0
Number([]); // 0
Number([1,2]); // NaN
Number('10a'); // NaN
Number(undefined); // NaN
转换为布尔型
- Boolean()函数
- 代表空、否定的值会被转化为false,如’’、0、NaN、 null、undefined
- 其余值都会被转化为true
console.log(Boolean(''));//flase
console.log(Boolean(0));//flase
console.log(Boolean(NaN));//flase
console.log(Boolean(null));//flase
console.log(Boolean(undefined));//flase
console.log(Boolean('小白'));//true
console.log(Boolean(12));//true
5. 隐式转换
什么是隐式转换?
在js中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时编译器会自动将运算符两边的数据做一个数据类型转换,这种由编译器自动转换的方式就称为隐式转换
隐式转换的规则
转成string类型
- +(字符串连接符)
转成number类型
- ++/–(自增自减运算符)
- ±*/%(算术运算符)
- > < >= <= == !== === (关系运算符)
转成boolean类型
- ! (逻辑非运算符)
面试题大坑
坑一:字符串连接符与算数运算符隐式转换规则混淆
// 字符串连接符(只要+号两边有一边是字符串)
1+"true" // 1true
// 算数运算浮(会把其他数据类型调用Number()方法转换成数字)
1+true // 2
1+undefined //NaN
1+null // 1
坑二:关系运算符:会把其他数据类型转换成number之后再比较关系
"2" > 10 // false
"2" >"10" // true,两边都是字符串时按照unicode编码 (字符串。charCodeAt())转换成数字
"abc" > "b" // false, 先比较'a'和'b', 'a'不大于'b',直接返回结果
"abc" > "aad" // true, 先比较'a'和'a',两者相等,接着比较'b'和'a',得出结果
NaN == NaN // false, NaN与任何数据比较都是NaN
undefined==null // true,如果数据类型是undefined和null ,得出固定结果true
坑三:复杂数据类型在隐式转换时会先转换成String, 再转换成Number运算
var a=??
if(a == 1 && a == 2 && a==3) {
console.log(1)
} // 如何完善a, 使其正确打印1
// 原理:
// 重写对象的valueOf() 方法
var a = {
i:0,
valueOf: function() {
return ++a.i
}
}
if(a==1 && a==2 && a==3) { // 每一次运算时都会调用一次a的valueOf方法
console.log("1");
}
坑四:逻辑非隐式转换与关系运算符隐式转换混淆
空数组的toString()会得到空字符串,而空对象的toString() 方法会得到字符串’[object, Object]’, Number(’[object, Object]’) == NaN, NaN与任何数据比较都不等
- []==0, true
- ![]==0, true
- []==![], true
- []==[], false
- {} = !{}, false
- {} ={}, false
[]==0 // true, [].valueOf().toString() = '', Number('') ==0 成立
![]==0 // true, 逻辑非优先级高于关系运算符, ![]==false(空数组转布尔得到true),false==0 成立
[]==![] // true, ![]== 0, []==0
[] == [] // false, 引用类型数据存在堆中,栈中存的是地址,所以结果为false
{} ==!{} // false, !{} == false, Number({}.valueOf().toString()) == NaN
{} == {} // false, Number({}.toString()) == NaN