javascript中原型的含义

Meaning of prototype in javascript

本文关键字:原型 javascript      更新时间:2023-11-01

我编写了从Person继承reader的短代码:

<script>
/* Class Person. */
function Person(name) {
    this.name = name;
}
Person.prototype.getName = function() {
    return this.name;
}
var reader = new Person('John Smith');
alert(reader.getName());
</script>

或者,我可以删除Person.prototype.getName = function() { return this.name; }的行,并在Person对象中创建它。例如

<script>
/* Class Person. */
function Person(name) {
    this.name = name;
    this.getName = function() { return this.name;}
}
var reader = new Person('John Smith');
alert(reader.getName());
</script>

在这两种情况下调用getName()时,我都得到了相同的结果。那么它们有什么不同呢?

当您在原型上放置一些东西时,对象的每个实例都共享相同的方法代码。它们都在使用相同的函数实例。

当您简单地在this上放置一个方法时,每个对象实例都有相同方法的副本

使用CCD_ 6要有效得多。请注意,这就是为什么通常将方法放在原型上的原因,因为您通常希望所有实例使用相同的方法,但属性放在实例本身上,因为通常不希望所有实例共享相同的属性。

对于您的注释,如果您将一个方法放在对象的构造函数上,那么您实际上创建了一个"静态"方法。对象的任何实例都不会有该方法,它们都必须在构造函数上访问该方法。所以在你的情况下,Person.someMethod()

当您将方法放入构造函数并从该构造函数创建对象时,每个对象都带有自己的getName函数。对于10个Person实例,每个实例都携带自己的getName,因此有10个单独的getName函数。

如果将getName放置在构造函数的原型中,那么相同的getName函数将在所有实例中共享/继承。因此对于Person的10个实例,每个实例都具有getName,但仅引用1个getName函数。

使用原型可以节省内存,因为该方法是跨实例共享的,所以只使用一个。

不同之处在于,当您将其放在原型上时,Person的所有实例共享getName的相同代码——您可以通过分配其他东西来更改Person所有实例上的getName

Person.prototype.getName = function() { return 'Mr Jones' };

此外,由于它们共享相同的代码,因此占用内存较少:getName函数只有一个副本,而不是每个实例一个副本。

另一个区别是,您可以稍后将Person设置为另一个类(比如Man)的原型,并且它将继承属性/方法。

更新:这是一篇很好的文章,解释了原型的其他属性:https://stackoverflow.com/a/1534286/295262

不同之处在于,您进一步扩展了Person类,子类将不会继承getName()方法

编辑:我上面的说法不正确。刚刚在jsfiddle上测试。不管我们是在原型上还是在函数实例本身上定义一个方法,它都可用于链中的子类。

证据如下:http://jsfiddle.net/u8qrd/

我知道将这些方法附加到原型中会带来性能/内存方面的好处。除此之外,在继承方面没有任何行为差异吗?

(希望我在这里提问不会违反SO规则)

在基于类的单词中,通过prototypethis声明函数之间的区别如下:

原型:

实例的函数如下所示:

somefunc = function(){super()/*call the function of the super-class*/};

这个:

实例的函数如下所示:

somefunc = function(){/* Do same stuff as in the prototype func declared */};

现在,更改原型上的函数对实例没有影响。

当您将任何带有this.functionname的函数添加到任何对象构造函数时,该构造函数创建的每个对象都会复制该函数,这也会占用内存。想象一下,若有几个对象是由同一个构造函数创建的,它需要多少内存。另一方面,当您使用cunstructorName.prototype.functionName创建它时,函数在内存中只加载一次,并且每个对象共享相同的原型函数构造函数。这种方法可以加快代码的加载和操作速度,还可以节省大量内存。

在查看javascript原型之前,首先要了解几个概念:

  1. 构造函数 :因此,基本上,在javascript中,任何用新关键字调用的函数都充当构造函数,并返回一个对象
  2. 构造函数中的this关键字:因此,当您在函数中使用this关键字,然后用new关键字调用该函数时。this关键字与返回的对象隐式绑定,如果将任何属性或方法分配给this关键字,它将被分配给返回的对象。如下面提供的代码示例所示:
function foo(){
this.name="foo"
this.greet=function(){
console.log("Good morning")
}
}
const obj=new foo()

所以现在,如果你想让某个属性对所有创建的对象保持不变,那么为每个对象实例分配该属性或方法单独的内存是没有意义的。相反,您可以在构造函数的原型属性上定义它,然后使用该构造函数创建的所有对象都可以访问它。例如,在上面给出的示例中,greet方法将对所有对象保持不变,因此我们可以重构如下所示:

function foo(){
this.name="foo"
}
foo.prototype.greet=function(){
console.log("Good morning")
}
const obj=new foo()

这不是继承

有些人可能会把它描绘成一种遗产。但不要混淆,这不是你的传统遗产。但取而代之的是授权。因此,在上面的代码示例中,当您尝试将greet方法w.r.t调用为obj时。口译员说他找不到它。所以他会看看这个物体指向哪个原型。它将指向foo函数的原型。因此,它将对其进行研究,并在其中找到定义的greet方法。