与JavaScript中的Prototype混淆

时间:2015-11-25 18:58:11

标签: javascript

1

我阅读了Douglas Crockford的JavaScript Good Parts一书。在本书中,method已添加到Function.prototype

一个。

Function.prototype.method = function() {}

Function.prototype.method === Function.method; // true

function MyClass() {}

MyClass.prototype.method = function() {}

MyClass.prototype.method == MyClass.method // false

infact MyClass.method未定义。

为什么在步骤a中为true,在步骤b中为false?

2

请解释以下内容:

Object instanceof Function    // true
Function instanceof Object    // true
Object instanceof Object      // true
Function instanceof Function  // true

这非常令人困惑。请用简单的词语解释。

2 个答案:

答案 0 :(得分:4)

<强> 1

a)您刚刚扩展了Function内置对象,现在每个Function实例都附加了该属性,包括实例中构建的Function。

b)您刚刚使用方法扩展了MyClass,现在MyClass的每个实例都附加了该方法。 但是,MyClass不是MyClass的实例,因此该方法不存在。

<强> 2

这些是该语言的标准内置对象。它们是可以返回实例的实例。关于Object,它的原型与所有东西共享,因为一切都来自Object - 一般来说最好避免改变它的原型。

这就是为什么看起来Function是Object的一个实例。一切都是。每个实例都派生自Function,因此Object实例也是Function的一个实例。而这恰恰相反。

还有一整套其他基本对象,例如,Object不是Number的实例,但Number是Object和Function的实例。

有关此列表的更多信息,请访问https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects

下面显示的只是这些对象的一小部分,因为列表中包含一些很可能不感兴趣的对象(例如URIError)。

  • 对象
  • 功能
  • 布尔
  • 符号
  • 错误
  • 数学
  • 日期
  • 字符串
  • 正则表达式
  • 阵列
  • JS​​ON
  • 承诺

答案 1 :(得分:1)

<强> 1a上。

01 Function.prototype.method = function foo() {}
02 Function.prototype.method === Function.method; // true

这是向内置prototype函数对象的Function属性所指向的对象添加属性。

Function是一个名为“Function”的内置函数对象实例。 因此,Function是一个对象,因为函数是对象。 由于Function是一个函数,因此它具有prototype属性。在这种情况下,它是另一个功能对象。

上面的第1行向method添加了一个名为Function.prototype的属性,将其指向函数对象foo(为清晰起见而命名)。

第2行对Function.prototype.method(在第1行中创建)和尝试在内置{{1}上获取与属性method相关联的值的结果进行测试。函数对象。 JavaScript中的属性解析是通过搜索由原型链链接的对象链来执行的。

因此,第2行Function会立即找到该属性,因为Function.prototype.method属性直接位于method上。

同样在第2行,Function.prototype上的Function.method 。然后通过查看Function属性指向的内容继续搜索(这称为原型链)。 JavaScript中的Function.__proto__引用自动指向创建它的函数的__proto__属性。在这种情况下,因为我们位于原型链的顶端(这是最顶层的函数!),我们有一个不寻常的情况,内置的prototype“创建了自己“(实际上Function是由运行时本身创建的,在userland代码之外),这意味着Functionprototype属性 - 在这个例子中 - 指向同一个对象。

因此,在__proto__链接后搜索method,找到__proto__指向的同一对象,并在那里找到属性Function.prototype。因此:

method

<强> 1b中。

02 Function.prototype.method === Function.method; // true

这是普通的用户态代码,我们没有像1a中那样找到最顶层 01 function MyClass() {} 02 MyClass.prototype.method = function foo() {} // Named for clarity. 03 MyClass.prototype.method == MyClass.method // false 04 // infact MyClass.method is undefined. 对象的原型的相同问题。

一旦声明它(上面的第1行),Function就像每个函数一样获得MyClass属性,指向空对象实例。

第2行向此空对象实例添加属性prototype,并将其指向函数method

第3行测试foofoo上寻找属性method的结果之间的参考相等性。和以前一样,要在MyClass上查找method,我们会执行搜索。它不直接存在于MyClass上,因此检查位于属性MyClass上的对象是否有一个名为method的属性(同样,这是遍历的原型链)。在这种情况下,就像1a(以及JavaScript中的每个对象)一样,__proto__指向创建对象的函数的__proto__属性。函数对象prototype由内置的MyClass函数对象创建,因此Function指向MyClass.__proto__(注意,而不是Function.prototype)。它什么也没找到,继续搜索原型链。它最终找不到名为MyClass.prototype的属性,因此返回method

因此:

undefined

<强> 2

MyClass.prototype.method == MyClass.method // false

Object是用于创建对象的内置构造函数 - 对象。因此它是一种功能。

Object instanceof Function    // true

Function instanceof Object // true 是一个运算符,如果RHS对象的 prototype属性驻留在LHS的原型链上,则返回true。 Function的原型链是:

instanceof

因此,在函数原型链的顶部,为了避免循环,Function.__proto__ -> Function.prototype Function.prototype -> function f() {} // An ordinary function, named for clarity f.__proto__ -> {} // An ordinary object. Let's call it 'o'. 构造函数的原型被用作Object(我称之为f.__proto__这里为了清楚起见)。因此:

f
Function instanceof Object    // true

为此,Object instanceof Object // true 必须位于Object.prototype的原型链上。

Object

所以Object.__proto__ -> Function.prototype Function.prototype.__proto__ -> {} // This is 'o' from above. ,因此:

Function.prototype.__proto__ === Object.prototype
Object instanceof Object      // true

与1a相同的解释也是如此。