在什么时候,Javascript 的 “typeof” 可能会返回不正确的类型?
我正在尝试理清别人的代码,并发现了一些奇怪的东西。我在程序的一部分中发现了以下代码:
if(typeof func == "function" || (typeof func == "object" && typeof func.document == "undefined"))
{
func();
}
这对我来说毫无意义,因为我不确定这样的事件什么时候会发生?typeof 有可能返回错误的类型吗?或者非函数对象有可能是可调用的吗?
代码很混乱,所以我真的找不到这个特定检查可能成功的例子。我应该指出,这段代码可能有十多年历史。我收到的说明是之所以需要这个检查,是因为有时在代码最初编写时,typeof 并没有返回 function 类型。
此外,需要进行此检查,因为有时函数会被传递一个 window 对象(?),因此有必要确保它不是一个 window 对象。
答案#1
记住:typeof 用于字面量。
typeof undefined === "undefined"
typeof 5 === "number"
typeof true === "boolean"
typeof "" === "string"
typeof {} === "object"
typeof [] === "object"
typeof function { } === "function"
// null is a weird exception:
typeof null === "object"
instanceof 用来区分某物何时是 “Function 类型的”(注意 typeof 检查的是字符串 "object",而 instanceof 检查的是 Function Object 本身:
{} instanceof Object
function {} instanceof Object
function {} instanceof Function
[] instanceof Object
[] instanceof Array
如你所见,typeof 显示 === "function" 和 !== "object":这可能会令人误解,因为函数也是对象。这时就用到了 instanceof。
现在,当你编写一个构造函数时,构造出的对象也是你函数的实例:
// the constructor
function Example { }
// the object
var ex = new Example();
typeof Example === "function"
typeof ex === "object"
ex instanceof Object
ex instanceof Example
使用原型你也可以扩展链,typeof 总是返回 object:
function DerivedExample { }
DerivedExample.prototype = new Example();
// DerivedExample.prototype.constructor = DerivedExample;
var ex1 = new DerivedExample();
typeof DerivedExample === "function"
typeof ex1 === "object"
ex1 instanceof Object
ex1 instanceof Example
ex1 instanceof DerivedExample
以上就是关于 JavaScript 中 typeof 和 instanceof 的所有内容。希望能澄清发生了什么。
还有一些也值得知道的事情(这不建议在生产代码中使用,但据我所知也在 CoffeeScript 源码中见过):
typeof new Number(5) === "object"
new Number(5) instanceof Object
new Number(5) instanceof Number
typeof new Boolean("true") === "object"
new Boolean("true") instanceof Object
new Boolean("true") instanceof Boolean
typeof new String("") === "object"
new String("") instanceof Object
new String("") instanceof String
关于函数和窗口对象:
每个独立函数将在 window 的上下文中调用。
(除非)当你使用 "use strict" 指令时,独立函数将以 undefined 作为上下文调用。
function world() {
// non-strict: this === window
// use-strict: this === undefined
}
world();
现在,当你将一个函数作为对象的成员来编写时,该函数的上下文就是对象:
var hello = {
world: function () {
// this === hello
}
};
hello.world();
这对于在新构建对象的上下文中调用的原型函数也同样适用:
function Hello() { }
Hello.prototype.world = function () {
// this instanceof Hello
// this will be === ex
};
var ex = new Hello();
ex.world();
至少,你可以使用 call 和 apply 改变任何函数的上下文:
var ex = { };
function Example() {
// (1) non-strict: this === window
// (1) use-strict: this === undefined
// (2) this === ex
}
Example(); // (1)
Example.call(ex); // (2)
Example.apply(ex); // (2)
答案#2
考虑这个例子
var a = [];
typeof a; // object
Object.prototype.toString.call(a); // [object Array]
var b = {};
typeof b; // object
Object.prototype.toString.call(b); // [object Object]
所以是的,typeof 有时确实会让人困惑
