微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

谈谈我对JavaScript中typeof和instanceof的深入理解

这次主要说说javascript的类型判断函数typeof和判断构造函数原型instanceof的用法和注意的地方。

typeof

先来说说typeof吧。首先需要注意的是,typeof方法返回一个字符串,来表示数据的类型。

typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。

它返回值是一个字符串,该字符串说明运算数的类型。typeof 一般只能返回如下几个结果: number,boolean,string,function,object,undefined。我们可以使用 typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

语法讲解

我们先看看各个数据类型对应typeof的值:

ottom: 0px; widows: 1; text-transform: none; text-indent: 0px; margin: 0px 0px 16px; padding-left: 0px; border-spacing: 0px; width: 639px; letter-spacing: normal; padding-right: 0px; border-collapse: collapse; font: 14px/25px 'microsoft yahei'; white-space: normal; empty-cells: show; color: rgb(68,68,68); border-top: rgb(221,221) 1px solid; word-spacing: 0px; padding-top: 0px; -webkit-text-stroke-width: 0px"> ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">
ottom: rgb(221,221) 1px solid; text-align: center; padding-bottom: 5px; background-color: rgb(249,249,249); margin: 0px; padding-left: 10px; padding-right: 10px; border-right: rgb(221,221) 1px solid; padding-top: 5px">数据类型 ottom: rgb(221,221) 1px solid; padding-top: 5px">Type
ottom: rgb(221,221) 1px solid; padding-bottom: 5px; margin: 0px; padding-left: 10px; padding-right: 10px; border-right: rgb(221,221) 1px solid; padding-top: 5px">Undefinedottom: rgb(221,221) 1px solid; padding-top: 5px">“undefined”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">Nullottom: rgb(221,221) 1px solid; padding-top: 5px">“object”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">布尔值ottom: rgb(221,221) 1px solid; padding-top: 5px">“boolean”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">数值ottom: rgb(221,221) 1px solid; padding-top: 5px">“number”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">字符串ottom: rgb(221,221) 1px solid; padding-top: 5px">“string”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">Symbol (ECMAScript 6 新增)ottom: rgb(221,221) 1px solid; padding-top: 5px">“symbol”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">宿主对象(JS环境提供的,比如浏览器)ottom: rgb(221,221) 1px solid; padding-top: 5px">Implementation-dependentottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">函数对象ottom: rgb(221,221) 1px solid; padding-top: 5px">“function”ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">任何其他对象ottom: rgb(221,221) 1px solid; padding-top: 5px">“object”

再看看具体的实例:

rush:js;"> // 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来判断数据类型其实并不准确。比如数组、正则、日期、对象的typeof返回值都是object,这就会造成一些误差。

所以在typeof判断类型的基础上,我们还需要利用Object.prototype.toString方法来进一步判断数据类型。

我们来看看在相同数据类型的情况下,toString方法和typeof方法返回值的区别:

ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">
ottom: rgb(221,221) 1px solid; padding-top: 5px">toString ottom: rgb(221,221) 1px solid; padding-top: 5px">typeof
ottom: rgb(221,221) 1px solid; padding-top: 5px">“foo”ottom: rgb(221,221) 1px solid; padding-top: 5px">Stringottom: rgb(221,221) 1px solid; padding-top: 5px">stringottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">new String(“foo”)ottom: rgb(221,221) 1px solid; padding-top: 5px">objectottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">new Number(1.2)ottom: rgb(221,221) 1px solid; padding-top: 5px">Numberottom: rgb(221,221) 1px solid; padding-top: 5px">trueottom: rgb(221,221) 1px solid; padding-top: 5px">Booleanottom: rgb(221,221) 1px solid; padding-top: 5px">booleanottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> ottom: rgb(221,221) 1px solid; padding-top: 5px">new Boolean(true)ottom: rgb(221,221) 1px solid; padding-top: 5px">new Date()ottom: rgb(221,221) 1px solid; padding-top: 5px">Dateottom: rgb(221,221) 1px solid; padding-top: 5px">new Error()ottom: rgb(221,221) 1px solid; padding-top: 5px">Errorottom: rgb(221,221) 1px solid; padding-top: 5px">new Array(1,3)ottom: rgb(221,221) 1px solid; padding-top: 5px">Arrayottom: rgb(221,221) 1px solid; padding-top: 5px">/abc/gottom: rgb(221,221) 1px solid; padding-top: 5px">RegExpottom: rgb(221,221) 1px solid; padding-top: 5px">new RegExp(“meow”)ottom: rgb(221,221) 1px solid; padding-top: 5px">object

可以看到利用toString方法可以正确区分出Array、Error、RegExp、Date等类型。

所以我们一般通过该方法来进行数据类型的验证

真题检测

但是既然今天说到了typeof,那这里就列出几道题目,来看看自己是否真正掌握了typeof的用法

第一题:

rush:js;"> var y = 1,x = y = typeof x; x;

第二题:

rush:js;"> (function f(f){ return typeof f(); })(function(){ return 1; });

第三题:

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

第四题:

rush:js;"> var foo = { bar: function(){ return this.baz; },baz: 1 } typeof (f = foo.bar)();

第五题:

rush:js;"> var f = (function f(){ return "1"; },function g(){ return 2; })(); typeof f;

第六题:

rush:js;"> var x = 1; if (function f(){}) { x += typeof f; } x;

第七题:

rush:js;"> (function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });

下面公布答案了,这七题的答案分别是:

"undefined","number","undefined","1undefined","undefined"

做对了几道呢?是不是很大的困惑呢?这几题虽然都有typeof,但是考察了很多javascript的基础噢。下面我们来一一详解。

第一题:

rush:js;"> var y = 1,x = y = typeof x; x;//"undefined"

表达式是从右往左的,x由于变量提升,类型不是null,而是undefined,所以x=y=”undefined”。

变量提升我在这文章中提到过,可以看看。

第二题:

rush:js;"> (function f(f){ return typeof f();//"number" })(function(){ return 1; });

传入的参数为f也就是function(){ return 1; }这个函数。通过f()执行后,得到结果1,所以typeof 1返回”number”。这道题很简单,主要是区分f和f()。

第三题:

rush:js;"> var foo = { bar: function() { return this.baz; },baz: 1 }; (function(){ return typeof arguments[0]();//"undefined" })(foo.bar);

这一题考察的是this的指向。this永远指向函数执行时的上下文,而不是定义时的(ES6的箭头函数不算)。当arguments执行时,this已经指向了window对象。所以是”undefined”。对this执行不熟悉的同学可以看看这篇文章:深入理解this,对刚刚提到的箭头函数感兴趣的同学可以看看初步探究ES6之箭头函数

第四题:

rush:js;"> var foo = { bar: function(){ return this.baz; },baz: 1 } typeof (f = foo.bar)();//undefined

如果上面那一题做对了,那么这一题也应该不会错,同样是this的指向问题。

第五题:

rush:js;"> var f = (function f(){ return "1"; },function g(){ return 2; })(); typeof f;//"number"

这一题比较容易错,因为我在遇到这道题之前也从来没有遇到过javascript的分组选择符。什么叫做分组选择符呢?举一个例子就会明白了:

rush:js;"> var a = (1,3); document.write(a);//3,会以最后一个为准

所以上面的题目会返回2,typeof 2当然是”number”啦。

第六题:

rush:js;"> var x = 1; if (function f(){}) { x += typeof f; } x;//"1undefined"

这是一个javascript语言规范上的问题,在条件判断中加入函数声明。这个声明语句本身没有错,也会返回true,但是javascript引擎在搜索的时候却找不到该函数。所以结果为”1undefined”。

第七题:

rush:js;"> (function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });

这题其实是一个考察心细程度的题目。形参的foo指向的是{ foo: { bar: 1 } }这个整体。相信这么说就明白了。

好啦。上面的题目都是很好的资源噢。

instanceof

接下来该说说instanceof方法了。instanceof运算符可以用来判断某个构造函数的prototype属性是否存在于另外一个要检测对象的原型链上。

instanceof 用于判断一个变量是否某个对象的实例,如 var a=new Array();alert(a instanceof Array); 会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。再如:function test(){};var a=new test();alert(a instanceof test) 会返回

谈到 instanceof 我们要多插入一个问题,就是 function 的 arguments,我们大家也许都认为 arguments 是一个 Array,但如果使用 instaceof 去测试会发现 arguments 不是一个 Array 对象,尽管看起来很像。

如果对原型不太了解,可以看看深入理解原型。

下面我们看看instanceof的实例:

rush:js;"> // 定义构造函数 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 C.prototype instanceof Object // true,同上 C.prototype = {}; var o2 = new C(); o2 instanceof C; // true o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上. D.prototype = new C(); // 继承 var o3 = new D(); o3 instanceof D; // true o3 instanceof C; // true

但是这里我们需要注意一个问题:

rush:js;"> function f(){ return f; } document.write(new f() instanceof f);//false function g(){} document.write(new g() instanceof g);//true

一个为什么返回false呢?因为构造函数的原型被覆盖了,我们可以看看new f和new g的区别:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐