★ 数据类型
一共8种
1:【对象类型】Object
7:【原始数据类型】null undefined boolean number string symbol bigint,
其中两个symbol bigint是es6中新增的
- Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
- BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
Symbol
- 场景1:扩展对象,属性名冲突问题
// // a.js =========================================
// cache['a_foo'] = Math.random()
// // b.js =========================================
// cache['b_foo'] = '123'
// console.log(cache)
-
两个 Symbol 永远不会相等
-
Symbol 描述文本
// console.log(Symbol('foo'))
- 使用 Symbol 为对象添加用不重复的键
// const obj = {}
// obj[Symbol()] = '123'
// obj[Symbol()] = '456'
// console.log(obj)
- 也可以在计算属性名中使用
const obj = {
[Symbol()]: 123
}
console.log(obj)
- Symbol 模拟实现私有成员
// a.js 只对外暴露 person ===============================
const name = Symbol()
const person = {
[name]: 'zce',
say () {
console.log(this[name])
}
}
// b.js =======================================
// 由于无法创建出一样的 Symbol 值,
// 所以无法直接访问到 person 中的「私有」成员
person[Symbol()] // 啥也没有
person.say() // zce
★ 原始数据类型、引用数据类型的区别
1.函数调用
原始类型存储的都是值,是没有函数可以调用的,比如 undefined.toString()会报错的
'1'.toString() 虽然看着是可以使用的。但是'1' 已经被强制转换成了 String 类型也就是对象类型,所以可以调用 toString 函数。
2.存储位置
原始数据类型 【栈】
引用数据类型 【堆】
★ 栈、堆的区别
1、存储数据
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
2、数据结构中:
- 在数据结构中,栈中数据的存取方式为先进后出。
- 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
3、在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收
★ 数据类型检测的方式有哪些
1、typeof
typeof属于一元运算符,运算符用来判断给定对象的类型。
用法: typeof XXX
返回值 类型
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof function(){}); // function
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof {}); // object
其中数组、对象、null都会被判断为object,其他判断都正确。
2、instanceof
instanceof是关系运算符,用来判断一个对象是否是另一个对象的实例。
用法: XXX instanceof 属性
返回值 Boolean值
instanceof只能正确判断引用数据类型,而不能判断基本数据类型。
其内部运行机制是判断在其原型链中能否找到该类型的原型。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log(function(){} instanceof Function); // true
console.log(function(){} instanceof Object); // true
console.log({} instanceof Object); // true
3、constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log(([]).constructor === Object); // !!!false!!
console.log((function() {}).constructor === Function); // true
console.log((function() {}).constructor === Object); //!!! false!!
console.log(({}).constructor === Object); // true
constructor的两个作用:
1、判断数据的类型
2、对象的实例可以通过constructor对象访问构造函数
所以需要注意的是,一旦手动改变了原型,那通过constructor来判断数据类型就不准确了
比如:
function Fn(){};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor===Fn); // false
console.log(f.constructor===Array); // true
4、Object.prototype.toString.call()
使用 Object 对象的原型方法 toString 来判断数据类型:
var a = Object.prototype.toString;
console.log(a.call(2)); //[object Number]
console.log(a.call(true)); //[object Boolean]
console.log(a.call('str')); //[object String]
console.log(a.call([])); //[object Array]
console.log(a.call(function(){})); //[object Function]
console.log(a.call({})); //[object Object]
console.log(a.call(undefined)); //[object Object]
console.log(a.call(null)); //[object Null]
//toString()的区别
console.log([1,2,3].toString()) // '1,2,3'
console.log(console.log.toString()) // 'function log() { [native code] }'
let fn = function(){
console.log('aaa')
}
console.log(fn.toString()) // function(){console.log('aaa')}
obj.toString()和Object.prototype.toString.call(obj)的区别
toString是Object的原型方法,
Array、function等类型作为Object的实例,都重写了toString方法。
根据原型链的知识,不同对象调用的是对应的重写之后的toString方法
function类型返回内容为函数体的字符串
Array类型返回元素组成的字符串
所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型 因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。
★ 判断数组的方式有哪些
1、通过instanceof做判断
obj instanceof Array
2、通过Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
3、通过ES6的Array.isArray()做判断
Array.isArrray(obj);
4、通过原型链做判断
obj.__proto__ === Array.prototype;
5、通过Array.prototype.isPrototypeOf【不熟悉】
Array.prototype.isPrototypeOf(obj)
★ isPrototypeOf
用于检测一个对象是否存在于另一个对象的原型链中
★ 类型转换
首先我们要知道,在 JS 中类型转换只有三种情况,分别是:
- 转换为布尔值
- 转换为数字
- 转换为字符串
| 原始值 | 转换目标 | 结果 |
|---|---|---|
| number | Boolean() | 除了0 -0 NaN 都为true |
| string | 除了空串都为true | |
| null undefined | false | |
| 引用类型 | true | |
| number | string | 5=>'5' |
| Boolean、函数、symbol | 'true' | |
| 数组 | [1,2]=>'1,2' | |
| 对象 | 'object Object' | |
| string | 数字 | '1'=>1,'a'=>NaN |
| 数组 | 空数组=> 0;一个元素且为数字的转数字;其余NaN | |
| null | 0 | |
| 除了数组的引用类型 | NaN | |
| Symbol | 报错 |
转Boolean()
undefined, null, false, NaN, '', 0, -0,为false,
其余都为 true,包括所有对象。
注意转换是用Boolean() 、String()、 Number()方法转换的时候,用==比较的时候又是另外的结果
★ 四则运算符
加法运算符不同于其他几个运算符,它有以下几个特点:
- 运算中其中一方为字符串,那么就会把另一方也转换为字符串
- 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
1 + '1' // '11'
true + true // 2
4 + [1,2,3] // "41,2,3"
如果你对于答案有疑问的话,请看解析:
- 对于第一行代码来说,触发特点一,所以将数字
1转换为字符串,得到结果'11' - 对于第二行代码来说,触发特点二,所以将
true转为数字1 - 对于第三行代码来说,触发特点二,所以将数组通过
toString转为字符串1,2,3,得到结果41,2,3
另外对于加法还需要注意这个表达式 'a' + + 'b'
'a' + + 'b' // -> "aNaN"
因为 + 'b' 等于 NaN,所以结果为 "aNaN",你可能也会在一些代码中看到过 + '1' 的形式来快速获取 number 类型。
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字
4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN
★ 比较运算符
- 如果是对象,就通过
toPrimitive转换对象 - 如果是字符串,就通过
unicode字符索引来比较
let a = {
valueOf() {
return 0
},
toString() {
return '1'
}
}
a > -1 // true
在以上代码中,因为 a 是对象,所以会通过 valueOf 转换为原始类型再比较值。
'b'>'a' // true
【比较运算的时候,如果是对象会转换成基本类型,通过toPrimitive()方法】 【Primitive ['prɪmətɪv'] 原始的】
★ toPrimitive
应用场景: 在JavaScript中,如果想要将对象转换成基本类型时,也就是所谓的拆箱时,会调用toPrimitive()。
函数结构: toPrimitive(input,preferedType?)
参数解释:
input是输入的值,即要转换的对象,必选;
preferedType是期望转换的基本类型,他可以是字符串,也可以是数字。选填,默认为number;
执行过程:
如果转换的类型是number,会执行以下步骤:
-
如果input是原始值,直接返回这个值;
-
否则,如果input是对象,调用input.valueOf(),如果结果是原始值,返回结果;
-
否则,调用input.toString()。如果结果是原始值,返回结果;
-
否则,抛出错误。
如果转换的类型是String,2和3会交换执行,即先执行toString()方法。
你也可以省略preferedType,此时,日期会被认为是字符串,而其他的值会被当做Number。
总结
如果转换的类型是number,先执行valueOf(),如果没有返回原始值,再执行toString()
如果转换的类型是String,先执行toString(),如果没有返回原始值,再执行valueOf()
★ == vs ===
对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换
对于 === 来说就简单多了,就是判断两者类型和值是否相同。