这是一个非常简单的基于原型的对象模型,在解释过程中将被视为示例,尚无评论:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
在讨论原型概念之前,我们必须考虑一些关键点。
1- JavaScript 函数的实际工作方式:
为了迈出第一步,我们必须弄清楚 JavaScript 函数实际上是如何工作的,作为一个类,比如this
在其中使用关键字的函数,或者只是作为一个带有参数的常规函数,它做什么和返回什么。
假设我们要创建一个Person
对象模型。但在这一步中,我将尝试在不使用prototype
andnew
关键字的情况下做同样的事情。
因此,在这一步functions
,objects
和this
关键字,都是我们。
第一个问题是不使用keyword 的情况下如何this
使用new
keyword。
为了回答这个问题,假设我们有一个空对象,以及两个函数,例如:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
现在不使用new
关键字我们如何使用这些功能。所以 JavaScript 有 3 种不同的方法来做到这一点:
一种。第一种方法只是将该函数作为常规函数调用:
Person("George");
getName();//would print the "George" in the console
在这种情况下,这将是当前上下文对象,这通常是全球 window
在浏览器或对象GLOBAL
中Node.js
。这意味着我们将在浏览器中使用 window.name 或在 Node.js 中使用 GLOBAL.name,并将“George”作为其值。
湾 我们可以将它们附加到一个对象上,作为它的属性
-最简单的方法是修改空person
对象,例如:
person.Person = Person;
person.getName = getName;
这样我们就可以这样称呼它们:
person.Person("George");
person.getName();// -->"George"
现在person
对象是这样的:
Object {Person: function, getName: function, name: "George"}
-将属性附加到对象的另一种方法是使用prototype
可以在任何名称为 的 JavaScript 对象中找到的对象的__proto__
,我试图在摘要部分对其进行一些解释。因此,我们可以通过执行以下操作来获得类似的结果:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
但是这样我们实际上所做的是修改Object.prototype
,因为每当我们使用字面量 ( { ... }
)创建一个 JavaScript 对象时,它都是基于 来创建的Object.prototype
,这意味着它会作为一个名为 的属性附加到新创建的对象上__proto__
,因此如果我们更改它,正如我们在之前的代码片段中所做的那样,所有 JavaScript 对象都会被更改,这不是一个好习惯。那么现在更好的做法是什么:
person.__proto__ = {
Person: Person,
getName: getName
};
现在其他物体都安然无恙,但这似乎仍然不是一个好习惯。所以我们还有一个解决方案,但是要使用这个解决方案,我们应该回到person
创建对象的那一行代码(var person = {};
),然后将其更改为:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
它所做的是创建一个新的 JavaScriptObject
并将 附加propertiesObject
到__proto__
属性。因此,为了确保您可以执行以下操作:
console.log(person.__proto__===propertiesObject); //true
但这里的棘手之处在于您可以访问__proto__
在person
对象的第一级中定义的所有属性(阅读摘要部分了解更多详细信息)。
如您所见,使用这两种方式中的任何一种this
都将准确指向person
对象。
C。JavaScript 有另一种为函数提供 的方法this
,即使用call或apply来调用函数。
apply() 方法使用给定的 this 值和作为数组(或类似数组的对象)提供的参数调用函数。
和
call() 方法使用给定的 this 值和单独提供的参数调用函数。
这是我最喜欢的方式,我们可以轻松调用我们的函数,例如:
Person.call(person, "George");
或者
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
这 3 种方法是找出 .prototype 功能的重要初始步骤。
2-new
关键字如何工作?
这是了解.prototype
功能的第二步。这是我用来模拟过程的内容:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
在这一部分中,当您使用关键字时,我将尝试执行 JavaScript 所采取的所有步骤,而不使用new
关键字 and 。所以当我们这样做的时候,函数充当了一个构造函数,这些是 JavaScript 所做的,一一:prototype
new
new Person("George")
Person
一种。首先,它创建一个空对象,基本上是一个空哈希,如:
var newObject = {};
湾 JavaScript 采取的下一步是将所有原型对象附加到新创建的对象
我们my_person_prototype
这里有类似于原型的对象。
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
这不是 JavaScript 实际附加原型中定义的属性的方式。实际方式与原型链概念有关。
一种。& B。您可以通过执行以下操作获得完全相同的结果,而不是这两个步骤:
var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"
现在我们可以调用我们的getName
函数my_person_prototype
:
newObject.getName();
C。然后它将该对象提供给构造函数,
我们可以使用我们的示例来做到这一点,例如:
Person.call(newObject, "George");
或者
Person.apply(newObject, ["George"]);
然后构造函数可以做任何它想做的事情,因为构造函数内部的this是刚刚创建的对象。
现在模拟其他步骤之前的最终结果:对象{名称:“乔治”}
概括:
基本上,当您在函数上使用new关键字时,您是在调用它,并且该函数充当构造函数,因此当您说:
new FunctionName()
JavaScript 在内部创建一个对象,一个空的散列,然后将该对象提供给构造函数,然后构造函数可以做任何它想做的事情,因为该构造函数的内部是刚刚创建的对象,然后它当然会给你那个对象如果您没有在函数中使用 return 语句,或者您return undefined;
在函数体的末尾放置了 a 。
因此,当 JavaScript 在对象上查找属性时,它所做的第一件事就是在该对象上查找它。然后有一个[[prototype]]
我们通常拥有的秘密属性,__proto__
该属性是 JavaScript 下一步要查看的内容。当它查看 时__proto__
,只要它又是另一个 JavaScript 对象,它就有自己的__proto__
属性,它会一直向上,直到到达下一个__proto__
为 null的点。重点是 JavaScript 中唯一一个其__proto__
属性为 null 的Object.prototype
对象是object:
console.log(Object.prototype.__proto__===null);//true
这就是继承在 JavaScript 中的工作方式。
换句话说,当你在一个函数上有一个原型属性并且你调用一个 new 时,在 JavaScript 完成查看新创建的属性对象后,它会查看函数的,.prototype
并且这个对象也可能有它的自己的内部原型。等等。