大佬们能理解这句话吗?
发布于 6 年前 作者 linxiaoziruo 4474 次浏览 来自 问答

Function.__proto__指向一个匿名函数function(){} ,匿名函数的__proto__指向Object的prototype ,Object的__proto__指向Function 的 prototype.

19 回复

你得知道,一个东西本身、它的__proto__、它的prototype三者之间有什么关系,才能理解这句话的意思。

@libook 这个我是能理解的。__proto__指向的是本身的prototype,本身的prototype是自身的创建加上从原型链上继承过来的属性的集合。但是这句话却是把Function,匿名函数,Object的搞成了一个循环。

原型链知识,我搞了半天才弄明白了,现在又忘了 QAQ

原型链知识,我搞了半天才弄明白了,现在又忘了 QAQ

我感觉得先理解“鸡生蛋,蛋生鸡”的哲学问题才能学好前端 (ε=ε=ε=┏(゜ロ゜;)┛

Function 继承自 ObjectObject 继承自 Function

所有对象的原型链的顶端是 Object.prototype,所以:

Function instanceof Object === true

我们在代码中会使用 let o = new Object(),因此 Object 本身也是构造函数:

Object instanceof Function === true

justjavac,已经说的非常完整了, Object 继承自 Function。这里有一点小歧义,我觉得不是所谓语义上的继承,只是本身Object作为一个普通函数,就是一个函数实例,所以当然它是在Function的原型链上,这就是你说的这句话导致人迷糊的关键所在,理解这点就好啦

@justjavac 不严谨,Function 继承自 Object,是指类型层面, Function instance 也可以当成 Object instance ,后面「Object 继承自 Function」这句话就是语言游戏了,正确的说法应该是 Object constructor function is Function type。

参考:JavaScript 的语言设计有哪些缺陷?

不要混淆 instanceof 和 subclass 这两种不同的关系 ,在 JavaScript 这里它们叫 Function、Object,在Java里就是 Class、Object,在 C# 里就是 Type、Object。因为JavaScript中类型、类构造器和普通变量全都使用同一个命名空间,所以让人产生了混淆。

var a = new Array;
alert(a instanceof Array);      // true
alert(a instanceof Object);     // true, Array extends Object
// 下面问题来了
// 所有对象都是 Object类型 的实例,
// 所以函数也是 Object类型 的实例,
// 所以 Array构造函数 也是 Object类型 的实例
alert(Array instanceof Object);


alert(Function instanceof Object);   //true
// 这是 true, Function类型 继承自 Object
alert(Function.prototype instanceof Object); 

alert(Object instanceof Function);   //true
// 但这是 false,Object类型 并没有继承自 Function
alert(Object.prototype instanceof Function); 

C# 代码:

var a = new Demo();
Console.WriteLine(a is Demo); // True
Console.WriteLine(a is Object); // True
Console.WriteLine(a.GetType() is Object); // True
Console.WriteLine(a.GetType() is Type); // True

对应 Java 代码:

Class _Class = Class.forName("java.lang.Class");
Class _Object = Class.forName("java.lang.Object");

// 下面全是 true
System.out.println(_Class instanceof Object);
System.out.println(_Object instanceof Class);
System.out.println(_Class instanceof Class);
System.out.println(_Object instanceof Object);

// 这是 true, Object 类型可以赋成 Class instance
System.out.println(_Object.isAssignableFrom(_Class));
// 但这是 false, Class 类型不能接受任意 Object instance
System.out.println(_Class.isAssignableFrom(_Object));

@justjavac 我明白了,照你这种对「继承」这个词的用法,Array也是继承了Function,String也是继承了Function,Number 也是继承了 Function,那你以后都跟别人这样说,看到底是更严谨了还是更容易混淆了。

但是早在ES6就引入了class,如果你坚持这种说法,就会和 class extends 相矛盾。我觉得不只我一个人,大部分人对继承这个词的习惯用法都是这样的,当说「B继承A」的时候:

  1. 要么是 class B extends A 语义,A和B都是class(或说是构造函数)名称,对应的原型继承关系就是: A.prototype.isPrototypeOf(B.prototype)
  2. 要么是直接的原型继承语义,let B = Object.create(A),关系是 A.isPrototypeOf(B)

绝不会用「B继承自A」来表达「B继承了A.prototype上的属性」,这样说就如同「3继承自Number」 。我觉得根本问题就在于混淆了 instanceof 和继承,当你说「Function继承自Object、Object继承自Function」时,举的例子也是Function instanceof Object; Object instanceof Function。 但正如 instanceof 名称所示,B instanceof A的含义是「B 是 A 的实例」而非「B继承自A」,按原型继承的说法只能说「B继承自A.prototype」,对应的原型关系是A.prototype.isPrototypeOf(B)。所以代换A和B,只能说 Function构造函数继承自 Object.prototype,Object构造函数继承自 Function.prototype。你用同一个词同时指代Object构造函数和Object.prototype,当语言停止工作时,哲学问题就产生了。

@JexCheng

什么是“照我这种用法”,这种用法可不是我说的。你看看 MDN 的左边:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String

String

Array

@justjavac 你这不只是玩文字游戏了,还玩排版游戏了,你要是能在正文中找出「{X instance} inherit from {X}」这种形式的表达算我输。但我劝你别浪费时间去找了,为了反驳而反驳有意思么?你会跟别人说「3继承自Number、new Array继承自Array」吗?人家文档菜单中就放个链接而已,这你也能拿来当佐证,是实在找不到其它的证据了吗?

@JexCheng

你是给了杠而杠吗?

如果你不懂 prototype-based inheritance 是什么,先去查明白再回来讨论。

es 规范:

In a class-based object-oriented language, in general, state is carried by instances, methods are carried by classes, and inheritance is only of structure and behaviour. In ECMAScript, the state and methods are carried by objects, while structure, behaviour, and state are all inherited.

class-like abstraction pattern

Although ECMAScript objects are not inherently class-based, it is often convenient to define class-like abstractions based upon a common pattern of constructor functions, prototype objects, and methods. The ECMAScript built-in objects themselves follow such a class-like pattern. Beginning with ECMAScript 2015, the ECMAScript language includes syntactic class definitions that permit programmers to concisely define objects that conform to the same class-like abstraction pattern used by the built-in objects.

@JexCheng

如果你说的“继承”和我说的“继承”根本就不是同一个继承,那就没有继续讨论的必要了。“前提相同”是讨论的基础,否则即使得到了结论也是错误的。

以不平平,其平也不平;以不徵徵,其徵也不徵。—— 庄子

@justjavac

以不平平,其平也不平

哈哈,感觉这句精妙地总结了很多讨(si)论(bi)

@justjavac 所以是不是MDN正文里找不到你这种用法?既然你引用了ES规范,那你不妨在规范里再搜索一下 inherit from 这个短语,看看后面跟着的到底是C还是C.prototype。要去真正搞懂问题,不要光停留在寻章摘句。我前面早就指出过,按照原型继承的说法,只能说 ConstructorFunction 继承了 Function.prototype。我从来没见过哪本书像你这样把 instanceof 关系等价于继承关系。

你当然可以继续特立独行坚持这样用「继承」这个词,说白了就是公然指鹿为马呗?当然没有继续讨论的必要了。我只好奇一点,你真的会坚持跟别人说「3继承了Number、[]继承了Array」吗?

还有,不管是class based还是prototype based,继承关系都满足传递性,C继承B、B继承A,可推出C继承A。像你这样把 instanceof 等价于继承就会破坏传递性,按你的用法:[] 继承了Array、Array继承Function。但是[]却没有继承Function。真正理解问题,不需要看别人怎么用词造句也可以凭自己思考作出判断,没有传递性的继承关系要了又有何用?

楼上有一张图形成循环很好解释了楼主的问题。 此外,我再补充几点。

Function是类,Object也是,是所有实例的模板,是抽象。

FunctionObject是两个类似的东西,其typeof相同。

object是类的实例化。-----注意是小写的object这只是个泛指。

__proto__用于向上搜索的,是委托的原动力。凡是需要原型链查找的都会用到该属性。

类.prototype上面定义的方法都能被继承,能被搜索到,是委托的内容。

总结:

实例代码:

function Foo(a, b) {
  this.a = a;
  this.b = b;
  console.log('hello')
}
var o = new Foo(···);

解释:

当调用o.···时,会先查找o对象自身,即o.···有没有该属性,如果没有就去查o.prototype.···,如果也没有就去查o的原型即o.__proto__也就是Foo.prototype,如果还是没有就再往上找o.__proto__.__proto__,一直找到object.prototype---->null,到了null还没找到,该属性就是undefined。<font color="#ffd700">因此oFoo没什么关系,oFoo.prototype才有关联。

证明如下:

const fuc = function(){console.log('hello');};
const fuc = new Function("console.log('hello');");
//以上两句等价
//类的typeof
typeof Object //"function"
typeof fuc    //"function"
typeof Function  //"function"
typeof 类  //"function"

-------------------------------------------------
const object1 = {a:1,b:'bb'}; 
const object1 = Object.create({a:1,b:'bb'}); 
const object1 = new Object({a:1,b:'bb'});
//以上三句等价

const array = [1,2,3];
const array = new Array(1,2,3);
// 实例的typeof
typeof object1  //"object"
typeof array   //"object"
typeof number  //"object"
typeof 实例    //"object"

@ailuhaosi 只有你说的 我完全听懂了 [/捂脸]

@ailuhaosi 有几处可能是笔误?

当调用o.···时,会先查找o对象自身,即o.···有没有该属性,如果没有就去查o.prototype.···,如果也没有就去查o的原型即o.__proto__也就是Foo.prototype,如果还是没有就再往上找o.proto.proto,一直找到object.prototype---->null,到了null还没找到,该属性就是undefined。

「如果没有就去查o.prototype.···」,这一步没并有,应该删掉。 「一直找到object.prototype」,此处object应该写成Object。

后面的证明代码是不是复制丢掉了一大部分?里面的问题我就不一一指出了

大佬们一番讨论,概念清晰了。js这乱乱的设计,跟缝缝补补一样,越补越乱。

回到顶部