.isPrototypeOf()和.hasOwnProperty()方法混淆

xco*_*ode 3 javascript

假设我有这个代码:

// Male will inherit ALL of the Human properties
function Human(x, y) {
  // Following properties will be inherited
  this.name = x;
  this.age = y;
  this.test = "Test 1";
}
// Following properties will ALSO be inherited
Human.prototype.citizen = "USA";
Human.prototype.employer = "Google";
Human.prototype.test = "Test 2";

function Male(x, y) {
  // Following properties will be the own properties of Male instances
  this.name = x;
  this.age = y;
  this.gender = "Male";
}

// Inheritance - Connecting Male object with Human object
Male.prototype = new Human(); // no arguments are passed
Male.prototype.constructor = Male; // correcting constructor property

var albert = new Male("Albert", 25);
Run Code Online (Sandbox Code Playgroud)

然后,我想对代码进行一些测试

Human.isPrototypeOf(albert); // I expect it to return TRUE
Run Code Online (Sandbox Code Playgroud)

但它返回FALSE,为什么呢?

并且,对于以下测试

Human.hasOwnProperty("age"); // /i expect it to return TRUE
Run Code Online (Sandbox Code Playgroud)

但它返回FALSE,为什么呢?

谢谢,

编辑 我的问题与其他问题略有不同,因为它也谈论原型链.

T.J*_*der 7

Human功能是不是albert的原型链.引用的对象Human.prototype是:

Human.prototype.isPrototypeOf(albert); // true
Run Code Online (Sandbox Code Playgroud)

Human.hasOwnProperty( "时代"); //我希望它返回TRUE

Human函数没有age属性.用它创建的实例new:

new Human().hasOwnProperty("age"); // true
Run Code Online (Sandbox Code Playgroud)

旁注:您设置继承链的方式很常见,并在很多示例中显示,但在两个方面不正确:

  1. 你不想new Human用来创建Male.prototype.

  2. 想打电话HumanMale:

所以:

function Male(x, y) {
    // Give Human its chance to initialize the object (#2)
    Human.call(this, x, y);
    // ...
}

// Don't use new Human to create the prototype (#1)
Male.prototype = Object.create(Human.prototype);
Male.prototype.constructor = Male;
Run Code Online (Sandbox Code Playgroud)

你不用new Human来创建原型的原因Male很简单:Human期望参数,但你没有任何给它.

这是更新的ES5及该代码的早期版本:

function Human(name, age) { // Argument names should be meaningful
  this.name = name;
  this.age = age;
  this.test = "Test 1";
}

Human.prototype.citizen = "USA";
Human.prototype.employer = "Google";
Human.prototype.test = "Test 2";

function Male(name, age) {
  Human.call(this, name, age);
  this.gender = "Male";
}

Male.prototype = Object.create(Human.prototype);
Male.prototype.constructor = Male;

var albert = new Male("Albert", 25);
console.log(Human.prototype.isPrototypeOf(albert)); // true
console.log(new Human().hasOwnProperty("age"));     // true
Run Code Online (Sandbox Code Playgroud)

或者当然,使用ES2015 +(如果您的目标尚不支持,则转换):

// THIS SNIPPET REQUIRES A BROWSER WITH ES2015+ SUPPORT

class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.test = "Test 1";
  }
}

Human.prototype.citizen = "USA";
Human.prototype.employer = "Google";
Human.prototype.test = "Test 2";

class Male extends Human {
  constructor(name, age) {
    super(name, age);
    this.gender = "Male";
  }
}

let albert = new Male("Albert", 25);
console.log(Human.prototype.isPrototypeOf(albert)); // true
console.log(new Human().hasOwnProperty("age"));     // true
Run Code Online (Sandbox Code Playgroud)


你已经说过你正试图看看连锁店是如何运作的.这是我们在创建后在内存中的图表albert(为简单起见,删除了一些细节):

         +??????????????????????????????????????????????????????????????????????+
         |                                                                      |
         \ +????????????????+                                                   |
Human?????>|    function    |                                                   |
           +????????????????+                            +????????????????????+ |
           | prototype      |???????????????????????????>|       object       | |    
           | name: "Human"  |                          / +????????????????????+ |    
           +????????????????+                          | | constructor        |?+
                                                       | | citizen: "USA"     |
         +???????????????????????????????????????????+ | | employer: "Google" |
         |                                           | | | test: "Test 2"     |
         \ +????????????????+                        | | +????????????????????+
Male??????>|    function    |                        | |
           +????????????????+    +?????????????????+ | |
           | prototype      |???>|     object      | | |
           | name: "Male"   |  / +?????????????????+ | |
           +????????????????+  | | constructor     |?+ |
                               | | [[Prototype]]   |???+
           +????????????????+  | +?????????????????+
albert????>|     object     |  |
           +????????????????+  |
           | name: "Albert" |  |
           | age: 25        |  |
           | gender: "Male" |  |
           | [[Prototype]]  |??+
           +????????????????+ 

[[Prototype]]以上是规范用于包含对其原型对象的引用的对象的"内部槽"的名称.相反,prototype函数(例如Human.prototype)上的属性只是函数的一个普通属性,它指向new[[Prototype]]使用该函数时将创建的新对象的对象new.

该图表上的一些注释:

  • 所有函数都有一个[[Prototype]]指向对象Function.prototype指向的内部插槽(为简单起见,上面省略了).
  • Human,该函数,有一个name属性:"Human"
  • Male,该函数,有一个name属性:"Male"
  • 该对象albert指的是具有以下name属性:"Albert"
  • albert[[Prototype]]Male.prototype; Male.prototype[[Prototype]]Human.prototype(和Human.prototype[[Prototype]],未示出,是`Object.prototype中).

你在评论中说过:

我只是无法理解为什么在继承语句之后我们可以Male.prototype.isPrototypeOf(albert)返回true而不是Human.isPrototypeOf(albert)(它返回false)因为Male.prototype是一个实例Human

因为Human,这个功能,在albert原型链中是无处可去的.让我们看看albert原型链:

  • albert[[Prototype]]Male.prototype
  • Male.prototype[[Prototype]]Human.prototype
  • Human.prototype[[Prototype]]Object.prototype
  • Object.prototype[[Prototype]]null

如图:

+???????????????+    +????????????????+    +?????????????????+    +?????????????????????+ 
|    albert     |    | Male.prototype |    | Human.prototype |    |  Object.prototype   |
+???????????????+    +????????????????+    +?????????????????+    +?????????????????????+ 
| [[Prototype]] |???>| [[Prototype]]  |???>| [[Prototype]]   |???>| [[Prototype]]: null |
+???????????????+    +????????????????+    +?????????????????+    +?????????????????????+ 

因此Human,该功能在该链中无处可去.