概念
首先明确ECMAscript中的数据类型分为两种:基本类型和引用类型
基本类型:即简单的数据段,都是按值访问的,即将一个基本类型的数据赋值给另外一个变量,是通过将原数据拷贝一份赋值的,两变量之间互不影响。如图:
引用类型:即保存在内存中的对象,按引用访问,即将一个引用类型的地址赋值给另一个变量,当该变量改变时,原变量也会随之改变。如图:
分类
基本类型有:
Undefined
,Null
,Boolean
,Number
,String
;引用类型:
1.第一类:原生对象(ECMAScript本身自带对象,有程序员在脚本运行环境中创建来使用):
object
,Array
,Date
,RegExp
,Function
,基于基本类型还衍生出来了三个包装类型:Boolean
,Number
,String
,每当我们读取一个基本数据类型的实例时,后台都会创建一个对应的基本包装类型,从而使我们可以使用不是对象的基本类型调用相应的方法。
基本包装类型和引用类型的区别
使用new
操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存内存中,而自动创建的基本包装类型的对象,只存在于一行代码执行的瞬间,然后立即被销毁,即我们不能在运行时为基本类型值添加属性和方法。如图:
typeof和Object.prototype.toString()辨析
typeof会判断数据类型会返回一个
字符串
,如下图
// Numberstypeof 37 === 'number';typeof 3.14 === 'number';typeof Math.LN2 === 'number';typeof Infinity === 'number';typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"typeof Number(1) === 'number'; // 不要这样使用!// Stringstypeof "" === 'string';typeof "bla" === 'string';typeof (typeof 1) === 'string'; // typeof返回的肯定是一个字符串typeof String("abc") === 'string'; // 不要这样使用!// Booleanstypeof true === 'boolean';typeof false === 'boolean';typeof Boolean(true) === 'boolean'; // 不要这样使用!// Symbolstypeof Symbol() === 'symbol';typeof Symbol('foo') === 'symbol';typeof Symbol.iterator === 'symbol';// Undefinedtypeof undefined === 'undefined';typeof blabla === 'undefined'; // 一个未定义的变量,或者一个定义了却未赋初值的变量// Objectstypeof {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
.
//分组选择符?难道这不是逗号表达式么?恩,回头细究~
题六:这个比较好玩
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.prototypeo instanceof C; // false,因为 D.prototype不在o的原型链上o instanceof D; o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回trueD.prototype = new C(); // 继承var o3 = new D();o3 instanceof D; // trueo3 instanceof C; // true
ps:prototypeObj.isPrototypeOf(object)用于测试一个对象是否存在于另一个对象的原型链上,object为被搜索原型链的对象
ps2:参考文献中有这样一个警示,然而我没看懂...明日回更,欢迎评论指点。