这张图再次表明,每个对象都有一个原型。构造函数
function Foo也有自己的__proto__,也就是function .prototype,
而它又通过__proto__属性再次引用
Object.prototype。因此,重复,Foo。原型只是一个显式
Foo的属性,引用b和c对象的原型。
var b = new Foo(20);
var c = new Foo(30);
__proto__和prototype之间有什么区别?
这一数据来自dmitrysoshnikov.com网站。
注:上述2010年的文章现在有第二版(2017年)。
让我用一个简单的例子来解释:
function User(email, name){
this.email = email;
this.name = name;
this.online = false;
// method directly added to the constructor
this.greet = ()=>{
console.log(`Hi ${this.name}`);
}
}
// Adding prototype method login to the constructor function.
User.prototype.login = function(){
this.online = true;
console.log(this.email, 'has logged in');
};
// Adding prototype method logout to the constructor function.
User.prototype.logout = function(){
this.online = false;
console.log(this.email, 'has logged out');
};
var userOne = new User('ryu@ninjas.com', 'Ryu');
var userTwo = new User('yoshi@mariokorp.com', 'Yoshi');
console.log(userOne);
userTwo.login();
userTwo.greet();
输出:
结论:
在构造函数中添加的属性和方法是
直接添加到对象中。
添加的属性和方法
.prototype。被添加到对象的__proto__属性中。我们甚至可以看到userOne。__proto__或userTwo.__proto__
为了解释,让我们创建一个函数
function a (name) {
this.name = name;
}
当JavaScript执行这段代码时,它将prototype属性添加到。prototype属性是一个具有两个属性的对象:
构造函数
__proto__
所以当我们这样做的时候
a.原型它返回
constructor: a // function definition
__proto__: Object
现在你可以看到构造函数就是函数a本身
而__proto__指向JavaScript的根对象。
让我们看看当我们使用带有new关键字的函数时会发生什么。
var b = new a ('JavaScript');
当JavaScript执行这段代码时,它会做4件事:
它创建了一个新对象,一个空对象// {}
它在b上创建__proto__,并使其指向a.prototype,因此b.__proto__ === a.prototype
它使用新创建的对象(在步骤#1中创建)作为上下文(this)执行a.p otype.constructor(这是函数a的定义),因此作为'JavaScript'传递的name属性(它被添加到this)被添加到新创建的对象。
它返回新创建的对象(在步骤#1中创建),因此var b被分配给新创建的对象。
现在如果我们添加a.prototype。car = "BMW"然后
b.car,输出“BMW”出现。
这是因为当JavaScript执行这段代码时,它在b上搜索car属性,它没有发现,然后JavaScript使用b.__proto__(在步骤#2中指向“a.prototype”)并找到car属性,因此返回“BMW”。
我为自己画了一个小图,代表以下代码片段:
var Cat = function() {}
var tom = new Cat()
我有经典的OO背景,所以用这种方式表示层次结构很有帮助。为了帮助您阅读此图表,请将图像中的矩形视为JavaScript对象。是的,函数也是对象。;)
JavaScript中的对象有属性,__proto__只是其中之一。
此属性背后的思想是指向(继承)层次结构中的祖先对象。
JavaScript的根对象是object。Prototype和所有其他对象都是这个对象的后代。根对象的__proto__属性为null,表示继承链的结束。
你会注意到原型是函数的属性。Cat是一个函数,但function和Object也是(本机)函数。Tom不是一个函数,因此它没有这个属性。
此属性背后的思想是指向一个将在构造中使用的对象,即当您在该函数上调用new操作符时。
注意,原型对象(黄色矩形)有另一个属性称为
构造函数,它指向各自的函数对象。为
简短的原因,这是没有描述。
实际上,当我们用new Cat()创建tom对象时,所创建的对象的__proto__属性将被设置为构造函数的原型对象。
最后,让我们稍微研究一下这个图表。以下陈述是正确的:
汤姆。__proto__属性指向与Cat.prototype相同的对象。
猫。__proto__指向函数。原型对象,就像函数一样。__proto__和Object。__proto__做。
Cat.prototype。__proto__和tom.__proto__。__proto__指向相同的对象,即object .prototype。
干杯!
只有一个对象用于原型链接。该对象显然有一个名称和值:__proto__是它的名称,prototype是它的值。这是所有。
为了让它更容易理解,看看这篇文章顶部的图表(由dmitry soshnikov绘制的图表),你永远不会发现__proto__的值指向prototype以外的其他东西。
要点是:__proto__是引用原型对象的名称,prototype是实际的原型对象。
这就像是在说:
let x = {name: 'john'};
X是对象名称(指针),{name: 'john'}是实际对象(数据值)。
注意:这只是一个非常简单的提示,说明它们在较高的水平上是如何相互关联的。
更新:下面是一个简单具体的javascript示例,以便更好地说明:
let x = new String("testing") // Or any other javascript object you want to create
Object.getPrototypeOf(x) === x.__proto__; // true
这意味着当Object.getPrototypeOf(x)为我们获取x的实际值(这是它的原型)时,正是x的__proto__所指向的。因此__proto__确实指向x的原型。因此__proto__引用x (x的指针),而prototype是x的值(它的原型)。
我希望现在大家都明白了。
对于任何想要了解原型继承的人来说,这都是一个非常重要的问题。根据我的理解,默认情况下,当从函数中使用new创建对象时,prototype会被赋值,因为function定义了prototype对象:
function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]
当我们创建一个普通的对象,没有new,即显式地从一个函数,它没有原型,但它有一个空的原型,可以分配一个原型。
var foo={
check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); // TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
我们可以使用Object。创建以显式链接对象。
// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`
解释性的例子:
function Dog(){}
Dog.prototype.bark = "woof"
let myPuppie = new Dog()
现在,myPupppie有__proto__属性指向Dog.prototype。
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
但是mypuppy没有原型属性。
> myPuppie.prototype
>> undefined
因此,mypuppie的__proto__是对用于实例化此对象的构造函数的.prototype属性的引用(当前mypuppie对象与此__proto__对象具有“委托”关系),而mypuppie的.prototype属性则根本不存在(因为我们没有设置它)。
MPJ的解释很好:
在JavaScript中创建对象