Javascript prototype是如何工作的?
我不太喜欢动态编程语言,但我已经编写了相当多的JavaScript代码。我从来没有真正了解过这种基于原型的编程,有人知道它是如何工作的吗Javascript prototype是如何工作的?,javascript,dynamic-languages,prototype-oriented,Javascript,Dynamic Languages,Prototype Oriented,我不太喜欢动态编程语言,但我已经编写了相当多的JavaScript代码。我从来没有真正了解过这种基于原型的编程,有人知道它是如何工作的吗 var obj = new Object(); obj.prototype.test = function() { alert('Hello?'); }; var obj2 = new obj(); obj2.test(); 我记得不久前我和人们进行了很多讨论(我不确定我在做什么),但据我所知,没有课堂的概念。它只是一个对象,这些对象的实例是原始对象的克隆,
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
我记得不久前我和人们进行了很多讨论(我不确定我在做什么),但据我所知,没有课堂的概念。它只是一个对象,这些对象的实例是原始对象的克隆,对吗
但是JavaScript中这个“.prototype”属性的确切用途是什么?它与实例化对象有什么关系
更新:正确的方法
此外,这些工具确实帮助很大。
prototype
允许您创建类。如果不使用prototype
,则它将成为静态的
下面是一个简短的例子
var obj = new Object();
obj.test = function() { alert('Hello?'); };
在上述情况下,您有静态函数调用测试。此函数只能由obj.test访问,您可以将obj想象为一个类
如以下代码所示
function obj()
{
}
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
obj已经成为一个现在可以实例化的类。obj可以存在多个实例,它们都具有test
功能
以上是我的理解。我正在把它变成一个社区wiki,这样人们可以在我错的时候纠正我。
prototype
允许你创建类。如果不使用prototype
,则它将成为静态的
下面是一个简短的例子
var obj = new Object();
obj.test = function() { alert('Hello?'); };
在上述情况下,您有静态函数调用测试。此函数只能由obj.test访问,您可以将obj想象为一个类
如以下代码所示
function obj()
{
}
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
obj已经成为一个现在可以实例化的类。obj可以存在多个实例,它们都具有test
功能
以上是我的理解。我把它变成了一个社区维基,所以如果我错了,人们可以纠正我
此“.prototype”属性的确切用途是什么
标准类的接口变得可扩展。例如,您正在使用数组
类,并且还需要为所有数组对象添加自定义序列化程序。你会花时间编写一个子类,还是使用合成或。。。prototype属性通过让用户控制类可用的确切成员/方法集来解决这个问题
将原型视为一个额外的vtable指针。当原始类中缺少某些成员时,将在运行时查找原型
此“.prototype”属性的确切用途是什么
标准类的接口变得可扩展。例如,您正在使用数组
类,并且还需要为所有数组对象添加自定义序列化程序。你会花时间编写一个子类,还是使用合成或。。。prototype属性通过让用户控制类可用的确切成员/方法集来解决这个问题
将原型视为一个额外的vtable指针。当原始类中缺少一些成员时,将在运行时查找原型。Javascript没有通常意义上的继承,但它具有原型链 原型链 如果在对象中找不到对象的成员,则会在原型链中查找该成员。链由其他对象组成。可以使用
\uuuu proto\uuu
变量访问给定实例的原型。每个对象都有一个,因为javascript中的类和实例之间没有区别
向原型中添加函数/变量的优点是,它必须只在内存中存在一次,而不是针对每个实例
它对于继承也很有用,因为原型链可以由许多其他对象组成。Javascript没有通常意义上的继承,但它有原型链 原型链 如果在对象中找不到对象的成员,则会在原型链中查找该成员。链由其他对象组成。可以使用
\uuuu proto\uuu
变量访问给定实例的原型。每个对象都有一个,因为javascript中的类和实例之间没有区别
向原型中添加函数/变量的优点是,它必须只在内存中存在一次,而不是针对每个实例
它对于继承也很有用,因为原型链可以由许多其他对象组成。每个名为[[prototype]]]
的JavaScript对象,其值为null
或对象
。您可以将插槽视为对象上的属性,位于JavaScript引擎内部,隐藏在您编写的代码之外。[[Prototype]]
周围的方括号是经过深思熟虑的,是一种表示内部插槽的ECMAScript规范约定
对象的[[Prototype]]
指向的值通俗地称为“该对象的原型”
如果您通过点(obj.propName
)或括号(obj['propName']
)符号访问属性,并且对象没有直接具有这样的属性(即,可以通过obj.hasOwnProperty('propName')
进行检查的自有属性),则运行时会在引用的对象上查找具有该名称的属性[[Prototype]]
。如果[[Prototype]]
也没有这样的属性,则依次检查其[[Prototype]]
,依此类推。这样,将遍历原始对象的原型链,直到找到匹配项或到达其末端。原型链顶部是null
值
现代JavaScript实现允许通过以下方式读取和/或写入[[Prototype]]
:
new
操作符(在构造函数返回的默认对象上配置原型链)扩展了
关键字(在使用类语法时配置原型链)object [[Prototype]] → aFunction.prototype
anObject.__proto__ === anotherObject
// (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
var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
Person("George");
getName();//would print the "George" in the console
person.Person = Person;
person.getName = getName;
person.Person("George");
person.getName();// -->"George"
Object {Person: function, getName: function, name: "George"}
person.__proto__.Person = Person;
person.__proto__.getName = getName;
person.__proto__ = {
Person: Person,
getName: getName
};
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
console.log(person.__proto__===propertiesObject); //true
Person.call(person, "George");
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
var newObject = {};
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
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"
newObject.getName();
Person.call(newObject, "George");
Person.apply(newObject, ["George"]);
new FunctionName()
console.log(Object.prototype.__proto__===null);//true
var F = function() {}
var f = new F()
f.__proto__ === F.prototype
f = Object.create(proto)
f.__proto__ === proto
var F = function(i) { this.i = i }
var f = new F(1)
(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)
var f = new F(1)
f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor
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
}
}
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "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
// "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
// 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
(c)----->(1)
| i
|
|
|[[Prototype]]
|
|
v __proto__
(C)<--------------(D) (d)
| | | |
| | | |
| |prototype |prototype |[[Prototype]]
| | | |
| | | |
| | | +---------+
| | | |
| | | |
| | v v
|[[Prototype]] (D.prototype)--------> (inc2 function object)
| | | inc2
| | |
| | |[[Prototype]]
| | |
| | |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
| inc
v
Function.prototype
c = new C(1)
c.inc() === 2
c.inc()
var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5
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")
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()
var b=new a() //error. a is not typeof==='function'
var b=new Math() //error. Math is not typeof==='function'
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'
var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.
function UserDefinedFunction()
{
}
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
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"
var o=Starting object;
do {
alert(o + "\n" + Object.getOwnPropertyNames(o))
}while(o=Object.getPrototypeOf(o))
var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null
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
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; }
};
})();
kvs = keyValueStore.create();
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; }
};
})();
Object.getPrototypeOf(Tree.prototype); // Object {}
Child
|
\
\
Tree.prototype
- branch
|
|
\
\
Object.prototype
-toString
-valueOf
-etc., etc.
function Person() {}
var p = new Person();
Person.prototype.constructor === Person
var obj = {}
obj.a // [[Get]] consults prototype chain
obj.b = 20 // [[Set]] consults prototype chain
function 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
// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(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)