概念
首先明确ECMAscript中的数据类型分为两种:基本类型和引用类型
基本类型:即简单的数据段,都是按值访问的,即将一个基本类型的数据赋值给另外一个变量,是通过将原数据拷贝一份赋值的,两变量之间互不影响。如图:
引用类型:即保存在内存中的对象,按引用访问,即将一个引用类型的地址赋值给另一个变量,当该变量改变时,原变量也会随之改变。如图:
分类
基本类型有:
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
操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存内存中,而自动创建的基本包装类型的对象,只存在于一行代码执行的瞬间,然后立即被销毁,即我们不能在运行时为基本类型值添加属性和方法。如图:
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
.
//分组选择符?难道这不是逗号表达式么?恩,回头细究~
题六:这个比较好玩
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:参考文献中有这样一个警示,然而我没看懂...明日回更,欢迎评论指点。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。