Joh*_*ren 1988 javascript dynamic-languages prototype-oriented
我不是那种动态编程语言,但是我写了很多JavaScript代码.我从来没有真正了解这个基于原型的编程,有没有人知道这是如何工作的?
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Run Code Online (Sandbox Code Playgroud)
我记得很久以前我和人们进行了很多讨论(我不确定我在做什么)但是据我所知,没有一个类的概念.它只是一个对象,这些对象的实例是原始的克隆,对吧?
但是JavaScript中这个".prototype"属性的确切目的是什么?它与实例化对象有什么关系?
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
Run Code Online (Sandbox Code Playgroud)
这些幻灯片也非常有帮助.
sti*_*vlo 1791
在实现Java,C#或C++等经典继承的语言中,您首先要创建一个类 - 对象的蓝图 - 然后您可以从该类创建新对象,或者您可以扩展该类,定义一个增强的新类原班.
在JavaScript中,您首先创建一个对象(没有类的概念),然后您可以扩充自己的对象或从中创建新对象.这并不困难,但对于习惯于经典方式的人来说,有点外来并难以代谢.
例:
//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();
Run Code Online (Sandbox Code Playgroud)
到目前为止,我一直在扩展基础对象,现在我创建了另一个对象,然后从Person继承.
//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());
Run Code Online (Sandbox Code Playgroud)
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());
Run Code Online (Sandbox Code Playgroud)
虽然如上所述我不能在Person上调用setAmountDue(),getAmountDue().
//The following statement generates an error.
john.setAmountDue(1000);
Run Code Online (Sandbox Code Playgroud)
Chr*_*oph 986
每个JavaScript对象都有一个名为[[Prototype]]的内部属性.如果您通过obj.propName
或查找属性obj['propName']
并且该对象没有这样的属性 - 可以通过检查obj.hasOwnProperty('propName')
- 运行时会在[[Prototype]]引用的对象中查找该属性.如果prototype-object也没有这样的属性,则依次检查其原型,从而遍历原始对象的原型链,直到找到匹配或达到其结束.
一些JavaScript实现允许直接访问[[Prototype]]属性,例如通过名为的非标准属性__proto__
.通常,只能在对象创建期间设置对象的原型:如果通过创建新对象new Func()
,则对象的[[Prototype]]属性将设置为引用的对象Func.prototype
.
这允许在JavaScript中模拟类,尽管JavaScript的继承系统 - 正如我们所见 - 原型,而不是基于类:
只需将构造函数作为类和原型的属性(即构造函数的prototype
属性引用的对象)视为共享成员,即每个实例的成员相同.在基于类的系统中,方法以相同的方式为每个实例实现,因此通常将方法添加到原型中,而对象的字段是特定于实例的,因此在构造期间添加到对象本身.
Meh*_*ami 179
我扮演JavaScript老师的角色,原型概念在我教授时一直是一个有争议的话题.我花了一段时间才想出一个澄清概念的好方法,现在在本文中我将试图解释JavaScript .prototype是如何工作的.
这是一个非常简单的基于原型的对象模型,在解释过程中将被视为一个样本,尚无评论:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
Run Code Online (Sandbox Code Playgroud)
在完成原型概念之前,我们必须考虑一些关键点.
要迈出第一步,我们必须弄清楚,JavaScript函数实际上是如何工作的,像类似函数的类使用this
关键字,或者作为常规函数及其参数,它做什么以及它返回什么.
假设我们想要创建一个Person
对象模型.但是在这一步中,我将尝试在不使用prototype
和new
关键字的情况下做同样的事情.
因此,在这一步functions
,objects
和this
关键字,都是我们.
第一个问题是关键字如何this
在不使用new
关键字的情况下有用.
所以回答一下,假设我们有一个空对象,有两个函数,比如:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
Run Code Online (Sandbox Code Playgroud)
现在不使用new
关键字我们如何使用这些功能.所以JavaScript有3种不同的方法:
Person("George");
getName();//would print the "George" in the console
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这将是当前上下文对象,这通常是全球 window
在浏览器或对象GLOBAL
中Node.js
.这意味着我们将在浏览器中使用window.name或在Node.js中使用GLOBAL.name,并使用"George"作为其值.
- 最简单的方法是修改空person
对象,如:
person.Person = Person;
person.getName = getName;
Run Code Online (Sandbox Code Playgroud)
通过这种方式我们可以称之为:
person.Person("George");
person.getName();// -->"George"
Run Code Online (Sandbox Code Playgroud)
现在person
对象就像:
Object {Person: function, getName: function, name: "George"}
Run Code Online (Sandbox Code Playgroud)
- 将属性附加到对象的另一种方法是使用prototype
可以在名称为的任何JavaScript对象中找到的该对象__proto__
,并且我试图在摘要部分稍微解释一下.所以我们可以通过这样做得到类似的结果:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
Run Code Online (Sandbox Code Playgroud)
但是这样我们实际上正在做的是修改Object.prototype
,因为无论何时我们使用literals({ ... }
)创建一个JavaScript对象,它都是基于创建的Object.prototype
,这意味着它作为一个名为的属性附加到新创建的对象__proto__
,所以如果我们改变它正如我们在之前的代码片段中所做的那样,所有JavaScript对象都会被更改,这不是一个好习惯.那么现在可能是更好的做法:
person.__proto__ = {
Person: Person,
getName: getName
};
Run Code Online (Sandbox Code Playgroud)
现在其他物品都很平静,但它似乎仍然不是一个好习惯.所以我们还有一个解决方案,但是要使用这个解决方案,我们应该回到person
创建对象的那一行代码(var person = {};
)然后改变它:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
Run Code Online (Sandbox Code Playgroud)
它的作用是创建一个新的JavaScript Object
并附propertiesObject
加到__proto__
属性.所以要确保你能做到:
console.log(person.__proto__===propertiesObject); //true
Run Code Online (Sandbox Code Playgroud)
但这里棘手的一点是您可以访问对象__proto__
第一级中定义的所有属性person
(有关更多详细信息,请阅读摘要部分).
正如你所看到的那样使用这两种方式中的任何一种this
都会指向person
对象.
this
,即使用call或apply来调用函数.apply()方法调用一个给定此值的函数,并将参数作为数组(或类数组对象)提供.
和
call()方法调用一个给定此值的函数和单独提供的参数.
这种方式是我最喜欢的,我们可以轻松调用我们的功能:
Person.call(person, "George");
Run Code Online (Sandbox Code Playgroud)
要么
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
Run Code Online (Sandbox Code Playgroud)
这三种方法是确定.prototype功能的重要初始步骤.
new
关键字如何运作?这是理解.prototype
功能的第二步.这是我用来模拟过程的:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
Run Code Online (Sandbox Code Playgroud)
在这部分中,我将尝试采用JavaScript所采取的所有步骤,而不使用new
关键字,并且prototype
当您使用new
关键字时.所以当我们这样做时new Person("George")
,Person
函数充当构造函数,这些是JavaScript所做的,一个接一个:
var newObject = {};
Run Code Online (Sandbox Code Playgroud)
我们在my_person_prototype
这里类似于原型对象.
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
Run Code Online (Sandbox Code Playgroud)
这不是JavaScript实际附加原型中定义的属性的方式.实际的方式与原型链概念有关.
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"
Run Code Online (Sandbox Code Playgroud)
现在我们可以调用我们的getName
函数my_person_prototype
:
newObject.getName();
Run Code Online (Sandbox Code Playgroud)
我们可以使用以下示例执行此操作:
Person.call(newObject, "George");
Run Code Online (Sandbox Code Playgroud)
要么
Person.apply(newObject, ["George"]);
Run Code Online (Sandbox Code Playgroud)
然后构造函数可以做任何想做的事情,因为这个构造函数内部是刚刚创建的对象.
现在是模拟其他步骤之前的最终结果:对象{name:"George"}
基本上,当你在一个函数上使用new关键字时,你正在调用它,并且该函数用作构造函数,所以当你说:
new FunctionName()
Run Code Online (Sandbox Code Playgroud)
JavaScript在内部创建一个对象,一个空哈希,然后它将该对象提供给构造函数,然后构造函数可以做任何想做的事情,因为这个构造函数内部是刚刚创建的对象,然后它给了你那个对象当然如果你没有在你的函数中使用return语句,或者你已经return undefined;
在函数体的末尾放了一个.
因此,当JavaScript在一个对象上查找一个属性时,它所做的第一件事就是它在该对象上查找它.然后有一个[[prototype]]
我们通常喜欢的秘密属性,__proto__
这个属性就是JavaScript接下来要看的东西.当它查看时__proto__
,就它再次是另一个JavaScript对象而言,它有自己的__proto__
属性,它会一直向上和向上,直到它到达下一个__proto__
为空的点.关键点是JavaScript中唯一一个__proto__
属性为null的Object.prototype
对象是object:
console.log(Object.prototype.__proto__===null);//true
Run Code Online (Sandbox Code Playgroud)
这就是继承在JavaScript中的工作方式.
换句话说,当你在一个函数上有一个prototype属性并且你在它上面调用一个新属性时,在JavaScript完成查找新创建的属性对象之后,它将查看该函数,.prototype
并且该对象也可能有它的自己的内部原型.等等.
Ram*_*esh 74
prototype
允许你上课.如果你不使用prototype
那么它就变成了静态的.
这是一个简短的例子.
var obj = new Object();
obj.test = function() { alert('Hello?'); };
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,你有静态函数调用测试.只能通过obj.test访问此函数,您可以将obj想象成一个类.
如下面的代码所示
function obj()
{
}
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Run Code Online (Sandbox Code Playgroud)
obj已成为一个现在可以实例化的类.可以存在多个obj实例,它们都具有该test
功能.
以上是我的理解.我正在制作社区维基,所以如果我错了,人们可以纠正我.
Cir*_*四事件 69
随着Ciro San在深度冥想后降落火狐之火,他的思绪清晰而平和.
然而,他的手不安,并且自己抓起一把刷子并记下下面的笔记.
0)两种不同的东西可以称为"原型":
原型属性,如 obj.prototype
原型内部属性,[[Prototype]]
在ES5中表示.
它可以通过ES5检索Object.getPrototypeOf()
.
Firefox可以通过__proto__
属性作为扩展访问它.ES6现在提到了一些可选要求__proto__
.
1)存在回答这个问题的概念:
当我这样做时
obj.property
,JS在哪里寻找.property
?
直观地说,经典继承应该影响属性查找.
2)
__proto__
用于点.
属性查找,如obj.property
..prototype
是不用于直接查找,只是间接地因为它决定__proto__
在对象创建与new
.查找顺序是:
obj
用obj.p = ...
或添加的属性Object.defineProperty(obj, ...)
obj.__proto__
obj.__proto__.__proto__
等等__proto__
就是null
,返回undefined
.这就是所谓的原型链.
您可以避免.
使用obj.hasOwnProperty('key')
和查找Object.getOwnPropertyNames(f)
3)设置有两种主要方式obj.__proto__
:
new
:
var F = function() {}
var f = new F()
Run Code Online (Sandbox Code Playgroud)
然后new
设置:
f.__proto__ === F.prototype
Run Code Online (Sandbox Code Playgroud)
这是.prototype
使用的地方.
Object.create
:
f = Object.create(proto)
Run Code Online (Sandbox Code Playgroud)
集:
f.__proto__ === proto
Run Code Online (Sandbox Code Playgroud)4)代码:
var F = function(i) { this.i = i }
var f = new F(1)
Run Code Online (Sandbox Code Playgroud)
对应下图:
(Function) ( F ) (f)----->(1)
| ^ | | ^ | i |
| | | | | | |
| | | | +-------------------------+ | |
| |constructor | | | | |
| | | +--------------+ | | |
| | | | | | |
| | | | | | |
|[[Prototype]] |[[Prototype]] |prototype |constructor |[[Prototype]]
| | | | | | |
| | | | | | |
| | | | +----------+ | |
| | | | | | |
| | | | | +-----------------------+ |
| | | | | | |
v | v v | v |
(Function.prototype) (F.prototype) |
| | |
| | |
|[[Prototype]] |[[Prototype]] [[Prototype]]|
| | |
| | |
| +-------------------------------+ |
| | |
v v v
(Object.prototype) (Number.prototype)
| | ^
| | |
| | +---------------------------+
| | |
| +--------------+ |
| | |
| | |
|[[Prototype]] |constructor |prototype
| | |
| | |
| | -------------+
| | |
v v |
(null) (Object)
Run Code Online (Sandbox Code Playgroud)
该图显示了许多语言的预定义对象节点:Number
,null
,Object
,Object.prototype
和Function
.我们的2行代码只创建了Function.prototype
,1
和Number.prototype
.
5) (1).__proto__
通常来自f
通过F
查找:
var f = new F(1)
Run Code Online (Sandbox Code Playgroud)
当我们编写时F.prototype
,JavaScript i
会将查找视为:
f
不具有 F
this
有new
,所以接受它结果f
直观正确,因为.constructor
用于构造F.prototype
,例如设置字段,就像在经典OOP语言中一样.
6)可以通过操纵原型链来实现经典继承语法.
ES6添加了.
和f.constructor
关键字,它们只是以前可能的原型操作疯狂的语法糖.
f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
Run Code Online (Sandbox Code Playgroud)
// "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
Run Code Online (Sandbox Code Playgroud)
// "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
Run Code Online (Sandbox Code Playgroud)
没有所有预定义对象的简化图:
// 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
Run Code Online (Sandbox Code Playgroud)
roc*_*ock 64
读完这个帖子后,我觉得与JavaScript Prototype Chain混淆了,然后我找到了这些图表
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
它是一个清晰的图表,显示原型链的JavaScript继承
和
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
这个包含一个代码示例和几个漂亮的图表.
原型链最终回落到Object.prototype.
原型链可以在技术上扩展,只要你想要,每次通过设置子类的原型等于父类的对象.
希望它对您理解JavaScript原型链也很有帮助.
sam*_*sam 37
每个对象都有一个内部属性[[Prototype]],将它链接到另一个对象:
object [[Prototype]] -> anotherObject
Run Code Online (Sandbox Code Playgroud)
在传统的javascript中,链接对象是prototype
函数的属性:
object [[Prototype]] -> aFunction.prototype
Run Code Online (Sandbox Code Playgroud)
某些环境将[[Prototype]]暴露为__proto__
:
anObject.__proto__ === anotherObject
Run Code Online (Sandbox Code Playgroud)
您在创建对象时创建[[Prototype]]链接.
// (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
Run Code Online (Sandbox Code Playgroud)
所以这些陈述是等价的:
var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;
Run Code Online (Sandbox Code Playgroud)
一new
言不显示的链接目标(Object.prototype
)本身; 相反,构造函数(Object
)暗示了目标.
记得:
__proto__
.prototype
属性.new
链接到prototype
其构造函数的属性.prototype
属性将不使用.new
.Geo*_*lly 26
Javascript没有通常意义上的继承,但它有原型链.
如果在对象中找不到对象的成员,则它在原型链中查找它.该链由其他对象组成.可以使用__proto__
变量访问给定实例的原型.每个对象都有一个,因为javascript中的类和实例之间没有区别.
向原型添加函数/变量的优点是它必须只在内存中一次,而不是每个实例.
它对继承也很有用,因为原型链可以包含许多其他对象.
Aru*_*ore 26
这篇文章很长.但我相信它会清除大多数关于JavaScript继承的"原型"性质的疑问.甚至更多.请阅读完整的文章.
JavaScript基本上有两种数据类型
非物件
以下是非对象数据类型
使用typeof运算符时,这些数据类型将返回
typeof "string literal"(或包含字符串文字的变量)=== 'string'
typeof 5(或任何数字文字或包含数字文字或NaN或Infynity的变量)=== 'number'
typeof true(或false或包含true或false的变量)=== 'boolean'
typeof undefined(或未定义的变量或包含undefined的变量)=== 'undefined'
的字符串,号码和布尔数据类型可以表示既作为对象和非对象.当它们被表示为对象他们的typeof总是==="对象".一旦我们理解了对象数据类型,我们将回到这一点.
对象
对象数据类型可以进一步分为两种类型
该功能类型的对象是返回字符串的那些"功能"与typeof运算符.所有用户定义的函数和所有可以通过使用new运算符创建新对象的对象内置的JavaScript都属于此类别.例如.
所以, typeof(Object) === typeof(String) === typeof(Number) === typeof(Boolean) === typeof(Array) === typeof(RegExp) === typeof(Function) == = typeof(UserDefinedFunction) === 'function'
所有Function类型对象实际上都是内置JavaScript对象Function的实例(包括Function对象,即它是递归定义的).就好像以下列方式定义了这些对象
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")
Run Code Online (Sandbox Code Playgroud)
如上所述,Function类型对象可以使用new运算符进一步创建新对象.例如,可以使用Object,String,Number,Boolean,Array,RegExp 或UserDefinedFunction类型的对象创建
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()
Run Code Online (Sandbox Code Playgroud)
这样创建的对象都是非函数类型对象,并返回其typeof === 'object'.在所有这些情况下,对象"a"不能使用operator new进一步创建对象.所以以下是错误的
var b=new a() //error. a is not typeof==='function'
Run Code Online (Sandbox Code Playgroud)
内置对象Math是typeof === 'object'.因此,新运算符无法创建Math类型的新对象.
var b=new Math() //error. Math is not typeof==='function'
Run Code Online (Sandbox Code Playgroud)
另请注意,Object,Array和RegExp函数可以创建新对象,甚至不使用operator new.然而,下面的人没有.
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'
Run Code Online (Sandbox Code Playgroud)
用户定义的函数是特例.
var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.
Run Code Online (Sandbox Code Playgroud)
由于Function类型对象可以创建新对象,因此它们也称为Constructors.
自动定义时,每个构造函数/函数(无论是内置的还是用户定义的)都有一个名为"prototype"的属性,默认情况下它的值被设置为一个对象.该对象本身有一个名为"constructor"的属性,默认情况下会引用构造函数/函数.
例如,当我们定义一个函数时
function UserDefinedFunction()
{
}
Run Code Online (Sandbox Code Playgroud)
以下自动发生
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
Run Code Online (Sandbox Code Playgroud)
此"prototype"属性仅存在于Function类型对象中 (并且永远不会出现在Non Function类型对象中).
这是因为当创建一个新对象(使用new运算符)时,它从Constructor函数的当前原型对象继承所有属性和方法,即 在新创建的对象中创建内部引用 ,该对象引用Constructor函数的当前原型对象引用的对象.
这个"内部参考"是在对象创建用于参考继承属性是被称为对象的原型(引用由构造的引用的对象"原型"属性,但不同的是从它).对于任何对象(函数或非函数),可以使用Object.getPrototypeOf()方法检索它.使用此方法可以跟踪对象的原型链.
此外,创建的每个对象(函数类型或非函数类型)都具有"构造函数"属性,该属性继承自构造函数的prototype属性引用的对象.默认情况下,这个"构造"属性引用的构造函数创建它(如果构造函数的默认的"原型"没有变化).
对于所有Function类型对象,构造函数始终是 函数Function(){}
对于非函数类型对象(例如,Javascript Built in Math对象),构造函数是创建它的函数.对于Math对象,它是函数Object(){}.
如果没有任何支持代码,上面解释的所有概念都可能有点令人生畏.请逐行浏览以下代码以了解概念.尝试执行它以更好地理解.
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"
Run Code Online (Sandbox Code Playgroud)
每个对象的原型链最终追溯到Object.prototype(它本身没有任何原型对象).以下代码可用于跟踪对象的原型链
var o=Starting object;
do {
alert(o + "\n" + Object.getOwnPropertyNames(o))
}while(o=Object.getPrototypeOf(o))
Run Code Online (Sandbox Code Playgroud)
各种对象的原型链如下所示.
要创建没有任何原型的对象,请使用以下命令:
var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null
Run Code Online (Sandbox Code Playgroud)
有人可能会认为将Constructor的prototype属性设置为null将创建一个带有null原型的对象.但是在这种情况下,新创建的对象的原型设置为Object.prototype,其构造函数设置为Object.以下代码对此进行了演示
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
Run Code Online (Sandbox Code Playgroud)
以下是本文的摘要
只有Function类型对象可以使用operator new创建一个新对象.这样创建的对象是非函数类型对象.该非功能型对象使用不能再创建一个对象的operator new.
默认情况下,所有函数类型对象都具有"原型"属性.此"prototype"属性引用具有"构造函数"属性的对象,该属性默认情况下引用Function类型对象本身.
所有对象(函数类型和非函数类型)都有一个"构造函数"属性,默认情况下引用创建它的函数类型对象/构造函数.
在内部创建的每个对象都引用由创建它的构造函数的"prototype"属性引用的对象 .此对象称为创建对象的原型(它与它引用的Function类型对象"prototype"属性不同).这样,创建的对象可以直接访问构造函数的"prototype"属性(在创建对象时)引用的对象中定义的方法和属性.
一个对象的原型(并且因此其继承的属性名称)可以使用被检索Object.getPrototypeOf() 方法.实际上,该方法可用于导航对象的整个原型链.
每个对象的原型链最终都追溯到Object.prototype(除非使用Object.create(null)创建对象,在这种情况下对象没有原型).
typeof(new Array())==='object'是语言设计而非道格拉斯克罗克福德指出的错误
将Constructor的prototype属性设置为null(或undefined,number,true,false,string)不应创建具有null原型的对象.在这种情况下,新创建的对象的原型设置为Object.prototype,其构造函数设置为Object.
希望这可以帮助.
Tha*_*var 22
prototypal
对于许多开发人员来说,继承的概念是最复杂的概念之一.让我们试着理解问题的根源,以便prototypal inheritance
更好地理解.让我们从一个plain
函数开始.
如果我们在上面使用new
运算符Tree function
,我们将其称为constructor
函数.
每个JavaScript
功能都有prototype
.当你登录时Tree.prototype
,你得到......
如果你查看上面的console.log()
输出,你可以看到一个构造函数属性Tree.prototype
和一个__proto__
属性.的__proto__
代表prototype
,这function
是基于关闭,因为这只是一个简单的JavaScript function
没有inheritance
建立的是,它指的是Object prototype
这仅仅是内置于JavaScript的东西...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
这有类似的东西.toString, .toValue, .hasOwnProperty
......
__proto__
带来了我的mozilla已被弃用,并被Object.getPrototypeOf
方法取代了object's prototype
.
Object.getPrototypeOf(Tree.prototype); // Object {}
Run Code Online (Sandbox Code Playgroud)
让我们为我们添加一个方法Tree
prototype
.
我们修改了Root
并添加了一个function
分支.
这意味着,当你创建instance
的Tree
,你可以调用它的branch
方法.
我们也可以添加primitives
或添加objects
到我们的Prototype
.
让我们添加一个child-tree
到我们Tree
.
这里从Tree Child
继承它prototype
,我们在这里做的是使用Object.create()
方法根据你传递的内容创建一个新对象,就在这里Tree.prototype
.在这种情况下,我们正在做的是将Child的原型设置为一个看起来与Tree
原型相同的新对象.接下来我们设置Child's constructor to Child
,如果我们不这样做,它会指向Tree()
.
Child
现在有自己的prototype
,它的__proto__
要点Tree
和Tree's prototype
指向基础Object
.
Child
|
\
\
Tree.prototype
- branch
|
|
\
\
Object.prototype
-toString
-valueOf
-etc., etc.
Run Code Online (Sandbox Code Playgroud)
现在您创建一个最初可用instance
的Child
和调用.我们实际上没有定义我们的.但是,孩子继承自哪个.branch
Tree
branch
Child prototype
Root prototype
在JS中,一切都不是一个对象,一切都可以像一个对象.
Javascript
有原始人喜欢strings, number, booleans, undefined, null.
他们不是object(i.e reference types)
,但肯定可以表现得像object
.我们来看一个例子吧.
在此列表的第一行中,primitive
为name分配了一个字符串值.第二行将名称视为an,object
并charAt(0)
使用点表示法调用.
这就是幕后发生的事情:// JavaScript
引擎的作用
该String object
只为它销毁前一个语句(这个过程被称为存在autoboxing
).让我们再回到我们的prototypal
inheritance
.
Javascript
支持delegation
基于的
继承prototypes
.Function
都有一个prototype
属性,它引用另一个对象.properties/functions
如果它不存在,则从它object
自身或通过
prototype
链看一个prototype
在JS是一个对象,yields
你的另一父object
.[即...授权] Delegation
意味着如果你无法做某事,你会告诉别人为你做这件事.
https://jsfiddle.net/say0tzpL/1/
如果你查看上面的小提琴,狗可以访问toString
方法,但它不可用,但可通过代表到的原型链获得Object.prototype
如果你看下面的一个,我们试图访问call
每个可用的方法function
.
https://jsfiddle.net/rknffckc/
如果您查看上面的小提琴,Profile
Function可以访问call
方法,但它不可用,但可以通过代理到的原型链获得Function.prototype
注意: prototype
是函数构造函数的属性,而是__proto__
从函数构造函数构造的对象的属性.每个函数都带有一个prototype
值为空的属性object
.当我们创建函数的实例时,我们得到一个内部属性[[Prototype]]
或其__proto__
引用是函数的原型constructor
.
上面的图看起来有点复杂,但是它展示了如何prototype chaining
工作的全貌.让我们慢慢来看看:
有两个实例b1
和b2
,它的构造是Bar
和家长是Foo和具有从原型链两种方法identify
,并speak
通过Bar
与Foo
https://jsfiddle.net/kbp7jr7n/
如果你查看上面的代码,我们有Foo
构造函数谁有方法identify()
和Bar
构造函数有speak
方法.我们创建了两个Bar
实例b1
和b2
其父类型Foo
.现在,在调用speak
方法时Bar
,我们能够识别通过prototype
链调用说话的人.
Bar
现在已经在Foo
其中定义了所有方法prototype
.让我们进一步深入理解Object.prototype
和Function.prototype
以及它们是如何相关的.如果你查找构造函数Foo
,Bar
并且Object
是Function constructor
.
该prototype
的Bar
就是Foo
,prototype
的Foo
就是Object
,如果你仔细看的prototype
的Foo
是有关Object.prototype
.
在我们关闭它之前,让我们在这里用一小段代码包装来总结上面的所有内容.我们在instanceof
这里使用运算符来检查object
其prototype
链中的prototype
属性是否在constructor
下面总结了整个大图.
我希望这可以添加一些信息,我知道这可能很难掌握......简单来说,它只是与对象相关的对象!
dir*_*tly 20
这个".prototype"属性的确切目的是什么?
标准类的接口变得可扩展.例如,您正在使用Array
该类,还需要为所有数组对象添加自定义序列化程序.您是否会花时间编写子类,或使用合成或...原型属性通过让用户控制类可用的确切成员/方法集来解决这个问题.
将原型视为额外的vtable指针.当原始类中缺少某些成员时,将在运行时查找原型.
tri*_*cot 19
将原型链分类为两类可能会有所帮助.
考虑一下构造函数:
function Person() {}
Run Code Online (Sandbox Code Playgroud)
值Object.getPrototypeOf(Person)
是一个函数.事实上,它是Function.prototype
.由于Person
是作为函数创建的,因此它共享所有函数具有的相同原型函数对象.它是相同的Person.__proto__
,但不应该使用该属性.无论如何,随着Object.getPrototypeOf(Person)
你有效地走上所谓的原型链的阶梯.
向上的链条看起来像这样:
Person
→交通Function.prototype
→交通Object.prototype
(终点)
重要的是,这个原型链与Person
可以构造的对象几乎没有关系.那些构造的对象具有它们自己的原型链,并且该链可能与上面提到的链没有共同的祖先.
以此对象为例:
var p = new Person();
Run Code Online (Sandbox Code Playgroud)
p与Person没有直接的原型链关系.他们的关系是不同的.对象p有自己的原型链.使用Object.getPrototypeOf
,你会发现链如下:
p
→交通Person.prototype
→交通Object.prototype
(终点)
这个链中没有功能对象(尽管可能是这样).
所以Person
似乎与两种生活相关的链条有关.要从一个链"跳"到另一个链,您使用:
.prototype
:从构造函数链跳转到created-object的链.因此,仅为函数对象定义此属性(因为new
只能在函数上使用).
.constructor
:从created对象的链跳转到构造函数的链.
以下是所涉及的两个原型链的可视化表示,表示为列:
总结一下:
该
prototype
属性不提供主题原型链的信息,也不提供主题创建的对象的信息.
毫不奇怪,该物业的名称prototype
可能导致混乱.如果这个属性被命名prototypeOfConstructedInstances
或沿着那条线的东西可能会更清楚.
您可以在两个原型链之间来回跳转:
Person.prototype.constructor === Person
Run Code Online (Sandbox Code Playgroud)
可以通过向prototype
属性显式指定不同的对象来打破这种对称性(稍后将详细介绍).
Person.prototype
是在创建函数的Person
同时创建的对象.它具有Person
构造函数,即使该构造函数实际上还没有执行.因此,同时创建了两个对象:
Person
本身两者都是对象,但它们具有不同的角色:函数对象构造,而另一个对象代表函数将构造的任何对象的原型.原型对象将成为其原型链中构造对象的父对象.
由于函数也是一个对象,它在自己的原型链中也有自己的父对象,但回想一下这两个链是不同的东西.
以下是一些可以帮助解决问题的平等 - 所有这些打印true
:
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);
Run Code Online (Sandbox Code Playgroud)
虽然在创建构造函数时会创建原型对象,但您可以忽略该对象,并指定另一个应该用作该构造函数创建的后续实例的原型的对象.
例如:
function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();
Run Code Online (Sandbox Code Playgroud)
现在t的原型链比p的长一步:
t
→交通p
→交通Person.prototype
→交通Object.prototype
(终点)
另外原型链是不再:Thief
和Person
是兄弟姐妹共享相同的父在他们的原型链:
Person
}
Thief
}→交通Function.prototype
→交通Object.prototype
(终点)
然后可以将先前呈现的图形扩展到此(原始图像Thief.prototype
被省略):
蓝线代表原型链,其他彩色线代表其他关系:
Bad*_*Bad 16
面向对象JavaScript的权威指南 - 一个非常简洁明了的〜30分钟的问题视频解释(原型继承主题从5:45开始,虽然我宁愿听完整个视频).此视频的作者还制作了JavaScript对象可视化工具网站http://www.objectplayground.com/.
B M*_*B M 14
我发现obj_n.prop_X
在引用时将"原型链"解释为递归约定很有帮助:
如果obj_n.prop_X
不存在,请检查obj_n+1.prop_X
位置obj_n+1 = obj_n.[[prototype]]
如果prop_X
最终在第k个原型对象中找到了那么
obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X
您可以在此处找到Javascript对象的属性关系图:
小智 13
当构造函数创建对象时,该对象隐式引用构造函数的"prototype"属性以解析属性引用.构造函数的"prototype"属性可以由程序表达式constructor.prototype引用,添加到对象原型的属性通过继承由共享原型的所有对象共享.
Ara*_*ind 10
让我告诉你我对原型的理解.我不打算将这里的继承与其他语言进行比较.我希望人们不要再比较语言,只要把语言理解为自己.了解原型和原型继承非常简单,我将在下面向您展示.
Prototype就像一个模型,在此基础上您可以创建产品.要理解的关键点是,当您使用另一个对象创建一个对象作为原型时,原型和产品之间的链接将持续存在.例如:
var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5
Run Code Online (Sandbox Code Playgroud)
每个对象都包含一个名为[[prototype]]的内部属性,该属性可由Object.getPrototypeOf()
函数访问.Object.create(model)
创建一个新对象并将其[[prototype]]属性设置为对象模型.因此,当您这样做时Object.getPrototypeOf(product)
,您将获得对象模型.
产品中的属性按以下方式处理:
使用prototype属性对象的这种链接称为原型继承.在那里,它是如此简单,同意?
Jim*_*ard 10
这里有两个不同但相关的实体需要解释:
.prototype
功能的属性.[[Prototype]]
[1]属性[2].这是两件不同的事情.
[[Prototype]]
属性:这是所有[2]对象上都存在的属性.
这里存储的是另一个对象,作为一个对象本身,它有一个[[Prototype]]
指向另一个对象的对象.那个其他对象有[[Prototype]]
它自己的.这个故事一直持续到您提供的原型对象提供可在所有对象上访问的方法(如.toString
).
该[[Prototype]]
物业是形成[[Prototype]]
连锁店的一部分.这个[[Prototype]]
对象链是例如在对象上执行[[Get]]
或[[Set]]
操作时检查的对象:
var obj = {}
obj.a // [[Get]] consults prototype chain
obj.b = 20 // [[Set]] consults prototype chain
Run Code Online (Sandbox Code Playgroud)
.prototype
属性:这是一个只能在函数中找到的属性.使用一个非常简单的功能:
function Bar(){};
Run Code Online (Sandbox Code Playgroud)
该.prototype
属性包含一个将b.[[Prototype]]
在您执行时分配的对象var b = new Bar
.你可以轻松地检查一下:
// 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
Run Code Online (Sandbox Code Playgroud)
其中最重要的.prototype
-是不是对的Object
功能.这个原型保存了所有[[Prototype]]
链包含的原型对象.在其上,定义了新对象的所有可用方法:
// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))
Run Code Online (Sandbox Code Playgroud)
现在,既然.prototype
是一个对象,它就有一个[[Prototype]]
属性.当你不做出任何任务Function.prototype
时,.prototype
的[[Prototype]]
指向原型对象(Object.prototype
).每次创建新功能时都会自动执行此操作.
这样,无论new Bar;
何时为您设置原型链,您都可以获得定义的所有内容Bar.prototype
以及定义的所有内容Object.prototype
:
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)
Run Code Online (Sandbox Code Playgroud)
当你这样做使分配到Function.prototype
所有你正在做的是延长了原型链包含另一个对象.这就像插入单链表中一样.
这基本上改变了[[Prototype]]
链,允许Function.prototype
由分配给的对象上定义的属性被函数创建的任何对象看到.
[1:这不会混淆任何人; 通过提供的__proto__
性能在许多实现.
[2]:除了null
.
考虑以下keyValueStore
对象:
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; }
};
})();
Run Code Online (Sandbox Code Playgroud)
我可以通过这样做来创建这个对象的新实例:
kvs = keyValueStore.create();
Run Code Online (Sandbox Code Playgroud)
该对象的每个实例都具有以下公共属性:
data
get
set
delete
getLength
现在,假设我们创建了此keyValueStore
对象的100个实例.尽管get
,set
,delete
,getLength
会做同样的事情对每个100个实例,每个实例都有自己的这个函数的副本.
现在,想象一下,如果你可以有只是一个单一的get
,set
,delete
和getLength
复制,并且每个实例将引用相同的功能.这对性能更好,并且需要更少的内存.
这就是原型进入的地方.原型是属性的"蓝图",它是继承的,但不是由实例复制的.所以这意味着它只在内存中存在一个对象的所有实例,并由所有这些实例共享.
现在,keyValueStore
再次考虑该对象.我可以像这样重写它:
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; }
};
})();
Run Code Online (Sandbox Code Playgroud)
这与keyValueStore
对象的先前版本完全相同,只是它的所有方法现在都放在原型中.这意味着,现在所有100个实例都共享这四种方法,而不是每种方法都有自己的副本.
在理解这类东西时,我总是喜欢类比.在我看来,与原型低音继承相比,"原型继承"相当令人困惑,尽管原型是更简单的范例.事实上,对于原型,实际上没有继承,因此名称本身就具有误导性,它更像是一种"委托".
想象一下......
你在高中,而且你在课堂上并且有一个今天到期的测验,但你没有笔来填写你的答案.卫生署!
你坐在你的朋友Finnius旁边,他可能有一支钢笔.你问,他看着他的桌子不成功,但他没有说"我没有笔",他是一个很好的朋友,如果他有笔,他会和他的另一个朋友Derp一起检查.Derp确实有一支备用笔并将其传递回Finnius,后者将其传递给您以完成您的测验.Derp已将笔委托给Finnius,后者已将笔委托给您使用.
这里最重要的是Derp不会给你笔,因为你与他没有直接关系.
这是原型如何工作的简化示例,其中搜索数据树以查找您正在寻找的事物.
new
关键字的构造函数时,对象将获取原型。可以__proto__
在新创建的对象的属性上找到对该原型的引用。__proto__
属性是指prototype
构造函数的属性。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.
Run Code Online (Sandbox Code Playgroud)
当在对象上查找属性时,JavaScript具有一种称为“原型继承”的机制,基本上是这样做的:
例如:
function Person(name) {
this.name = name;
}
let mySelf = new Person('Willem');
console.log(mySelf.__proto__ === Person.prototype);
console.log(mySelf.__proto__.__proto__ === Object.prototype);
Run Code Online (Sandbox Code Playgroud)
更新:
__proto__
尽管已在大多数现代浏览器中实现了该属性,但已弃用该 属性,获取原型对象引用的一种更好的方法是:
Object.getPrototypeOf()
归档时间: |
|
查看次数: |
486300 次 |
最近记录: |