How does JavaScript .prototype work?
我对动态编程语言不太了解,但我已经编写了相当多的javascript代码。我从来没有真正了解过这个基于原型的编程,有人知道它是如何工作的吗?
1 2 3 4 | var obj = new Object(); obj.prototype.test = function() { alert('Hello?'); }; var obj2 = new obj(); obj2.test(); |
我记得有一段时间我和别人讨论了很多(我不太确定自己在做什么),但据我所知,没有课堂的概念。它只是一个对象,这些对象的实例是原始对象的克隆,对吗?
但javascript中这个".prototype"属性的确切目的是什么?它如何与实例化对象相关?
更新:正确方式1 2 3 4 5 | var obj = new Object(); // not a functional object obj.prototype.test = function() { alert('Hello?'); }; // this is wrong! function MyObject() {} // a first class functional object MyObject.prototype.test = function() { alert('OK'); } // OK |
而且这些幻灯片真的帮助了很多。
在一个实现Java、C、C++等经典继承的语言中,您首先创建一个类——一个对象的蓝图——然后您可以从该类中创建新对象,或者可以扩展类,定义一个新的类来增加原始类。
在JavaScript中,您首先创建一个对象(没有类的概念),然后您可以扩充自己的对象或从中创建新的对象。这并不难,但有点异国情调,很难为习惯于古典方式的人进行新陈代谢。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //Define a functional object to hold persons in JavaScript var Person = function(name) { this.name = name; }; //Add dynamically to the already defined object a new getter Person.prototype.getName = function() { return this.name; }; //Create a new object of type Person var john = new Person("John"); //Try the getter alert(john.getName()); //If now I modify person, also John gets the updates Person.prototype.sayMyName = function() { alert('Hello, my name is ' + this.getName()); }; //Call the new method on john john.sayMyName(); |
直到现在,我一直在扩展基本对象,现在我创建了另一个对象,然后从个人继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //Create a new object of type Customer by defining its constructor. It's not //related to Person for now. var Customer = function(name) { this.name = name; }; //Now I link the objects and to do so, we link the prototype of Customer to //a new instance of Person. The prototype is the base that will be used to //construct all new instances and also, will modify dynamically all already //constructed objects because in JavaScript objects retain a pointer to the //prototype Customer.prototype = new Person(); //Now I can call the methods of Person on the Customer, let's try, first //I need to create a Customer. var myCustomer = new Customer('Dream Inc.'); myCustomer.sayMyName(); //If I add new methods to Person, they will be added to Customer, but if I //add new methods to Customer they won't be added to Person. Example: Customer.prototype.setAmountDue = function(amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function() { return this.amountDue; }; //Let's try: myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue()); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | var Person = function (name) { this.name = name; }; Person.prototype.getName = function () { return this.name; }; var john = new Person("John"); alert(john.getName()); Person.prototype.sayMyName = function () { alert('Hello, my name is ' + this.getName()); }; john.sayMyName(); var Customer = function (name) { this.name = name; }; Customer.prototype = new Person(); var myCustomer = new Customer('Dream Inc.'); myCustomer.sayMyName(); Customer.prototype.setAmountDue = function (amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function () { return this.amountDue; }; myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue()); |
如前所述,我不能对一个人调用setAmountDue()、getAmountDue()。
1 2 | //The following statement generates an error. john.setAmountDue(1000); |
每个javascript对象都有一个名为[[原型]]的内部属性。如果您通过
一些JavaScript实现允许直接访问[[原型]]属性,例如通过名为
这允许在javascript中模拟类,尽管正如我们所见,javascript的继承系统是原型的,而不是基于类的:
只需将构造函数函数看作类,并将原型的属性(即构造函数函数的
我扮演着一个javascript老师的角色,当我讲课时,原型概念一直是一个有争议的话题。我花了一段时间才想出一个很好的方法来澄清这个概念,现在在本文中,我将尝试解释javascript.prototype是如何工作的。好的。
这是一个非常简单的基于原型的对象模型,在解释过程中会被视为一个样本,目前还没有评论:好的。
1 2 3 4 5 6 7 | function Person(name){ this.name = name; } Person.prototype.getName = function(){ console.log(this.name); } var person = new Person("George"); |
在讨论原型概念之前,我们必须考虑一些关键点。好的。1-javascript函数的实际工作方式:
为了进行第一步,我们必须弄清楚,javascript函数实际上是如何工作的,作为一个类函数,在其中使用
假设我们想要创建一个
所以在这个步骤中,
第一个问题是,不使用
为了回答这个问题,假设我们有一个空对象,有两个函数,比如:好的。
1 2 3 4 5 6 | var person = {}; function Person(name){ this.name = name; } function getName(){ console.log(this.name); } |
现在不使用
1 2 | Person("George"); getName();//would print the"George" in the console |
在这种情况下,这将是当前上下文对象,通常是浏览器中的全局
-最简单的方法是修改空的
1 2 | person.Person = Person; person.getName = getName; |
我们可以这样称呼他们:好的。
1 2 | person.Person("George"); person.getName();// -->"George" |
现在,
1 | Object {Person: function, getName: function, name:"George"} |
-另一种将属性附加到对象的方法是使用该对象的
1 2 | person.__proto__.Person = Person; person.__proto__.getName = getName; |
但是我们实际做的就是修改
1 2 3 4 | person.__proto__ = { Person: Person, getName: getName }; |
现在其他的物体都是和平的,但这似乎仍然不是一个好的实践。所以我们还有一个解决方案,但是要使用这个解决方案,我们应该回到创建了
1 2 3 4 5 | var propertiesObject = { Person: Person, getName: getName }; var person = Object.create(propertiesObject); |
它所做的是创建一个新的javascript
1 | console.log(person.__proto__===propertiesObject); //true |
但这里的难点在于,您可以访问
如您所见,使用这两种方法中的任何一种,
The apply() method calls a function with a given this value and
arguments provided as an array (or an array-like object).Ok.
和好的。
The call() method calls a function with a given this value and
arguments provided individually.Ok.
这种方式是我最喜欢的,我们可以很容易地调用我们的函数,比如:好的。
1 | Person.call(person,"George"); |
或好的。
1 2 3 4 5 | //apply is more useful when params count is not fixed Person.apply(person, ["George"]); getName.call(person); getName.apply(person); |
这三种方法是确定.prototype功能的重要初始步骤。好的。2-
这是了解
1 2 | function Person(name){ this.name = name; } my_person_prototype = { getName: function(){ console.log(this.name); } }; |
在这一部分中,我将尝试在不使用
1 | var newObject = {}; |
b.javascript的下一步是将所有原型对象附加到新创建的对象上。
我们这里的
1 2 3 | for(var key in my_person_prototype){ newObject[key] = my_person_prototype[key]; } |
这不是JavaScript实际附加在原型中定义的属性的方式。实际的方法与原型链的概念有关。好的。A.&B.通过执行以下操作,您可以获得完全相同的结果,而不是这两个步骤:
1 2 3 4 5 | 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" |
现在我们可以在我们的
1 | newObject.getName(); |
c.然后它将该对象赋给构造函数,
我们可以用我们的样本来实现这一点,比如:好的。
1 | Person.call(newObject,"George"); |
或好的。
1 | Person.apply(newObject, ["George"]); |
然后,构造函数可以做它想要做的任何事情,因为该构造函数内部的这个对象是刚刚创建的。好的。
现在,模拟其他步骤之前的最终结果是:对象名称:"乔治"好的。总结:
基本上,当你对一个函数使用新的关键字时,你是在调用它,而这个函数是一个构造函数,所以当你说:好的。
1 | new FunctionName() |
javascript在内部生成一个对象,一个空散列,然后将该对象提供给构造函数,然后构造函数可以做它想要做的任何事情,因为该构造函数内部是刚刚创建的对象,如果您没有在函数中使用RETURN语句,或者如果您已经放置了一个OCx1〔0〕在你的功能体的末端。好的。
所以当JavaScript查找对象的属性时,它首先要做的就是在该对象上查找它。还有一个秘密属性
1 | console.log(Object.prototype.__proto__===null);//true |
这就是继承在JavaScript中的工作原理。好的。
好的。
换言之,当您在函数上有一个原型属性,并且对此调用了一个新的属性时,在javascript完成对新创建的属性对象的查看之后,它将查看函数的
下面是一个简短的例子。
1 2 | var obj = new Object(); obj.test = function() { alert('Hello?'); }; |
在上面的例子中,您有静态函数调用测试。此函数只能由obj.test访问,您可以将obj想象为一个类。
如以下代码所示
1 2 3 4 5 6 7 | function obj() { } obj.prototype.test = function() { alert('Hello?'); }; var obj2 = new obj(); obj2.test(); |
obj已经成为一个类,现在可以实例化。obj可以存在多个实例,它们都具有
以上是我的理解。我正在把它变成一个社区维基,这样人们可以在我错的时候纠正我。
原型的七个Koans
当慈三经过深思熟虑,下到火狐山时,他的头脑清醒而平静。
然而,他的手却不安,他自己抓着一把刷子,匆匆记下了下面的笔记。
0)有两种不同的东西可以称为"原型":
原型属性,如
obj.prototype 中所示。原型内部属性,在ES5中表示为
[[Prototype]] 。可通过ES5
Object.getPrototypeOf() 检索。火狐使它可以作为扩展通过
__proto__ 属性进行访问。ES6现在提到了__proto__ 的一些可选要求。
1)这些概念用于回答问题:
When I do
obj.property , where does JS look for.property ?
直观地说,经典继承应该影响属性查找。
2)
__proto__ 用于点. 属性查找,如obj.property 中所示。.prototype 不直接用于查找,只是间接用于确定__proto__ 在使用new 创建对象时的查找。
查找顺序为:
- 添加
obj.p = ... 或Object.defineProperty(obj, ...) 的obj 属性 obj.__proto__ 的性质obj.__proto__.__proto__ 的性质等- 如果有的
__proto__ 是null ,返回undefined 。
这就是所谓的原型链。
您可以避免使用
3)设置
new :1
2var F = function() {}
var f = new F()那么,
new 设置了:1f.__proto__ === F.prototype这就是使用
.prototype 的地方。Object.create :1f = Object.create(proto)集合:
1f.__proto__ === proto
4)代码:
1 2 | var F = function() {} var f = new F() |
对应下图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | (Function) ( F ) (f) | ^ | | ^ | | | | | | | | | | | +-------------------------+ | | |constructor | | | | | | | +--------------+ | | | | | | | | | | | | | | |[[Prototype]] |[[Prototype]] |prototype |constructor |[[Prototype]] | | | | | | | | | | | | | | | | +----------+ | | | | | | | | | | | | +-----------------------+ | | | | | | v | v v | v (Function.prototype) (F.prototype) | | | | |[[Prototype]] |[[Prototype]] | | | | | +-------------------------------+ | | v v (Object.prototype) | | ^ | | | | | +---------------------------+ | | | | +--------------+ | | | | | | | |[[Prototype]] |constructor |prototype | | | | | | | | -------------+ | | | v v | (null) (Object) |
此图显示了许多语言预定义的对象节点:
5)
1 2 3 4 5 | f.constructor === F !f.hasOwnProperty('constructor') Object.getPrototypeOf(f) === F.prototype F.prototype.hasOwnProperty('constructor') F.prototype.constructor === f.constructor |
当我们编写
f 没有.constructor 。f.__proto__ === F.prototype 有.constructor === F 所以拿着吧
结果
6)经典继承语法可以通过操作原型链来实现。
ES6添加了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class C { constructor(i) { this.i = i } inc() { return this.i + 1 } } class D extends C { constructor(i) { super(i) } inc2() { return this.i + 2 } } |
1 2 3 4 | // Inheritance syntax works as expected. (new C(1)).inc() === 2 (new D(1)).inc() === 2 (new D(1)).inc2() === 3 |
1 2 3 4 5 6 7 | //"Classes" are just function objects. C.constructor === Function C.__proto__ === Function.prototype D.constructor === Function // D is a function"indirectly" through the chain. D.__proto__ === C D.__proto__.__proto__ === Function.prototype |
1 2 3 4 5 6 7 | //"extends" sets up the prototype chain so that base class // lookups will work as expected var d = new D(1) d.__proto__ === D.prototype D.prototype.__proto__ === C.prototype // This is what `d.inc` actually does. d.__proto__.__proto__.inc === C.prototype.inc |
1 2 3 4 5 6 7 8 9 | // Class variables // No ES6 syntax sugar apparently: // http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives C.c = 1 C.c === 1 // Because `D.__proto__ === C`. D.c === 1 // Nothing makes this work. d.c === undefined |
没有所有预定义对象的简化图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | __proto__ (C)<---------------(D) (d) | | | | | | | | | |prototype |prototype |__proto__ | | | | | | | | | | | +---------+ | | | | | | | | | | v v |__proto__ (D.prototype) | | | | | | | | |__proto__ | | | | | | | | +--------------+ | | | | | | | v v | (C.prototype)--->(inc) | v Function.prototype |
在阅读了这个线程之后,我对javascript原型链感到困惑,然后我找到了这些图表
http://iwiki.readthedocs.org/en/latest/javascript/js-core.html继承
通过原型链显示javascript继承是一个清晰的图表
和
http://www.javascriptbank.com/javascript/article/javascript_古典_继承/
这个示例包含一个代码示例和几个漂亮的图表。
prototype chain ultimately falls back to Object.prototype.
prototype chain can be technically extended as long as you want, each time by setting the prototype of the subclass equal to an object of the parent class.
希望这对您理解JavaScript原型链也有帮助。
每个对象都有一个内部属性,[[原型]],将其链接到另一个对象:
1 | object [[Prototype]] -> anotherObject |
在传统的javascript中,链接对象是函数的
1 | object [[Prototype]] -> aFunction.prototype |
有些环境将[[原型]]暴露为
1 | anObject.__proto__ === anotherObject |
创建对象时创建[[原型]]链接。
1 2 3 4 5 6 7 8 9 10 11 | // (1) Object.create: var object = Object.create(anotherObject) // object.__proto__ = anotherObject // (2) ES6 object initializer: var object = { __proto__: anotherObject }; // object.__proto__ = anotherObject // (3) Traditional JavaScript: var object = new aFunction; // object.__proto__ = aFunction.prototype |
所以这些陈述是等价的:
1 2 3 | var object = Object.create(Object.prototype); var object = { __proto__: Object.prototype }; // ES6 only var object = new Object; |
记得:
- 每个对象都有一个链接,[[原型]],有时作为
__proto__ 公开。 - 每个函数都有一个
prototype 属性。 - 使用
new 创建的对象链接到其构造函数的prototype 属性。 - 如果函数从未用作构造函数,则其
prototype 属性将不使用。 - 如果不需要构造函数,请使用object.create而不是
new 。
这篇文章很长。但我相信它能帮你解决大部分问题关于JavaScript继承的"原型"性质。甚至更多。请阅读全文。好的。
javascript基本上有两种数据类型好的。
- 非对象
- 物体
非对象好的。
以下是非对象数据类型好的。
- 一串
- 数字(包括NaN和Infinity)
- 布尔值(真、假)
- 未定义
当使用typeof运算符时,这些数据类型返回如下好的。
"string literal"的类型(或包含string literal的变量)=="string"好的。
typeof 5(或任何数字文字或包含数字文字或NaN或Infynity的变量)=='数字'好的。
typeof true(或false,或包含true或false的变量)=='布尔值'好的。
未定义的类型(或未定义的变量或包含未定义的变量)=='未定义'好的。
字符串、数字和布尔数据类型既可以表示为对象,也可以表示为非对象。当它们表示为对象时,它们的typeof始终为=='对象'。一旦我们了解了对象数据类型,我们将回到这一点。好的。
物体好的。
对象数据类型可以进一步分为两种类型好的。
函数类型对象是使用typeof运算符返回字符串"function"的对象。所有用户定义的函数和所有可以使用new操作符创建新对象的javascript内置对象都属于此类。例如好的。
- 对象
- 弦
- 数
- 布尔
- 数组
- 类型化数组
- 正则表达式
- 功能
- 可以使用new运算符创建新对象的所有其他内置对象
- 函数userDefinedFunction()/*用户定义的代码*/
所以,typeof(object)==类型of(string)==类型of(number)==类型of(boolean)===类型of(array)===类型of(regexp)===类型of(function)===类型of(userdefinedfunction)==='函数'好的。
所有的函数类型对象实际上都是内置的javascript对象函数的实例(包括函数对象,即它是递归定义的)。就好像这些对象是按以下方式定义的好的。
1 2 3 4 5 6 7 8 | var Object= new Function ([native code for object Object]) var String= new Function ([native code for object String]) var Number= new Function ([native code for object Number]) var Boolean= new Function ([native code for object Boolean]) var Array= new Function ([native code for object Array]) var RegExp= new Function ([native code for object RegExp]) var Function= new Function ([native code for object Function]) var UserDefinedFunction= new Function ("user defined code") |
如前所述,函数类型对象可以使用new操作符进一步创建新对象。例如,可以使用好的。
1 2 3 4 5 6 7 | var a=new Object() or var a=Object() or var a={} //Create object of type Object var a=new String() //Create object of type String var a=new Number() //Create object of type Number var a=new Boolean() //Create object of type Boolean var a=new Array() or var a=Array() or var a=[] //Create object of type Array var a=new RegExp() or var a=RegExp() //Create object of type RegExp var a=new UserDefinedFunction() |
这样创建的对象都是非函数类型的对象,并返回它们的typeof=='object'。在所有这些情况下,对象"a"不能进一步创建对象使用运算符new。所以以下是错误的好的。
1 | var b=new a() //error. a is not typeof==='function' |
内置对象数学类型为typeof=='object'。因此,new运算符无法创建类型为math的新对象。好的。
1 | var b=new Math() //error. Math is not typeof==='function' |
还要注意,对象、数组和regexp函数可以创建一个新对象,而不必使用operator new。但是下面的没有。好的。
1 2 3 | var a=String() // Create a new Non Object string. returns a typeof==='string' var a=Number() // Create a new Non Object Number. returns a typeof==='number' var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean' |
用户定义的函数是特殊情况。好的。
1 | var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined. |
由于函数类型对象可以创建新对象,因此它们也被称为构造函数。好的。
定义后,每个构造函数/函数(无论是内置的还是用户定义的)都会自动具有一个名为"prototype"的属性,其默认值设置为对象。此对象本身有一个名为"constructor"的属性,默认情况下,它引用了构造函数/函数。好的。
例如,当我们定义一个函数时好的。
1 2 3 | function UserDefinedFunction() { } |
跟踪自动发生好的。
1 | UserDefinedFunction.prototype={constructor:UserDefinedFunction} |
此"原型"属性仅存在于函数类型对象中(并且从不在非函数类型对象中)。好的。
这是因为当创建一个新对象(使用new运算符)时,它继承了构造函数函数当前原型对象的所有属性和方法,即在新创建的对象中创建了一个内部引用,该对象引用了构造函数函数当前原型对象引用的对象。好的。
在对象中创建的用于引用继承属性的"内部引用"称为对象的原型(它引用了构造函数的"原型"属性引用的对象,但与之不同)。对于任何对象(函数或非函数),都可以使用object.getprototypeof()方法来检索。使用这种方法,我们可以跟踪对象的原型链。好的。
此外,创建的每个对象(函数类型或非函数类型)都有一个"构造函数"属性,该属性继承自构造函数函数的原型属性引用的对象。默认情况下,此"构造函数"属性引用创建它的构造函数函数(如果构造函数函数的默认"原型"未更改)。好的。
对于所有函数类型对象,构造函数函数始终是函数函数()好的。
对于非函数类型的对象(例如javascript内置数学对象),构造函数函数是创建它的函数。对于数学对象,它是函数对象()。好的。
在没有任何支持代码的情况下,上面解释的所有概念都有点让人望而生畏。请逐行阅读下面的代码以理解这个概念。试着执行它以获得更好的理解。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | function UserDefinedFunction() { } /* creating the above function automatically does the following as mentioned earlier UserDefinedFunction.prototype={constructor:UserDefinedFunction} */ var newObj_1=new UserDefinedFunction() alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays true alert(newObj_1.constructor) //Displays function UserDefinedFunction //Create a new property in UserDefinedFunction.prototype object UserDefinedFunction.prototype.TestProperty="test" alert(newObj_1.TestProperty) //Displays"test" alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays"test" //Create a new Object var objA = { property1 :"Property1", constructor:Array } //assign a new object to UserDefinedFunction.prototype UserDefinedFunction.prototype=objA alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays false. The object referenced by UserDefinedFunction.prototype has changed //The internal reference does not change alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction alert(newObj_1.TestProperty) //This shall still Display"test" alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display"test" //Create another object of type UserDefinedFunction var newObj_2= new UserDefinedFunction(); alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true. alert(newObj_2.constructor) //Displays function Array() alert(newObj_2.property1) //Displays"Property1" alert(Object.getPrototypeOf(newObj_2).property1) //Displays"Property1" //Create a new property in objA objA.property2="property2" alert(objA.property2) //Displays"Property2" alert(UserDefinedFunction.prototype.property2) //Displays"Property2" alert(newObj_2.property2) // Displays Property2 alert(Object.getPrototypeOf(newObj_2).property2) //Displays "Property2" |
每个对象的原型链最终都可以追溯到object.prototype(它本身没有任何原型对象)。以下代码可用于跟踪对象的原型链好的。
1 2 3 4 5 6 7 | var o=Starting object; do { alert(o +" " + Object.getOwnPropertyNames(o)) }while(o=Object.getPrototypeOf(o)) |
各种对象的原型链如下所示。好的。
- 每一个函数对象(包括内置函数对象)。 object.prototype function.prototype > >。
- 简单对象(创造了新的城市(或对象){ }包括内置的数学对象object.prototype)> >。
- 对象的创新与新的或object.create >一个或多个原型系统object.prototype > >。
用于创建对象的原型是"没有任何使用下面的:
好。
1 2 | var o=Object.create(null) alert(Object.getPrototypeOf(o)) //Displays null |
一位可能会认为"原型性质的constructor两个空应创建的对象和一个空的原型。然而,在这些用例中创造了新的原型对象的两个object.prototype冰上和冰上的两个constructor功能对象。这是demonstrated市下面的代码
好。
1 2 3 4 5 6 | function UserDefinedFunction(){} UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.) var o=new UserDefinedFunction() alert(Object.getPrototypeOf(o)==Object.prototype) //Displays true alert(o.constructor) //Displays Function Object |
下面的文章总结本
好。
- 有两类类型对象的功能和非功能型
-
功能型只读对象可以创建一个新的对象,使用新的运营商。这样的目标是创造了非功能型对象。《非功能型对象不能继续创造新的对象进行操作。
好。
-
全功能型城市的默认对象有一个"原型"的性质。这个原型性质的证明人"这是一个对象"constructor"性质,证明人的城市功能类型的默认对象本身。
好。
-
所有对象(非功能型和功能型)有一个"constructor"性质,违约的证明人的城市功能类型的对象/ constructor,创造了它。
好。
-
这是我们创造了每一个对象引用的对象internally证明人的城市 "原型"性质的constructor,创造了它。这冰的已知对象作为对象的原型创造了(这是从不同的功能类型对象的"原型"的性质,它的证明人)。这种方式创造了可以直接访问对象的方法和属性定义的对象引用的constructor的"原型"("性能对象的创建时间)。
好。
-
的对象的原型(鸭hence继承其财产的名称可以使用"retrieved object.getprototypeof()方法。事实上这个方法 可以用于navigating的全部对象的原型链。
好。
-
在每个对象的原型链ultimately痕迹后object.prototype(这两个对象的使用创造了《冰object.create(null),在这种情况下有没有对象的原型)。
好。
-
{T(New Array())=对象是城市设计的语言,而不是一个错误AA Douglas Crockford芒城
好。
-
Setting"原型性质的constructor两个空(或undefined号、威胁、褶皱、字符串)将不创建对象有一个空的原型。在这些用例中创造了新的原型对象的两个object.prototype冰上和冰上的两个constructor功能对象。
好。
希望这helps。
好。 好的。
javascript没有通常意义上的继承,但它有原型链。
原型链如果在对象中找不到对象的成员,则在原型链中查找该成员。链由其他对象组成。可以使用
向原型中添加一个函数/变量的好处是它必须只在内存中存在一次,而不是在每个实例中。
它对于继承也很有用,因为原型链可以由许多其他对象组成。
对于许多开发人员来说,
好的。
如果我们在
好的。
每个
好的。
如果您查看上面的
https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/object/prototype好的。
这有点像
我的Mozilla带来的
好的。
1 | Object.getPrototypeOf(Tree.prototype); // Object {} |
让我们给我们的
好的。
我们修改了
好的。
这意味着当你创建一个
好的。
我们也可以将
好的。
让我们把一个
好的。
在这里,
好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Child | \ \ Tree.prototype - branch | | \ \ Object.prototype -toString -valueOf -etc., etc. |
现在您创建一个
好的。
在JS中,一切都不是一个对象,一切都可以像一个对象一样工作。好的。
好的。
在这个列表的第一行中,一个
这就是幕后发生的事情://
好的。
Javascript 支持通过delegation 继承,基于prototypes 。- 每个
Function 有一个prototype 属性,它指的是另一个对象。 - 从
object 本身或通过prototype 链,如果不存在
JS中的
好的。
https://jsfiddle.net/say0tzpl/1/好的。
如果您查看上面的小提琴,dog可以访问
好的。
如果你看下面的一个,我们试图访问每个
好的。
https://jsfiddle.net/rknffckck/好的。
如果您查看上面的小提琴,
好的。
注:
好的。
上面的图表看起来有点复杂,但给出了
有两个实例
好的。
https://jsfiddle.net/kbp7jr7n/好的。
如果您查找上面的代码,我们有
好的。
好的。
好的。
在结束之前,我们先用一小段代码来总结上面的所有内容。我们在这里使用
好的。
我希望这个添加是一些信息,我知道这可能是一个很大的把握…简单来说,它只是链接到对象的对象!!!!!好的。好啊。
what is the exact purpose of this".prototype" property?
标准类的接口变得可扩展。例如,您正在使用
把原型想象成一个额外的vtable指针。当原始类中缺少某些成员时,将在运行时查找原型。
它可能有助于将原型链分为两类。好的。
考虑建造师:好的。
1 | function Person() {} |
向上的链条如下:好的。
&
重要的是,这个原型链与
以该对象为例:好的。
1 | var p = new Person(); |
P与人没有直接的原型链关系。他们的关系不同。对象P有自己的原型链。使用
&
这个链中没有函数对象(尽管可能是这样)。好的。
因此,
以下是所涉及的两个原型链的可视化演示,以列表示:好的。
好的。
总结:好的。
The
prototype property gives no information of the subject's prototype chain, but of objects created by the subject.Ok.
不足为奇,
您可以在两个原型链之间来回跳跃:好的。
1 | Person.prototype.constructor === Person |
这种对称性可以通过向
都是虚构的,但他们有不同的角色:面向建筑的功能,而其他的面向,代表的prototype of any面向那将函数的构造。在prototype面向将成为《亲子法的对象在其prototype链。
/好的。
从一个函数是也安的面向,它也有其自身的父母在其自身的prototype链,但回忆说,这些双链是什么不同的事情。
/好的。
这里是一些equalities那手术grasp的问题……所有这些
/好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function Person() {}; // This is prototype chain info for the constructor (the function object): console.log(Object.getPrototypeOf(Person) === Function.prototype); // Step further up in the same hierarchy: console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype); console.log(Object.getPrototypeOf(Object.prototype) === null); console.log(Person.__proto__ === Function.prototype); // Here we swap lanes, and look at the constructor of the constructor console.log(Person.constructor === Function); console.log(Person instanceof Function); // Person.prototype was created by Person (at the time of its creation) // Here we swap lanes back and forth: console.log(Person.prototype.constructor === Person); // Although it is not an instance of it: console.log(!(Person.prototype instanceof Person)); // Instances are objects created by the constructor: var p = new Person(); // Similarly to what was shown for the constructor, here we have // the same for the object created by the constructor: console.log(Object.getPrototypeOf(p) === Person.prototype); console.log(p.__proto__ === Person.prototype); // Here we swap lanes, and look at the constructor console.log(p.constructor === Person); console.log(p instanceof Person); |
/好的。 综合水平的prototype链
尽管从一prototype创建面向的是当你创建一个constructor函数,你可以忽视,面向assign,和另一个面向,这应该是用来作为prototype任何subsequent instances创造通过这constructor。。。。。。。
/好的。
设计实例:
/好的。
1 2 3 4 | function Thief() { } var p = new Person(); Thief.prototype = p; // this determines the prototype for any new Thief objects: var t = new Thief(); |
现在的prototype链T是自然的一步比,P:
/好的。
nbsp nbsp &;&;& nbsp;nbsp;
/好的。
其他prototype链是不自然:
/好的。
nbsp nbsp &;&;& nbsp;nbsp
/好的。
在presented简慢了图形然后可以被扩展到这个(原
/好的。
/好的。
蓝色的线代表prototype链,其他色系代表其他的关系:
/好的。
- 之间的关系的对象和其constructor
- 之间的一个constructor和prototype面向那将被用于constructing对象
好的。
面向对象的javascript的权威指南-一个非常简洁清晰的30分钟视频解释问题(原型继承主题从5:45开始,尽管我宁愿听整个视频)。本视频作者还制作了javascript对象可视化工具网站http://www.objectplayplay.com/.。
当引用
如果不存在
如果最终在k-th原型对象中找到了
您可以通过以下属性找到javascript对象关系图:
http://jsobts.org网站
当构造函数创建对象时,该对象隐式引用构造函数的"原型"属性以解析属性引用。程序表达式constructor.prototype可以引用构造函数的"prototype"属性,添加到对象原型的属性通过继承由共享原型的所有对象共享。
让我告诉你我对原型的理解。我不打算把这里的继承与其他语言进行比较。我希望人们不要再比较语言了,把语言理解为自己的语言。理解原型和原型继承非常简单,我将在下面向您展示。
原型就像一个模型,基于这个模型你可以创建一个产品。要理解的关键点是,当您使用另一个对象作为原型创建一个对象时,原型和产品之间的链接将一直持续。例如:
1 2 3 4 5 | var model = {x:2}; var product = Object.create(model); model.y = 5; product.y =>5 |
每个对象都包含一个名为[[原型]]的内部属性,
产品中的属性按以下方式处理:
- 当一个属性被访问来读取它的值时,它会在作用域链中查找。对变量的搜索从产品开始,一直到它的原型。如果在搜索中找到这样一个变量,搜索将在该变量处停止,并返回该值。如果在作用域链中找不到这样的变量,则返回UNDEFINED。
- 当一个属性被写入(更改)时,该属性总是被写入到产品对象上。如果产品还没有这样的属性,则隐式地创建和写入它。
这种使用原型属性的对象链接称为原型继承。很简单,同意吗?
这里有两个不同但相关的实体需要解释:
- 函数的
.prototype 属性。 - 所有对象的
[[Prototype]] 属性[2]。
这是两件不同的事情。
这是存在于所有[2]对象上的属性。
这里存储的是另一个对象,作为对象本身,它有一个自己的
1 2 3 | var obj = {} obj.a // [[Get]] consults prototype chain obj.b = 20 // [[Set]] consults prototype chain |
这是一个仅在函数上找到的属性。使用非常简单的函数:
1 | function Bar(){}; |
1 2 3 4 | // Both assign Bar.prototype to b1/b2[[Prototype]] var b = new Bar; // Object.getPrototypeOf grabs the objects [[Prototype]] console.log(Object.getPrototypeOf(b) === Bar.prototype) // true |
其中一个最重要的
1 2 | // Get properties that are defined on this object console.log(Object.getOwnPropertyDescriptors(Object.prototype)) |
现在,由于
这样,只要你做
1 2 3 4 5 | var b = new Bar; // Get all Bar.prototype properties console.log(b.__proto__ === Bar.prototype) // Get all Object.prototype properties console.log(b.__proto__.__proto__ === Object.prototype) |
当您确实对
这基本上改变了
[1:这不会混淆任何人;在许多实现中通过
考虑以下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; this.get = function(key) { return this.data[key]; }; this.set = function(key, value) { this.data[key] = value; }; this.delete = function(key) { delete this.data[key]; }; this.getLength = function() { var l = 0; for (p in this.data) l++; return l; } }; return { // Singleton public properties 'create' : function() { return new kvs(); }, 'count' : function() { return count; } }; })(); |
我可以通过执行以下操作创建此对象的新实例:
1 | kvs = keyValueStore.create(); |
此对象的每个实例都将具有以下公共属性:
data get set delete getLength
现在,假设我们创建这个
现在,想象一下,如果您只有一个
原型就是这样出现的。原型是继承但不被实例复制的属性的"蓝图"。这意味着对于一个对象的所有实例,它在内存中只存在一次,并且由所有这些实例共享。
现在,再考虑一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; }; kvs.prototype = { 'get' : function(key) { return this.data[key]; }, 'set' : function(key, value) { this.data[key] = value; }, 'delete' : function(key) { delete this.data[key]; }, 'getLength' : function() { var l = 0; for (p in this.data) l++; return l; } }; return { 'create' : function() { return new kvs(); }, 'count' : function() { return count; } }; })(); |
这与以前版本的
用更好的图片解释基于javascript原型的继承的另一个尝试
我总是喜欢用类比来理解这类事情。"在我看来,与类低音继承相比,"原型继承"是相当混乱的,尽管原型是非常简单的范例。事实上,对于原型,实际上没有继承,因此名称本身及其本身具有误导性,它更像是一种"委托"。
想象一下……
你在上高中,你在上课,今天要做一个测验,但是你没有一支笔来填写答案。呸!
你坐在你的朋友芬尼乌斯旁边,他可能有一支笔。你问他,他环顾办公桌,但没有说"我没有笔",他是一个很好的朋友,如果他有笔,他会和他的另一个朋友德普核对。德普确实有一支备用的钢笔,把它传给芬尼乌斯,芬尼乌斯把它传给你,让你完成测验。德普已将笔委托给芬尼乌斯,芬尼乌斯已将笔委托给你使用。
重要的是,德普不会把笔给你,因为你和他没有直接的关系。
这是一个原型如何工作的简化示例,其中搜索数据树以查找您要查找的内容。
总结:
- 函数是JavaScript中的对象,因此可以具有属性
- (构造函数)函数始终具有原型属性
- 当一个函数被用作带有
new 关键字的构造函数时,对象将得到原型。可以在新创建的对象的__proto__ 属性中找到对该原型的引用。 - 此
__proto__ 属性是指构造函数函数的prototype 属性。
例子:
1 2 3 4 5 6 7 8 9 | function Person (name) { this.name = name; } let me = new Person('willem'); console.log(Person.prototype) // Person has a prototype property console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function. |
Javascript在查找名为"原型继承"的对象的属性时有一种机制,其基本功能如下:
- 首先检查属性是否位于对象本身。如果是,则返回此属性。
- 如果属性不在对象本身上,它将"向上爬升原链"。它主要查看proto属性所引用的对象。在这里,它检查proto引用的对象上的属性是否可用。
- 如果属性不在proto对象上,它将沿着proto链一直向上爬到对象对象上。
- 如果在对象及其原型链上找不到该属性,它将返回未定义的。
例如:
1 2 3 4 5 6 7 8 9 | function Person(name) { this.name = name; } let mySelf = new Person('Willem'); console.log(mySelf.__proto__ === Person.prototype); console.log(mySelf.__proto__.__proto__ === Object.prototype); |
更新:
另一个显示原型、原型和构造函数关系的方案:
只是您已经有了一个使用
原型通过克隆现有对象来创建新对象。所以说真的,当我们考虑原型的时候,我们真的可以考虑克隆或者复制某个东西,而不是把它编造出来。
了解对象的原型(可通过
参考:https://developer.mozilla.org/en-us/docs/learn/javascript/objects/object_原型