JavaScript | 2020-07-23 18:27:06 1068次 6次
一、栈(stack)和堆(heap)
stack 为自动分配的内存空间,它由系统自动释放;而 heap 则是动态分配的内存,大小也不一定会自动释放
二、数据类型
JS 分两种数据类型:
基本数据类型:Number、String、Boolean、Null、 Undefined、Symbol(ES6),这些类型可以直接操作保存在变量中的实际值,存放在栈中。
引用数据类型:Object(在JS中除了基本数据类型以外的都是对象,数组是对象,函数是对象,正则表达式是对象)。引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存。通过这个引用地址可以快速查找到保存中堆内存中的对象
三、数据类型判断
这个看似很简单的一个问题,放在 js 中彷佛没有那么简单了,大致可以通过四种方式来判断,各有优缺点,某些情况下还需要相互结合使用。
1.typeof
先看下它的底层表示,在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:
000:对象
1:整数
010:浮点数
100:字符串
110:布尔
undefined:用 - (−2^30)表示
null:对应机器码的 NULL 指针,一般是全零,所以 typeof null = 'object'
基本数据类型判断:
typeof ""; //string typeof 1; //number typeof false; //boolean typeof undefined; //undefined typeof Symbol(); //symbol
引用数据类型判断:
typeof function(){}; //function typeof {}; //object typeof null; //object typeof []; //object typeof new Date(); //object typeof new RegExp(); //object
使用 typeof 对基本数据类型判断没问题,引用数据类型判断就不灵了。
2.instanceof
它是用来判断 left 是否 right 的实例,具体使用可以查看上一篇中的原型和继承,看下这个方法的模拟实现:
function instance(left,right){ let prototype = right.prototype; let proto = Object.getPrototypeOf(left); //__proto__ while(true){ //按照上篇文章中那张图,到终点了指向null 或者找不到原型 if (proto === null || proto === undefined){ return false; } if (proto === prototype){ return true; } //沿着链 继续往下找 proto = Object.getPrototypeOf(proto); } } console.log(instance({},Object)); //true console.log(instance([],Number)); //false
针对基本数据类型判断通过这个方法是无效的。
引用数据类型判断:
({}) instanceof Object; //true [] instanceof Array; //true [] instanceof Object; //true (()=>{}) instanceof Function; // true (()=>{}) instanceof Object; // true new String(123) instanceof String; //true 通过new 构造的 类型是object
可见通过这种方式判断数据类型是不安全的。
3.constructor
它可以让对象诞生以后,就具有可追溯的数据类型,参照上篇的原型图,构造函数的 prototype 上有一个 constructor 属性,并让其指向构造函数。
'1'.constructor == String // true new String('1').constructor == String //true new String('1').constructor == Object //false (1).constructor == Number // true new Number(1).constructor == Number //true new Number(1).constructor == Object // false true.constructor == Bollen // true [].constructor == Array //true [].constructor == Object//false (()=>{}).constructor == Function //true (()=>{}).constructor == Object //false
constructor 判断无法判断 null 和 undefined,通过 new String('1') 这种方式判断也是不准确的。
4.Object.prototype.toString()
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]]。这是一个内部属性,其格式为 [object Xxx],其中 Xxx 就是对象的类型。但是对于其他对象,则需要通过 call、apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call([]) "[object Array]" Object.prototype.toString.call('') "[object String]"
采用这个方法可以完美的判断所有数据类型(NaN 除外,这个方法判断会返回 Number,使用 isNaN 判断,isNaN() 不传值或者值为 NaN 时返回 true),比如可以封装为一个函数:
let isString = obj => Object.prototype.toString.call( obj ) === '[object String]'; isString('') //true isString(11) // false
但是这么多类型一个个创建函数太麻烦,可以通过高阶函数方式封装一个抽象的方法:
let isType = type => obj => { return Object.prototype.toString.call( obj ) === '[object ' + type + ']'; }
isType('String')('123'); // true isType('Array')([1, 2, 3]); // true isType('Number')(123); // true
6人赞