typeof函数不是一个函数。

4

我的同事给我展示了下面的代码,让我大吃一惊:

const x = Object.create(function() {});
// variant: const x = Object.create(Array);
console.log(x.call) // ƒ call() { [native code] }
console.log(typeof x.call) // "function"
console.log(x.call instanceof Function) // true
x.call() // Uncaught TypeError: x.call is not a function

我理解x.call是从function原型继承而来的,它不属于x的属性:

x.hasOwnProperty('call') // false

但是为什么x.call不能实际执行呢?这与call关键字有关吗?


6
有时更精确的错误信息会很有用,Firefox 提示:"TypeError: Function.prototype.call called on incompatible Object"。 - Teemu
请注意,变量 x 没有函数体。您无法调用没有函数体的函数。 - Alnitak
2
还要注意,将一个类型的实例传递给Object.create并不会产生与传递该类型的原型相同的结果。通常情况下,你应该选择后者。 - Alnitak
2个回答

4
Object.create的核心思想可以概括为:
function create(prt){
    var noOP = function(){};
    noOP.prototype = prt;
    return new noOP;
}

因此,返回的值不是函数,而是对象。为了说明这一点,我首先会存储一个函数:

var u = function(){return 5}

现在我将在它上面使用 "Object.create":
var res = create(u);

安慰后,你会得到>noOP {},所以这是一个普通对象。问题就从这里开始:

res.hasOwnProperty("prototype") //false

因此,新创建的对象具有"prototype",但实际上是从u继承而来的。

res.prototype === u.prototype //true

同样的,“call”是再次从u继承而来,而u又继承自其构造函数(Function)的原型:

res.call === u.call //true
res.call === Function.prototype.call //also true

以下是您的问题,如果您查看call的EcmaScript实现,它期望一个可调用的this。请将callres中隔离出来:

var x = res.call; //ƒ call() { [native code] }

现在我将“调用”该调用,我们将传递3个参数,第一个是要调用的内容,第二个是在可调用内部设置this,第三个及以后是可调用的参数:

x.call(function(a){console.log("hey");console.log(a);console.log(this);},5,5)
//hey
//5
//Number {5}

现在尝试在您创建的对象res上执行相同操作,可以使用res.callx.call进行调用。
x.call(res,5,5) //TypeError: x.call is not a function

最终,问题归结为从Object.create返回的对象不可调用。

3
因为对象 x 继承了来自 Function.prototypecall,然而 call 是用于函数调用的,所以如果你试图在一个普通对象上执行它,它会失败。

在Chrome浏览器中,Function.prototype.call()返回undefined,并且不会产生错误。 - Alnitak
@alnitak 噢,看起来Function.prototype()本身就是一个函数... - Jonas Wilms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接