什么是 "The" 原型?
What is "The" prototype?
我正在努力研究原型,很想知道 原型到底是什么。许多混淆源于不理解用于描述的元语言
原型。
这是我所知道的:
当我们创建一个带有属性的命名构造函数时,该构造函数主体内的属性由该构造函数创建的对象实例继承。在这里,我从名为 Person 的构造函数创建了一个名为 person001 的实例。
function Person(firstName,lastName) {
this.firstName = firstName;
this.lastName = lastName
}
undefined
var person001 = new Person("John","Doe");
当我查看控制台中的对象实例并跟踪原型链时,我在两个不同的地方找到了它。它是 dunder proto 对象的构造函数对象...
Person {firstName: "John", lastName: "Doe"}
firstName: "John"
lastName: "Doe"
__proto__:
constructor: ƒ Person(firstName,lastName)
__proto__: Object
和一个 属性 原型对象在同一个构造函数对象中。
Person {firstName: "John", lastName: "Doe"}
firstName: "John"
lastName: "Doe"
__proto__:
constructor: ƒ Person(firstName,lastName)
arguments: null
caller: null
length: 2
name: "Person"
prototype:
constructor: ƒ Person(firstName,lastName)
__proto__: Object
__proto__: ƒ ()
[[FunctionLocation]]: script.js:76
[[Scopes]]: Scopes[1]
__proto__: Object
当我使用命名构造函数的 .prototype 属性 添加 属性 时,我将 属性 添加到原型对象,而不是构造函数。添加的 属性 将位于原型 属性 对象中的构造函数旁边。这里我使用构造函数Person.属性的原型属性添加了一个叫做age的属性。
Person.prototype.age = 0;
现在我又添加了一个 属性,原型到底是什么?
当我 运行 对象实例 person001 上的 Object.getPrototypeOf 方法时,它 returns 在我看来像原型对象。它有 3 个属性——构造函数、我添加的 属性 和隐式 dunder proto 对象。
Object.getPrototypeOf(person001);
{age: 0, constructor: ƒ}
age: 0
constructor: ƒ Person(firstName,lastName)
__proto__: Object
那么原型是什么?是原型对象{构造函数,附加属性}吗?还是只是原型对象的构造函数?
在此先感谢您的帮助。
说你已经为一个 Person 创建了一个构造函数,然后是它的两个实例:
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
现在您创建的每个人都有不同的名字,而且他们都可以说出来,因为他们共享相同的 属性 来自某些 parent object.
但玛丽不仅会说话。她可以唱歌。但是约翰不能。
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
mary.sing = () => console.log('♪♪♪ Lalalalalala ♪♪♪');
mary.sing();
john.sing(); // John is such a bad singer, that this throws an error !
如果后来您意识到您的员工不仅需要说话,还需要走路,那该多好啊。您需要引用他们的公共 parent 以告诉他们全部走在一条线上。这就是原型。玛丽和约翰都有一个共同的原型,并且在内心深处都有对该原型的引用(即 __proto__
,用于朋友和家人)。
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
Person.prototype.walk = () => console.log('I am walking alright');
john.walk();
mary.walk();
// That is the same as:
john.__proto__.walk()
mary.__proto__.walk()
现在约翰摔得很厉害,走路也很困难
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
Person.prototype.walk = () => console.log('I am walking alright');
// John's infamous accident
john.walk = () => console.log('My leg hurts so bad...');
john.walk();
mary.walk();
实例有自己的 属性,我们使用它。
没有,我们查看它的__proto__
,有就用。
希望对您有所帮助!
首先,原型只是一个对象。几乎 JS 中的每个对象(例如,当您使用 Object.create(null)
时除外)都有一些原型,并且原型可以链接起来。
示例:当您使用文字 []
创建数组时,您的数组实例连接到对象(顺便说一句,也是数组实例)定义数组的属性,如 map
等,它本身是连接到另一个定义对象属性的原型(对象实例),如 toString
。这些属性通常是函数。现在,当您访问对象的属性之一时,例如 [].hasOwnProperty
,引擎会查找原型链以找到它。它从您的 []
实例开始,找不到它,继续到原型(数组),也没有成功,因此移动到最终找到它的最后一个原型(对象实例)。
如您所见,原型链总是在某个地方结束,因此如果您尝试在链中的最后一个原型上检索原型,您将得到 null
.
现在回到构造函数。首先要注意的是,这些只是普通函数——实例的实际 "creator" 是关键字 new
。现在每个函数都有一个 prototype
属性 告诉你:使用这个函数创建的每个对象都将原型连接到函数 prototype
属性 中的任何对象。默认情况下,每个函数都包含此 属性 中的对象实例,这意味着您从该函数创建的每个对象都将原型连接到此实例,因此将具有 "inherit" 属性,例如 toString
.
你可以在这个例子中看到函数的 prototype
属性 和实例的原型之间的联系。
function A() {}
var a = new A();
a.__proto__ == A.prototype; // is true
最后,函数的 prototype
属性 中的 constructor
属性 告诉你,当使用带有 new
关键字。这一口归结为:
function A() {}
A == A.prototype.constructor; // is true
它是对自身的引用。在 ES6 之前创建您自己的继承链时,这个 属性 是可选的设置,但为了正确起见还是这样做了。
那么什么是原型?它只是一个对象,通过特殊的原型连接连接到其他对象实例,使其能够访问预定义的属性。这是一种在JS中进行继承的方式。
编辑:我的朋友@teemu 添加到我的回答中:每个内置对象都有其原型。
用非常简单的语言来说,每个函数都是 javascript 中的一种特殊对象,每个函数都有自己的 "prototype" 对象容器。
所以每个构造函数都会有自己的 "prototype" 对象,它会与使用 this 构造的 __proto__
中的所有对象共享。
让我们看例子:
// constructor function:
var Person = function(name, age){
this.name = name;
this.age = age
}
var tony = new Person('tony', 21);
var bruce = new Person('bruce', 22);
正如我们讨论的那样,
Person.prototype
应与 tony.__proto__
和 bruce.__proto__
相同
注意:您也可以用内置数组、对象或字符串替换 Person。
为了验证这一点,我们可以这样做:
Person.prototype == tony.__proto__; //true
Person.prototype == bruce.__proto__; //true
bruce.__proto__ == tony.__proto__; //true
接下来我们要做的是在 bruce.__proto__
上添加一个 属性:
bruce.__proto__.isSuperHero = true;
在 prototype
中添加属性也是一样的
但这会随处体现;
console.log(tony.__proto__.isSuperHero ) // true
console.log(Person.prototype.isSuperHero) //true
现在你可以把一个原型想象成一个普通的space,就像所有家庭成员的房子,如果任何家庭成员对那个房子做出改变,它将是每个人都改变了,每个家庭成员都可以进入房子,无论他多大年纪或他只是一个新生儿。每个家庭成员都一样,楼梯一样,房间一样,墙壁的颜色一样。
我希望这能帮助您理解原型链,我尝试用不同的方式来解释它,我认为这是更好的方式。
当你obj = new Person
时,游戏中有三名玩家:
- 新创建的对象
obj
- 构造函数
Person
- 原型,存储在
Person.prototype
下的特殊隐藏对象
它们之间的关系如下:
obj.__proto__ === Person.prototype
Person.prototype.constructor === Person
插图:
function Person(firstName,lastName) {
this.firstName = firstName;
this.lastName = lastName
}
var person1 = new Person("John","Doe");
var person2 = new Person("Ann","Smith");
Person.prototype.age = 42;
我正在努力研究原型,很想知道 原型到底是什么。许多混淆源于不理解用于描述的元语言 原型。
这是我所知道的:
当我们创建一个带有属性的命名构造函数时,该构造函数主体内的属性由该构造函数创建的对象实例继承。在这里,我从名为 Person 的构造函数创建了一个名为 person001 的实例。
function Person(firstName,lastName) {
this.firstName = firstName;
this.lastName = lastName
}
undefined
var person001 = new Person("John","Doe");
当我查看控制台中的对象实例并跟踪原型链时,我在两个不同的地方找到了它。它是 dunder proto 对象的构造函数对象...
Person {firstName: "John", lastName: "Doe"}
firstName: "John"
lastName: "Doe"
__proto__:
constructor: ƒ Person(firstName,lastName)
__proto__: Object
和一个 属性 原型对象在同一个构造函数对象中。
Person {firstName: "John", lastName: "Doe"}
firstName: "John"
lastName: "Doe"
__proto__:
constructor: ƒ Person(firstName,lastName)
arguments: null
caller: null
length: 2
name: "Person"
prototype:
constructor: ƒ Person(firstName,lastName)
__proto__: Object
__proto__: ƒ ()
[[FunctionLocation]]: script.js:76
[[Scopes]]: Scopes[1]
__proto__: Object
当我使用命名构造函数的 .prototype 属性 添加 属性 时,我将 属性 添加到原型对象,而不是构造函数。添加的 属性 将位于原型 属性 对象中的构造函数旁边。这里我使用构造函数Person.属性的原型属性添加了一个叫做age的属性。
Person.prototype.age = 0;
现在我又添加了一个 属性,原型到底是什么?
当我 运行 对象实例 person001 上的 Object.getPrototypeOf 方法时,它 returns 在我看来像原型对象。它有 3 个属性——构造函数、我添加的 属性 和隐式 dunder proto 对象。
Object.getPrototypeOf(person001);
{age: 0, constructor: ƒ}
age: 0
constructor: ƒ Person(firstName,lastName)
__proto__: Object
那么原型是什么?是原型对象{构造函数,附加属性}吗?还是只是原型对象的构造函数?
在此先感谢您的帮助。
说你已经为一个 Person 创建了一个构造函数,然后是它的两个实例:
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
现在您创建的每个人都有不同的名字,而且他们都可以说出来,因为他们共享相同的 属性 来自某些 parent object.
但玛丽不仅会说话。她可以唱歌。但是约翰不能。
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
mary.sing = () => console.log('♪♪♪ Lalalalalala ♪♪♪');
mary.sing();
john.sing(); // John is such a bad singer, that this throws an error !
如果后来您意识到您的员工不仅需要说话,还需要走路,那该多好啊。您需要引用他们的公共 parent 以告诉他们全部走在一条线上。这就是原型。玛丽和约翰都有一个共同的原型,并且在内心深处都有对该原型的引用(即 __proto__
,用于朋友和家人)。
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
Person.prototype.walk = () => console.log('I am walking alright');
john.walk();
mary.walk();
// That is the same as:
john.__proto__.walk()
mary.__proto__.walk()
现在约翰摔得很厉害,走路也很困难
const Person = function(name) {
this.name = name;
this.speak = () => console.log('My name is ' + this.name)
};
const john = new Person('John');
const mary = new Person('Mary');
john.speak();
mary.speak();
Person.prototype.walk = () => console.log('I am walking alright');
// John's infamous accident
john.walk = () => console.log('My leg hurts so bad...');
john.walk();
mary.walk();
实例有自己的 属性,我们使用它。
没有,我们查看它的__proto__
,有就用。
希望对您有所帮助!
首先,原型只是一个对象。几乎 JS 中的每个对象(例如,当您使用 Object.create(null)
时除外)都有一些原型,并且原型可以链接起来。
示例:当您使用文字 []
创建数组时,您的数组实例连接到对象(顺便说一句,也是数组实例)定义数组的属性,如 map
等,它本身是连接到另一个定义对象属性的原型(对象实例),如 toString
。这些属性通常是函数。现在,当您访问对象的属性之一时,例如 [].hasOwnProperty
,引擎会查找原型链以找到它。它从您的 []
实例开始,找不到它,继续到原型(数组),也没有成功,因此移动到最终找到它的最后一个原型(对象实例)。
如您所见,原型链总是在某个地方结束,因此如果您尝试在链中的最后一个原型上检索原型,您将得到 null
.
现在回到构造函数。首先要注意的是,这些只是普通函数——实例的实际 "creator" 是关键字 new
。现在每个函数都有一个 prototype
属性 告诉你:使用这个函数创建的每个对象都将原型连接到函数 prototype
属性 中的任何对象。默认情况下,每个函数都包含此 属性 中的对象实例,这意味着您从该函数创建的每个对象都将原型连接到此实例,因此将具有 "inherit" 属性,例如 toString
.
你可以在这个例子中看到函数的 prototype
属性 和实例的原型之间的联系。
function A() {}
var a = new A();
a.__proto__ == A.prototype; // is true
最后,函数的 prototype
属性 中的 constructor
属性 告诉你,当使用带有 new
关键字。这一口归结为:
function A() {}
A == A.prototype.constructor; // is true
它是对自身的引用。在 ES6 之前创建您自己的继承链时,这个 属性 是可选的设置,但为了正确起见还是这样做了。
那么什么是原型?它只是一个对象,通过特殊的原型连接连接到其他对象实例,使其能够访问预定义的属性。这是一种在JS中进行继承的方式。
编辑:我的朋友@teemu 添加到我的回答中:每个内置对象都有其原型。
用非常简单的语言来说,每个函数都是 javascript 中的一种特殊对象,每个函数都有自己的 "prototype" 对象容器。
所以每个构造函数都会有自己的 "prototype" 对象,它会与使用 this 构造的 __proto__
中的所有对象共享。
让我们看例子:
// constructor function:
var Person = function(name, age){
this.name = name;
this.age = age
}
var tony = new Person('tony', 21);
var bruce = new Person('bruce', 22);
正如我们讨论的那样,
Person.prototype
应与 tony.__proto__
和 bruce.__proto__
注意:您也可以用内置数组、对象或字符串替换 Person。
为了验证这一点,我们可以这样做:
Person.prototype == tony.__proto__; //true
Person.prototype == bruce.__proto__; //true
bruce.__proto__ == tony.__proto__; //true
接下来我们要做的是在 bruce.__proto__
上添加一个 属性:
bruce.__proto__.isSuperHero = true;
在 prototype
中添加属性也是一样的但这会随处体现;
console.log(tony.__proto__.isSuperHero ) // true
console.log(Person.prototype.isSuperHero) //true
现在你可以把一个原型想象成一个普通的space,就像所有家庭成员的房子,如果任何家庭成员对那个房子做出改变,它将是每个人都改变了,每个家庭成员都可以进入房子,无论他多大年纪或他只是一个新生儿。每个家庭成员都一样,楼梯一样,房间一样,墙壁的颜色一样。
我希望这能帮助您理解原型链,我尝试用不同的方式来解释它,我认为这是更好的方式。
当你obj = new Person
时,游戏中有三名玩家:
- 新创建的对象
obj
- 构造函数
Person
- 原型,存储在
Person.prototype
下的特殊隐藏对象
它们之间的关系如下:
obj.__proto__ === Person.prototype
Person.prototype.constructor === Person
插图:
function Person(firstName,lastName) {
this.firstName = firstName;
this.lastName = lastName
}
var person1 = new Person("John","Doe");
var person2 = new Person("Ann","Smith");
Person.prototype.age = 42;