.isPrototypeOf() 和 .hasOwnProperty() 方法混淆
.isPrototypeOf() and .hasOwnProperty() method confusion
假设我有这个代码:
// 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
但它 return 错误,这是为什么?
并且,对于下面的测试
Human.hasOwnProperty("age"); // /i expect it to return TRUE
但它 return 错误,这是为什么?
谢谢,
编辑
我的问题与另一个问题略有不同,因为它也是在谈论原型链。
Human
函数 不在 albert
的原型链中。 Human.prototype
引用的对象是:
Human.prototype.isPrototypeOf(albert); // true
Human.hasOwnProperty("age"); // /i expect it to return TRUE
Human
函数没有 age
属性。 new
使用它创建的实例执行:
new Human().hasOwnProperty("age"); // true
旁注:您设置继承链的方式很常见,在很多示例中都有展示,但有两个地方不正确:
您不想使用 new Human
创建 Male.prototype
。
你想从Male
打电话给Human
:
所以:
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
创建原型的原因很简单: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]]
是规范用于对象 "internal slot" 的名称,该对象包含对其原型对象的引用。相比之下,prototype
,属性 函数(例如,Human.prototype
),只是一个普通的 属性 函数,指向 new
将要执行的对象如果您将该函数与 new
.
一起使用,则用作它创建的新对象的 [[Prototype]]
关于该图的一些注释:
- 所有函数都有一个
[[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
's prototype chain. Lets'中不存在看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
函数不在该链中。
假设我有这个代码:
// 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
但它 return 错误,这是为什么?
并且,对于下面的测试
Human.hasOwnProperty("age"); // /i expect it to return TRUE
但它 return 错误,这是为什么?
谢谢,
编辑 我的问题与另一个问题略有不同,因为它也是在谈论原型链。
Human
函数 不在 albert
的原型链中。 Human.prototype
引用的对象是:
Human.prototype.isPrototypeOf(albert); // true
Human.hasOwnProperty("age"); // /i expect it to return TRUE
Human
函数没有 age
属性。 new
使用它创建的实例执行:
new Human().hasOwnProperty("age"); // true
旁注:您设置继承链的方式很常见,在很多示例中都有展示,但有两个地方不正确:
您不想使用
new Human
创建Male.prototype
。你想从
Male
打电话给Human
:
所以:
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
创建原型的原因很简单: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]]
是规范用于对象 "internal slot" 的名称,该对象包含对其原型对象的引用。相比之下,prototype
,属性 函数(例如,Human.prototype
),只是一个普通的 属性 函数,指向 new
将要执行的对象如果您将该函数与 new
.
[[Prototype]]
关于该图的一些注释:
- 所有函数都有一个
[[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)
returntrue
but not inHuman.isPrototypeOf(albert)
(it returnfalse
) sinceMale.prototype
is an instance ofHuman
因为Human
这个函数在albert
's prototype chain. Lets'中不存在看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
函数不在该链中。