数据类型
对外的,面对编译器
基本数据类型(值类型)
包括:Undefined 、Null、Boolean、String、Number、Symbol(ES6)
存放位置:内存中的栈区域。
值的不可变性,称这些类型的值为原始值。
基本数据类型的值是按值访问的,基本类型的值是不可变的。
比较:基本数据类型的比较是值的比较,只判断是否相等。
拷贝:都是值的复制,相互没有影响。
引用数据类型(对象类型)
包括: Object、Array、Function、RegExp、Date
存放位置:内存中的栈存放指向堆区域的指针,内容在堆区域中
值的可变性:引用类型的值是按引用访问的,引用类型的值是动态可变的
比较: 引用类型的比较是引用地址的比较,判断是否指向同一对象。
拷贝:
- 赋值:仅改变引用的指针,指向同一个对象,相互影响
- 浅拷贝:拷贝一层,不对对象的子对象进行拷贝,对第一层的基本类型的修改互不影响,对于子对象会相互影响。
- 深拷贝:对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
undefined 和 null 的区别?
undefined:是一个没有设置值的变量。JavaScript特有的。没有返回值的函数返回为undefined,没有实参的形参也是undefined。
null:它是一个空对象指针。
null 和 undefined 的值相等,但类型不等:
typeof undefined // undefined
typeof null // object
null === undefined // false
null == undefined // true
基本数据类型和引用类型的数据结构
基本数据类型:数据存于内存中的栈区域。
引用数据类型:内存中的栈存放指向堆区域的指针,内容在堆区域中。
赋值、浅拷贝和深拷贝
如果是基本数据类型,直接赋值,会拷贝其本身,不存在浅拷贝和深拷贝。
如果是引用类型:
- 赋值:仅改变引用的指针,指向同一个对象,相互影响
- 浅拷贝:拷贝一层,不对对象的子对象进行拷贝,对第一层的基本类型的修改互不影响,对于子对象会相互影响。
- 深拷贝:对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
赋值
let obj1 = {
color: 'red',
age: 20,
address: {
city: 'beijing',
},
arr: ['a', 'b', 'c']
};
//赋值
let obj2 = obj1;
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj2.age);//21
console.log(obj2.address.city);//shanghai
浅拷贝
let obj1 = {
color: 'red',
age: 20,
address: {
city: 'beijing',
},
arr: ['a', 'b', 'c']
};
//浅拷贝
let obj3 = shallowCopy(obj1);
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj3.age); //20
console.log(obj3.address.city); //shanghai
//自定义浅拷贝函数
function shallowCopy(obj) {
if (typeof obj !== 'object' || obj == null) {
return obj;
}
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = obj[key];
}
}
return result;
}
深拷贝
let obj1 = {
color: 'red',
age: 20,
address: {
city: 'beijing',
},
arr: ['a', 'b', 'c']
};
//深拷贝
let obj4 = deepCopy(obj1);
obj1.age = 21;
obj1.address.city = "shanghai";
console.log(obj4.age);//20
console.log(obj4.address.city);//shanghai
//自定义深拷贝函数
function deepCopy(obj) {
// obj 是 null 或者不是对象和数组,直接返回
if (typeof obj !== 'object' || obj == null) {
return obj;
}
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepCopy(obj[key]);
}
}
return result;
}
本地对象
对内的,供开发者使用
-
包装类型对象
- Boolean
- String
- Number
-
引用类型
- Array
- Function
- Date
- Object
- RegExp
- Error
-
内置对象
在脚本程序初始化时被创建,不必实例化这两个对象。- Global
- Math
基本包装类型
在实际中每读取一个基本数据值的时候,后台就会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法操作这些数据。
let s1 = "some text"; //值类型没有方法。
let s2 = s1.substring(2);
console.log(s1); //some text
console.log(s2); //me text
引用类型与基本包装类型的区别
它们的对象生命周期不同:
引用类型:使用new创建引用类型的实例,在执行数据流离开当前作用域时会一直存储在内存中。
基本包装类型:自动创建基本包装类型的对象,只执行一行代码的瞬间之后就会立即销毁。
这意味着在运行时为基本包装类型值添加属性和方法是无效的。
let s1 = 'some text';
s1.color = 'red';
s1.color // undefined
// 但是这样是可以的
let s1 = new String('some text');
s1.color = 'red';
s1.color // red
不建议显式的创建基本包装类型的对象,因为在很多时候会造成一些让人很迷惑的东西。
let b = new Boolean(false); //b 这个变量就是 Boolean 对象
let c = b && true;
console.log(c); // true
let str = 'hello'; // str 本质上是一个原始值,并不存在 prototype 属性
console.log(typeof str); // string
console.log(str instanceof String); // false
参考文章:https://segmentfault.com/a/11...
类型判断
typeof
相较于JS基本数据类型少null多function。
console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof 123); //number
console.log(typeof "123"); //string
console.log(typeof true); //boolean
console.log(typeof function a() {}); //function
console.log(typeof [1, 2, 3]); //object
console.log(typeof {a: "a"}); //object
instanceof
- 确定原型指向关系。只适用于对象,因为值类型没有原型。
- 不能判断一个对象实例具体属于哪种类型。
let a = [];
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true
console.log(null instanceof Object);//false
Object.prototype.toString.call()
- Object 的原型方法,返回"[object type]",其中type是对象的类型。
- toString()调用null返回[object, Null],undefined返回[object Undefined]。
- 无法识别自定义的对象类型。
console.log(Object.prototype.toString.call(123)); //[object Number]
function optc(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}
console.log(optc(123)); //Number
console.log(optc('123')); //String
console.log(optc(true)); //Boolean
console.log(optc(undefined)); //Undefined
console.log(optc(null)); //Null
console.log(optc({})); //Object
console.log(optc([])); //Array
console.log(optc(function () {})); //Function
console.log(optc(/\d/)); //RegExp
console.log(optc(new Date())); //Date
constructor(构造函数)
利用构造函数判断数据类型。
- 对象的构造函数名就是该数据类型。
- 除Null和Undefined外,所有的数据类型都是/可以转化为对象,而如果是对象,就肯定有构造函数。
function A() {}
let a = new A();
console.log(a.constructor.toString()); //function A() {}
总结
准确判断数据类型包括自定义的对象类型
function dataType(data) {
if (!data) { //判断null、undefined
return Object.prototype.toString.call(data).slice(8, -1);
} else {
return data.constructor.toString().match(/function\s*([^(]*)/)[1];
}
}
console.log(dataType(null)); //null
console.log(dataType(undefined)); //Undefined
console.log(dataType(123)); //Number
console.log(dataType([])); //Array
function Point(x, y) {}
console.log(dataType(new Point(1, 2))); //Point
类型转换
强制类型转换
1. 转换成字符串
String()
此方法常用于null和undefined转换成字符串类型
toString()
此方法不适合用于null和undefined
对象 | 返回值 |
---|---|
Number | 返回当前数值的字符串 |
String | 字符串本身 |
Boolean | false-->"false" |
Array | [1,2,3]-->"1,2,3" |
Function | 返回当前函数源代码的字符串 |
Object | "[object object]" |
Date | 返回表示UTC的字符串 |
Symbol | "Symbol()" |
2. 转换成数字
Number()
Number方法只要字符串中有一个字母则返回NaN,并且可以转换boolear类型。Number()可以用于任何数据类型。
parseInt()和parseFloat()
parseInt方法在字符串中遇到数值转换成数字,如果遇到非数字就会返回,不能转换boolear类型。parseInt()和parseFloat()则专门用于字符串。
let str1 = "123";
let str2 = "abc";
let str3 = "123abc";
let a = true;
console.log(Number(str1)); // 123
console.log(Number(str2)); // NaN
console.log(Number(str3)); //NaN
console.log(Number(a)); //1
console.log(parseInt(str1)); // 123
console.log(parseInt(str2)); //NaN
console.log(parseInt(str3)); //123
console.log(parseInt(a)); //NaN
3. 转换成布尔类型
Boolean()
五种转换为false的情况:null
,undefined
,''(空字符串)
,0
,NaN
。其余为true。
隐式类型转换
1. 四则运算符带来的类型转换
转换规则
加法运算:
一方是字符串,另一方也会被转换为字符串类型。加法运算会触发3种类型转换
- 将值转换为原始值
- 将值转换为数字
- 将值转化为字符串
null会转换为0;undefined 会转换为NaN.
其他运算:双方会被转为数字进行运算。
console.log(100 + undefined); //NaN
console.log(100 + null);//100
console.log(1 + "1"); //11
console.log(1 * "2"); //2
console.log([1, 2] + [3, 4]); //1,23,4
console.log('a' + +'b'); //aNaN
/* 转换步骤
* +'b' -> 'NaN'
* 'a' + 'NaN' -> 'aNaN'
*/
2. "=="
-
==
会发生类型转换,使两边尽量相等。
类型(x) | 类型(y) | 结果 |
---|---|---|
null | undefined | true |
number | string | 把y转化为number,再与x进行比较 |
boolean | 任何类型 | 把x转换为number,再与x进行比较 |
string或number | object | 把y转换为原始值,再与x进行比较 |
object | object | 如果它们指向同一个对象,则返回true;否则返回false |
- 使用
==
的情况:除了==null之外,其他一律都用===
const obj = {x: 100};
if (obj.a == null) {}
//相当于:
//if (obj.a === null || obj.a === undefined) {}
- if 语句和逻辑运算
if 语句中就是判断 truly
变量和 falsely
变量。
//以下是falsely 变量。除此之外都是 truly 变量
console.log(!!0 === false);
console.log(!!NaN === false);
console.log(!!null === false);
console.log(!!undefined === false);
console.log(!!false === false);
console.log(!!" " === true);
逻辑判断(隐式转换成Boolean值)
console.log((10 && 0)); //0
console.log(("" || "abc")); //abc
console.log((!global.abc)); //true
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。