frontend-notes

数据类型

7种原始类型(基本类型、基本数据类型)

基本数据类型的值是按值访问的

一种既非对象也无方法的数据,所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。变量会被赋予一个新值,而原值不能像数组、对象以及函数那样被改变。

引用类型/Object 类型

引用类型的值是按引用访问的。查看所有的标准内置对象

除过上面的 7 种基本数据类型外,剩下的就是引用类型了,统称为 Object 类型。细分的话,有:Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型 等。typeof instance === "object"。

记住 typeof 操作符的唯一目的就是检查数据类型,如果我们希望检查任何从 Object 派生出来的结构类型,使用 typeof 是不起作用的,因为总是会得到 “object”。检查 Object 种类的合适方式是使用 instanceof 关键字。但即使这样也存在误差。详情看下面的”判断类型的方法“小节

判断类型的方法

typeof

经常用来检测一个变量是不是最基本的数据类型,适合用于比较简单的场景,如特定类型判断,是否是字符串、是否是函数等

var a;
typeof a;    // undefined

a = null;
typeof a;    // object

a = true;
typeof a;    // boolean

a = 666;
typeof a;    // number

a = "hello";
typeof a;    // string

a = Symbol();
typeof a;    // symbol

a = function(){}
typeof a;    // function

a = [];
typeof a;    // object
a = {};
typeof a;    // object
a = /aaa/g;
typeof a;    // object

优点:

局限性:

这是浏览器的BUG:所有的值在计算中都以二进制编码储存,浏览器中把前三位000的当作对象,而null的二进制前三位是000,所以被识别为对象,但是他不是对象,他是空对象指针,是基本类型值。详细讲解可以看这篇文章: 浅谈 instanceof 和 typeof 的实现原理

instanceof

用来判断某个构造函数的 prototype 属性所指向的对象是否存在于另外一个要检测对象的原型链上,简单说就是判断一个引用类型的变量具体是不是某种类型的对象(注意:instanceof 后面一定要是对象类型,并且大小写不能错) 适合用于判断【自定义的类】实例对象, 而不是用来判断原生的数据类型

({}) instanceof Object              // true
([]) instanceof Array               // true
(/aa/g) instanceof RegExp           // true
(function(){}) instanceof Function  // true

优点:

局限性:

Object.prototype.toString

返回一个表示该对象的字符串,适合用于检查【内置类】

使用Object.prototype.toString检查对象类型

Object.prototype.toString 的原理是当调用的时候, 就取值内部的 [[Class]] 属性值, 然后拼接成 ‘[object ‘ + [[Class]] + ‘]’ 这样的字符串并返回. 然后我们使用 call 方法来获取任何值的数据类型.

Object.prototype.toString.call("123")           // [object String]
Object.prototype.toString.call(123)             // [object Number]
Object.prototype.toString.call(new Date());     // [object Date]
Object.prototype.toString.call(true);           // [object Boolean]
Object.prototype.toString.call([1,2,3]);        // [object Array]
Object.prototype.toString.call(function () {}); // [object Function]
Object.prototype.toString.call(Math);           // [object Math]
Object.prototype.toString.call(undefined);      // [object Undefined]
Object.prototype.toString.call(null);           // [object Null]
Object.prototype.toString.call(/\d/);           // [object RegExp]
Object.prototype.toString.call(Symbol);         // [object Symbol]

优点:

局限性:

此方法是基于JS本身专门进行数据检测的,所以是目前检测数据类型比较好的方法。

总结

检查内置类

function _typeof(obj){
  var s = Object.prototype.toString.call(obj);
  return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};
// or
function type(obj) {
  return typeof obj !== "object" ? typeof obj : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

单独检测

/**
 * @desc 是否是 Undefined 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isUndefined(obj) {
    return obj === void 0;
}
/**
 * @desc 是否是 Null 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isNull(obj) {
    return obj === null;
}
/**
 * @desc 是否是 Boolean 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isBoolean(obj) {
    return typeof(obj) === 'boolean';
}
/**
 * @desc 是否是 Number 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isNumber(obj) {
    return typeof(obj) === 'number';
}
/**
 * @desc 是否是 String 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isString(obj) {
    return typeof(obj) === 'string';
}
/**
 * @desc 是否是 Object 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
 * @desc 是否是 Array 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isArray(obj){
    return Array.isArray?Array.isArray(obj):Object.prototype.toString.call(obj) === '[object Array]';
}
/**
 * @desc 是否是 Function 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isFunction(obj){
    return typeof(obj) === 'function';
}
/**
 * @desc 是否是 Date 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isDate(obj){
    return Object.prototype.toString.call(obj) === '[object Date]';
}
/**
 * @desc 是否是 RegExp 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isRegExp(obj){
    return Object.prototype.toString.call(obj) === '[object RegExp]';
}
/**
 * @desc 是否是 Error 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isError(obj){
    return Object.prototype.toString.call(obj) === '[object Error]';
}
/**
 * @desc 是否是 Arguments 类型检测
 * @param obj 待检测的数据
 * @return {Boolean} 布尔值
 */
function isArguments(obj){
    return Object.prototype.toString.call(obj) === '[object Arguments]';
}

其他问题

说说你对javascript是弱类型语言的理解?

JavaScript 是弱类型语言,而且JavaScript 声明变量的时候并没有预先确定的类型,变量的类型就是其值的类型,也就是说变量当前的类型由其值所决定,夸张点说上一秒种的String,下一秒可能就是个Number类型了,这个过程可能就进行了某些操作发生了强制类型转换。虽然弱类型的这种不需要预先确定类型的特性给我们带来了便利,同时也会给我们带来困扰,为了能充分利用该特性就必须掌握类型转换的原理。

基础类型和引用类型存储上有什么区别?

  1. 存储位置不同
    • 基本数据类型:以栈的形式存储, 保存与赋值指向数据本身, 用typeof 来判断类型,存储空间固定。
    • 引用类型:以堆的形式存储, 保存于赋值指向对象的一个指针, 用instanceof 来判断类型 , 存储空间不固定。
  2. 传值方式不同
    • 基本数据类型按值传递,无法改变一个基本数据类型的值
    • 引用类型按引用传递,应用类型值可以改变

堆和栈的区别 堆是动态分配内存,内存大小不一,也不会自动释放。栈是自动分配相对固定大小的内存空间,并由系统自动释放。

javascript的基本类型就5种:Undefined、Null、Boolean、Number和String,它们都是直接按值存储在栈中的,每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说,更加容易管理内存空间。

javascript中其他类型的数据被称为引用类型的数据 : 如对象(Object)、数组(Array)、函数(Function) …,它们是通过拷贝和new出来的,这样的数据存储于堆中。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据。

null 和 undefined 有什么区别

null 和 undefined 究竟有何区别

为什么 Object.prototype.toString.call(null) 输出 ‘[object Null]’

toString()Object的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

JavaScript 万物皆对象,为什么 xxx.toString() 不能返回变量类型? 这是因为 各个类中重写了toString的方法,因此需要调用Object中的toString方法,必须使用toString.call()的方式调用。 对于 Object 对象,直接调用toString()就能返回'[object Object]' 。而对于其他对象,则需要通过call / apply来调用才能返回正确的类型信息。

Objects vs. Maps

使用场景

虽然 Map 在很多情况下会比 Object 更为高效,不过 Object 永远是 JS 中最基本的引用类型,它的作用也不仅仅是为了储存键值对。

js中的强制转换规则

参考