javascript - JavaScript如何使用.prototype?

  显示原文与译文双语对照的内容

我不是那种动态编程语言,但我已经编写了我的JavaScript代码共享。 我从来没有真正了解过这个prototype-based编程,有谁知道它是如何工作的?


var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

我记得很多时候我跟别人聊天,我并不确定我在做什么。 就像我所理解的,没有类的概念,它只是一个对象,这些对象的实例是原始对象的克隆?

但是在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

同时这些幻灯片真的帮助了很多。

时间:

每个JavaScript对象都有一个名为 [[Prototype] ]的内部属性。 如果通过 obj.propName 或者 obj['propName'] 查找属性,并且对象没有这样的属性- 可以通过 obj.hasOwnProperty('propName') 检查该属性- 运行时在 [[Prototype] ] 引用的对象中查找属性。 如果该prototype-object还不具有这种属性的对象,它的Prototype是依次检查,从而遍历整个原始 prototype-chain,直至找到匹配项或者它的结束时为止。

一些浏览器提供了实现都允许直接进入 [[Prototype] ] 属性( 如通过一个名为 __proto__ non-standard属性) 。 通常,只有在创建对象时才能设置对象 Prototype: 如果你通过 new Func() 创建新对象,对象的[[Prototype] ] 属性将被设置为由 Func.prototype 引用的对象。

这允许在JavaScript中模拟类,尽管我们已经看到了JavaScript系统的继承- - Prototype,而不是 class-based:

只需将构造函数的函数看作类,Prototype ( IE 函数在构造函数 prototype 所引用的对象的一些属性)的属性作为共享成员,即每个实例的IE 成员。 在class-based系统中,方法的实现方式与每个实例相同,因此方法通常被添加到Prototype中,而对象的字段是 instance-specific,因此在构造过程中添加到对象本身。

以一种实现经典继承的语言如 Java,C# 或者 C++ 首先需要创建一个从该类class--a蓝图为你objects--and然后你可以创建新的对象,也可以扩展这个类,定义一个新的类,它进一步增强原来的类。

在JavaScript中你首先创建一个对象( 没有类的概念),然后你可以扩充你自己的对象或者从它创建新对象。 于有人习惯了经典way,相关并不困难,但是有点外,难以

例如:


//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();

直到现在,我一直在扩展基本对象,现在我创建另一个对象,然后从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());


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() 。


//The following statement generates an error.
john.setAmountDue(1000);

我扮演了一个JavaScript教师的角色,Prototype概念一直是我在教学中的一个争论的话题。 我花了一点时间想出了一个清晰的方法来阐明这个概念,现在在本文中,我将尝试解释如何做 JavaScript 。Prototype工作。


这是一个非常简单的基于Prototype的对象模型,在解释过程中将被视为一个示例,但没有注释:


function Person(name){
 this.name = name;
}
Person.prototype.getName = function(){
 console.log(this.name);
}
var person = new Person("George");


在通过Prototype概念之前,我们必须考虑一些关键问题。

1-如何实际工作:

踏出第一步,我们必须弄明白,如何的JavaScript函数实际工作,作为一个类,如函数使用 this 关键字在它或者与它的参数就像一个普通的函数,它能做什么以及它的返回的内容。

假设我们想创建一个 Person 对象模型。 使用 prototypenew 关键字,的但多半在这一步我是在试图做同样的那间事情 without.

所以在这一步 functionsobjectsthis 关键字,都是我们有。

使用 new 关键字,第一个问题将是 this 如何关键字可能有用 without.

这样,我们假设我们有一个空对象,以及两个函数:


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

在这种情况下,这将是当前的上下文对象,它通常是被全局对象在浏览器中或者在 Node.jsGLOBALwindow 。 它意味着我们必须在浏览器中,window.name 或是以"乔治"为它的value, GLOBAL.name 在 node.js,.

b 。我们可以 它们附加到一个对象,作为它的属性

- 为此最简单的方式是修改空 Person 对象的数据结构,如


person.Person = Person;
person.getName = getName;

这样我们就可以调用它们:


person.Person("George");
person.getName();//-->"George"

现在 Person 对象就像:


Object {Person: function, getName: function, name:"George"}


在另一页的摘要 part, - 方法附上一个属性到对象正在使用的该对象的prototype,可以发现在任何一个JavaScript对象,该对象具有名称 __proto__,我曾试过做一些解释.对 这样我们就可以得到类似的结果:


person.__proto__.Person = Person;
person.__proto__.getName = getName;

这种方式现在我们已经正在修改使用字面值( {.. . } ) Object.prototype,因为每当我们创建一个JavaScript对象,所做的才到基于 Object.prototype 创建,这意味着自然就附加到新创建的对象作为一个命名叫 __proto__,所以如果我们改变它,因为我们已经做了在我们上面代码中,所有的js对象都可能有所变化,而不是一个好的实践。 那么现在更好的做法是:


person.__proto__ = {
 Person: Person,
 getName: getName
};

现在其他的对象都是安静的,但它似乎不是一个好的实践。 所以我们还有一个解决方案,但是要使用这个解决方案,我们应该回到创建 Person 对象的代码行 var person = {}; ) 然后将它的改为:


var propertiesObject = {
 Person: Person,
 getName: getName
};
var person = Object.create(propertiesObject);

它所做的是创建一个新的JavaScript Object 并将 propertiesObject 附加到 __proto__ 属性。 为了确保你能够:


console.log(person.__proto__===propertiesObject);//true

但是这里棘手的一点是你可以访问 __proto__Person object(read the summary part for more detail)的第一个级别中定义的所有属性。


就像你看到的使用这两种方法中的任何一种 this 都会指向 Person 对象。

this 有另一种提供函数的方法,它使用调用或者来调用函数。

apply() 方法用给定的这个值调用一个函数,参数作为数组( 或者array-like对象) 提供。

call() 方法使用给定的值调用一个函数,并提供单独提供的参数。

这种方式是我最喜欢的,我们可以轻松地调用我们的函数,比如:


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 functionality.this的第二步,我使用它来模拟流程:


function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };

在这一部分我把订货是试图采取哪些JavaScript采取的所有步骤,而无需使用 new 关键字以及 prototype,当你使用 new 关键字。 所以当我们做 new Person("George") 时,Person 函数充当一个构造函数,这就是JavaScript所做的,一个一个:

首先,它创建一个空对象,基本上是一个空的哈希像:


var newObject = {};

b 。js采取的下一个步骤是以 了所有Prototype对象附加到新创建的对象

这里的my_person_prototype 与Prototype对象相似。


for(var key in my_person_prototype){
 newObject[key] = my_person_prototype[key];
}

JavaScript并不是真正地附加在Prototype中定义的属性。 实际的方式与Prototype链概念相关。


&,而不是这两个步骤,你可以通过执行以下操作获得完全相同的结果:


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 function:

 
newObject.getName();

 

然后,它将对象赋予构造函数,

我们可以用下面的示例来实现:


Person.call(newObject,"George");

或者


Person.apply(newObject, ["George"]);

然后该构造函数可以做什么它想要,因为这里 放进这个构造函数是创建的对象,它只是。

模拟其他步骤之前的最终结果: 对象 {name:"乔治"}


摘要:

实际上,当你使用了一个函数,要调用上关键字在这个或者那个函数可以作为一个构造器,那么你说:

 
new FunctionName()

 

结束时你的函数内部 body, JavaScript使绘制的对象,一个空的散列,然后给出了该对象到构造函数,那么该构造函数可以做什么它想要,因为这里 放进这个构造函数是对象,该对象刚刚创建的该对象,然后它给你在你的函数中返回语句或者如果你已经将一个当然可以下载任何东西

所以当JavaScript在一个对象上查找一个属性时,它所做的第一件事就是在那个对象上查找它。 在next,然后有一个秘密属性 [[prototype]] 这我们一般都有它像 __proto__ 这种性质就是浏览器提供了建筑物贴 而当它将彻底检查 __proto__,至于再上面是另一个JavaScript对象,它拥有自己的__proto__ 属性,它的价值也会和,知道它使得在某一点的下一个 __proto__ 为空,则。 要点是JavaScript中唯一的对象,它的__proto__ 属性是 Object.prototype 对象:


console.log(Object.prototype.__proto__===null);//true

这就是继承在JavaScript中的作用。

The prototype chain

换句话说,当你在函数上拥有一个Prototype属性并且调用了一个新的对象时,JavaScript完成了对新创建的对象的属性查看之后,它就会看到函数的.prototype,它也有它自己的内部 Prototype 。 等等。

prototype 允许你创建类。 如果你不使用 prototype,那么它就变成静态的。

下面是一个简短的例子。


var obj = new Object();
obj.test = function() { alert('Hello?'); };

在上面的例子中,你有静态funcation调用测试。 这里函数只能由 obj.test 访问,在那里你可以想象obj是一个类。

如下面的代码所示


function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

obj已经成为一个可以实例化的类。 对象的多个实例可以存在,它们都有 test 函数。

上是我的理解。 我把它做成社区维基,这样人们就可以纠正我如果我错了。

在读取这个线程之后,我感到困惑于 JavaScript Prototype链,然后我发现这些图表

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance*[[protytype]]* and <code> prototype </code> property of function objects

通过Prototype链 它是一个清晰的图表以显示js继承

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

这个例子包含一个带有代码和几个漂亮图表的示例。

Prototype链最终回退到 Object.prototype 。

Prototype链可以在技术上扩展,只要你想,每次通过设置子类的Prototype等于父类的一个对象。

希望对你理解 JavaScript Prototype链也有帮助。

每个对象都有一个内部属性 [[Prototype] ],将它的链接到另一个对象:


object [[Prototype]] -> anotherObject

在传统的javascript中,第二个对象是函数的prototype 属性:


object [[Prototype]] -> aFunction.prototype

1..__proto__ == Number.prototype
"".__proto__ == String.prototype
[].__proto__ == Array.prototype

创建对象时创建 [[Prototype] ] 链接:


var object = Object.create( anotherObject )
//: object.__proto__ = anotherObject

在传统的javascript中,它使用 new:


var object = new aFunction;
//: object.__proto__ = aFunction.prototype;

他们选择了这种语法,所以你可以使用函数作为构造函数:


var object = new aFunction("☺︎");
//: object = aFunction.call({},"☺︎")
//: object.__proto__ = aFunction.prototype;

所以如果你想在Prototype链上共享属性,你必须把它们放在函数的prototype 属性上。

如果不需要构造函数,只需使用 Object.create 就可以了:


var duck = { says:"quack!" };
var mallard = Object.create(duck);

Object.getPrototypeOf(mallard) === duck;
//-> true
duck.isPrototypeOf(mallard)
//-> true

使用 new: 创建一个函数,增加它的prototype 属性,然后将它作为构造函数调用:


var Duck = function (){};
Duck.prototype.says ="quack!";

var mallard = new Duck;
mallard.says;
//->"quack!"

mallard instanceof Duck;
//-> true
mallard.constructor === Duck === Duck.prototype.constructor;
//-> true
Object.getPrototypeOf(mallard) === Duck.prototype;
//-> true
Duck.prototype.isPrototypeOf(mallard);
//-> true

Javascript在通常意义上没有继承,但它有Prototype链。

Prototype链

如果在Prototype链中找不到对象的成员,则在Prototype链中查找它。 链由其他对象组成。 可以使用 __proto__ 变量访问给定实例的Prototype 。 每个对象都有一个,因为在javascript中类和实例没有区别。

将一个函数/变量添加到Prototype的好处是它只能在内存中一次,而不是每个实例。

它对于继承也很有用,因为Prototype链可以包含许多其他对象。

这里"。Prototype"属性的确切用途是什么?

到标准类的接口变得可以扩展。 例如你正在使用 Array 类,你还需要为所有数组对象添加一个自定义序列化程序。 你会花费时间编码子类,还是使用组合或者。。 Prototype属性通过允许用户控制可以用于类的成员/方法的确切集合来解决这个问题。

把Prototype看作一个额外的vtable-pointer 。 当某些成员从原始类中丢失时,在运行时查找 Prototype 。

1 ) 两种不同的东西可以被称为"Prototype":

  • Prototype属性,如 obj.prototype 中所示

  • Prototype内部属性,在ES5中表示为 [[Prototype]]

    它可以通过 ES5 Object.getPrototypeOf() 检索。

    Firefox 使它可以通过 __proto__ 属性作为扩展访问。


磅2 )

  • __proto__ 用于点 . 属性查找,如 obj.property
  • 在对象创建与 .prototype 不是直接用于执行查找,只是间接地因为它决定

查找顺序为:

  • obj 属性用 obj.p =.. . 或者 Object.defineProperty(obj,.. .) 添加
  • obj.__proto__的属性
  • obj.__proto__.__proto__的属性,等等
  • 如果某些 __proto__null,返回 undefined

如果要避免查找并只查找给定对象,可以使用 Object.getOwnProperty(obj)


3 ) 主要有两种方法可以设置 obj.__proto__: newObject.create

  • new:

    
    var F = function() {}
    var f = new F()
    
    

    然后 new 已经设置:

    
    f.__proto__ === F.prototype
    
    
  • Object.create:

    
     f = Object.create(proto)
    
    

    集合:

    
    f.__proto__ === proto
    
    

当你做时,4 )f = new Fnew 还设置 f.constructor = F

这允许你获取对象的构造函数,这些对象与"经典"面向对象语言中的类相对应。


5 ) 代码:


var F = function() {}
var f = new F()

对应于以下图表:


(Function) ( F ) (f)
 | | | ^ |
 | | | | |
 | | | +-------------------------+ |
 | | | | |
 | | +--------------+ | |
 | | | | |
 | | | | |
 |[[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)

一旦你看到了这一点,就很清楚了为什么以下所有都是真的:


Object.getPrototypeOf(f) === F.prototype
Object.getPrototypeOf(F) === Function.prototype
Object.getPrototypeOf(F.prototype) === Object.prototype

f.prototype === undefined
F.prototype.constructor === F

f.constructor === F
F.constructor === Function

//`constructor` comes from `F.prototype` through lookup.
!f.hasOwnProperty('constructor')
F.prototype.hasOwnProperty('constructor')


6 ) 如果修改 prototype,你添加新属性以这以它为 [[Prototype]] 因为所有对象的查找:


f = new F()
F.prototype.a = 1
f.a === 1

你也可以将 prototype 设置为任何对象:


F.prototype = {a:1}
g = new F()
g.a === 1

但这并不很酷,因为那时:


g.constructor === Object

而不是 F 所期望的。 这是因为现在 g.__proto__ = {a:1},它是一个 Object,并且不包含 constructor,所以它查看 {}.__proto__ === Object.prototype 并查找 Object

当构造函数创建一个对象时,该对象隐式引用"构造函数 Prototype"属性以解析属性引用。 "构造函数 Prototype"属性可以由程序表达式构造函数引用。Prototype和添加到对象Prototype的属性是共享的,通过共享Prototype的所有对象共享。

...