我阅读了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?
请解释以下内容:
Object instanceof Function // true
Function instanceof Object // true
Object instanceof Object // true
Function instanceof Function // true
这非常令人困惑。请用简单的词语解释。
答案 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)。
答案 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代码之外),这意味着Function
和prototype
属性 - 在这个例子中 - 指向同一个对象。
因此,在__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行测试foo
与foo
上寻找属性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相同的解释也是如此。