网站搜索

在什么时候,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 有时确实会让人困惑