【面试篇】JS数据类型及判断

静书

概念

首先明确ECMAscript中的数据类型分为两种:基本类型和引用类型

  • 基本类型:即简单的数据段,都是按值访问的,即将一个基本类型的数据赋值给另外一个变量,是通过将原数据拷贝一份赋值的,两变量之间互不影响。如图:
    clipboard.png

  • 引用类型:即保存在内存中的对象,按引用访问,即将一个引用类型的地址赋值给另一个变量,当该变量改变时,原变量也会随之改变。如图:
    clipboard.png

分类

  • 基本类型有:Undefined,Null,Boolean,Number,String;

  • 引用类型:
    1.第一类:原生对象(ECMAScript本身自带对象,有程序员在脚本运行环境中创建来使用):

object,Array,Date,RegExp,Function,基于基本类型还衍生出来了三个包装类型:Boolean,Number,String,每当我们读取一个基本数据类型的实例时,后台都会创建一个对应的基本包装类型,从而使我们可以使用不是对象的基本类型调用相应的方法。
2.第二类内置对象(JS语言提供的不依赖于执行宿主的对象,如Global,Math)。
3.宿主对象(JS语言提供的任何依赖宿主环境的对象,如IE中的window,WS中的WScript实例,以及任何用户创建的类)

  • 基本包装类型和引用类型的区别
    使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存内存中,而自动创建的基本包装类型的对象,只存在于一行代码执行的瞬间,然后立即被销毁,即我们不能在运行时为基本类型值添加属性和方法。如图:clipboard.png

typeof和Object.prototype.toString()辨析

  • typeof会判断数据类型会返回一个字符串,如下图

// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"
typeof Number(1) === 'number'; // 不要这样使用!

// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的肯定是一个字符串
typeof String("abc") === 'string'; // 不要这样使用!

// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 不要这样使用!

// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';

// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一个未定义的变量,或者一个定义了却未赋初值的变量

// Objects
typeof {a:1} === 'object';

// 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型
typeof [1, 2, 4] === 'object';

typeof new Date() === 'object';

// 下面的容易令人迷惑,不要这样使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) ==== 'object';
typeof new String("abc") === 'object';

// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';

由以上结果可知typeof在数组,正则,日期,对象上的判断并不好,都是返回object
由此可以引出另一个判断方法Object.prototype.toString();toString()方法返回一个描述某对象的字符串,如果此方法在自定义的对象中未被覆盖,则toString()返回"[object type]",其中type是对象类型。在使用toString()方法检测对象类型时,常用Object.prototype.toString.call()Object.prototype.toString.apply()来检测,如下代码:

var toString = Object.prototype.toString;
toString.call(new Date);//[object Date]
toString.call(new String);//[object String]
toString.call(Math);//[object Math]
toString.call(undefined);//[object Undefined]
toString.call(null);//[object Null]

牛刀小试

题一:

var y = 1, x = y = typeof x;
x;

//out:"undefined",因为x变量提升,故typeof时,不为null

题二:

  (function f(f){
    return typeof f();
  })(function(){ return 1; });

//out:"number",因为在立即执行函数里将function(){return 1}当做实参传递给了形参f,故当f执行后返回1,typeof 1便返回"number"

题三:

  var foo = {
    bar: function() { return this.baz; },
    baz: 1
  };
  (function(){
    return typeof arguments[0]();
  })(foo.bar);

//out:"undefined",考察this指针,除了ES6的箭头函数以外,this指针永远指向函数执行时的上下文对象,在此处传入arguments[0]中,this指向window对象,故为undefined.

clipboard.png
//分组选择符?难道这不是逗号表达式么?恩,回头细究~

题六:这个比较好玩

  var x = 1;
  if (function f(){}) {
    x += typeof f;
  }
  x;//

//out:"1undefined",本以为会是1function呢,结果看了解析才知道,是因为javascript语言规范的问题,在条件判断中加入函数声明,会返回true,然而javascript引擎在搜索时找不到该函数,所以结果为1undefined

题七:

  (function(foo){
    return typeof foo.bar;
  })({ foo: { bar: 1 } });

//out:undefined ,噗,看成"numberl"了,函数里的foo指向整个对象,然而整个对象并没有bar属性

instanceof辨析

indtanceof用来判断某个构造函数的prototype属性是否存在于要检测对象的原型链上,如下:

// 定义构造函数
function C(){} 
function D(){} 

var o = new C();
// true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof C; 
// false,因为 D.prototype不在o的原型链上
o instanceof D; 
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true

ps:prototypeObj.isPrototypeOf(object)用于测试一个对象是否存在于另一个对象的原型链上,object为被搜索原型链的对象

ps2:参考文献中有这样一个警示,然而我没看懂...明日回更,欢迎评论指点。
clipboard.png

阅读 6.5k

Aleen_Zhang的前端进阶之路
专注,极致,热爱

简书

595 声望
55 粉丝
0 条评论

简书

595 声望
55 粉丝
文章目录
宣传栏