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

标签 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);

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

Human.isPrototypeOf(albert); // I expect it to return TRUE

但它返回 FALSE,这是为什么?

并且,对于下面的测试

Human.hasOwnProperty("age"); // /i expect it to return TRUE

但它返回 FALSE,这是为什么?

谢谢,

编辑 我的问题与另一个问题略有不同,因为它也是在谈论原型(prototype)链。

最佳答案

Human albert 中的函数的原型(prototype)链。 Human.prototype 引用的对象是:

Human.prototype.isPrototypeOf(albert); // true

Human.hasOwnProperty("age"); // /i expect it to return TRUE

Human函数没有 age属性(property)。 new 用它创建的实例做:

new Human().hasOwnProperty("age"); // true

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

  1. 您不想使用 new Human创建Male.prototype .

  2. 确实想调用Human来自 Male :

所以:

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;

您不使用 new Human 的原因为 Male 创建原型(prototype)很简单: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

当然,也可以使用 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


您说过您正在尝试查看链条的工作原理。这是创建 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]] above 是规范用于对象“内部插槽”的名称,该对象包含对其原型(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)。

在您的评论中:

I just can't understand why after inheritance statement we can do Male.prototype.isPrototypeOf(albert) return true but not in Human.isPrototypeOf(albert) (it return false) since Male.prototype is an instance of Human

因为 Human ,函数,在 albert 中无处可寻的原型(prototype)链。让我们看看albert的原型(prototype)链:

  • 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 ,该函数不在该链中。

关于javascript - .isPrototypeOf() 和 .hasOwnProperty() 方法混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39433397/

相关文章:

javascript - jQuery 工具提示 + ajax 内容

javascript - SOQL 查询中的 LIKE 或 CONTAINS

javascript - 使用 javascript 创建 Jquery 链接

javascript - 在 HTML 页面中获取私有(private)文件或显示私有(private)图像

javascript - Ractive/Paths.js 演示中的预期长度错误

javascript - 类型错误 : Cannot read property '0' of undefined. React Redux 应用程序

javascript - 单击按钮时隐藏边框样式

javascript - pypugjs 中的组合条件

javascript - 如何使 highcharts 饼图数据标签始终位于每个切片的中心?

javascript - 根据 AJAX 请求的类型显示 LoadingGif