prototype与_proto_
对象的 prototype 属性的方法、属性为对象所属的那一“类”所共有。对象原型链通过 proto 属性向上寻找。
为 proto 指定 null 之外的原始类型(Number, String, Boolean, undefined, Symbol)值是无效的。
通过构造函数或者 {} 方式创建的对象的 prototype 属性默认为 undefined
var a = {
x: 10,
calculate: function (z) {
return this.x + this.y + z;
}
};
var b = {
y: 20,
__proto__: a
};
var c = {
y: 30,
__proto__: a
};
// call the inherited method
b.calculate(30); // 60
c.calculate(40); // 80
如果没有明确指定,那么 proto 默认为 Object.prototype,而Object.prototype 自身也有 proto ,值为 null,是原型链的终点。
构造函数模式的继承
// a constructor function
function Foo(y) {
// which may create objects
// by specified pattern: they have after
// creation own "y" property
this.y = y;
}
// also "Foo.prototype" stores reference
// to the prototype of newly created objects,
// so we may use it to define shared/inherited
// properties or methods, so the same as in
// previous example we have:
// inherited property "x"
Foo.prototype.x = 10;
// and inherited method "calculate"
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
};
// now create our "b" and "c"
// objects using "pattern" Foo
var b = new Foo(20);
var c = new Foo(30);
// call the inherited method
b.calculate(30); // 60
c.calculate(40); // 80
// let's show that we reference
// properties we expect
console.log(
b.__proto__ === Foo.prototype, // true
c.__proto__ === Foo.prototype, // true
// also "Foo.prototype" automatically creates
// a special property "constructor", which is a
// reference to the constructor function itself;
// instances "b" and "c" may found it via
// delegation and use to check their constructor
b.constructor === Foo, // true
c.constructor === Foo, // true
Foo.prototype.constructor === Foo, // true
b.calculate === b.__proto__.calculate, // true
b.__proto__.calculate === Foo.prototype.calculate // true
);
如果没有明确指定,通过构造函数创建的对象的 proto 属性值为构造函数的 prototype 属性。
下面的写法在javascript是很常见的,但是javascript中的new的执行过程是怎么样子的呢?看下面写法:
var Person = function(name) {
this.name = name;
}
var p = new Person();
new操作符的操作是:
var p = {}
p.proto = Person.prototype
Person.call(p)
var p={}; 也就是说,初始化一个对象p。
p.proto = Person.prototype;
Person.call(p);也就是说构造p,也可以称之为初始化p。
var Person = function() {}
var p = new Person();
alert(p.__proto__ == Person.prototype)
这段代码会返回true。说明我们步骤2的正确。
那么proto是什么?我们在这里简单地说下。每个对象都会在其内部初始化一个属性,就是proto,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去proto里找这个属性,这个proto又会有自己的proto,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
按照标准,proto是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。
好,概念说清了,让我们看一下下面这些代码:
var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
var p = new Person();
p.Say();
这段代码很简单,相信每个人都这样写过,那就让我们看下为什么p可以访问Person的Say。
首先var p=new Person();可以得出p.proto=Person.prototype。那么当我们调用p.Say()时,首先p中没有Say这个属性,于是,他就需要到他的proto中去找,也就是Person.prototype,而我们在上面定义了Person.prototype.Say=function(){}; 于是,就找到了这个方法。
好,接下来,让我们看个更复杂的。
var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
Person.prototype.Salary = 50000;
var Programmer = function () { };
Programmer.prototype = new Person();
Programmer.prototype.WriteCode = function () {
alert("programmer writes code");
};
Programmer.prototype.Salary = 500;
var p = new Programmer();
p.Say();
p.WriteCode();
alert(p.Salary);
我们来做这样的推导:
var p=new Programmer()可以得出p.proto=Programmer.prototype;
而在上面我们指定了Programmer.prototype=new Person();我们来这样拆分,var p1=new Person();Programmer.prototype=p1;那么:
p1.proto=Person.prototype;
Programmer.prototype.proto=Person.prototype;
由根据上面得到p.proto=Programmer.prototype。可以得到p.proto.proto=Person.prototype。
好,算清楚了之后我们来看上面的结果,p.Say()。由于p没有Say这个属性,于是去p.proto,也就是Programmer.prototype,也就是p1中去找,由于p1中也没有Say,那就去p.proto.proto,也就是Person.prototype中去找,于是就找到了alert(“Person say”)的方法。
其余的也都是同样的道理。
1.总共三类对象(蓝色大框)
2.实例对象(通过new XX() 所得到的实例),跟原型链相关的只有 proto 属性,指向其对应的原型对象 *.prototype 。
3.构造函数对象分原生和自定义两类。跟原型链相关的有 proto 属性,除此之外还有 prototype 属性。它们的 proto 属性都是指向 Function.prototype 这个原型对象的。prototype 也是指向对应的原型对象。
4.原型对象除了一样拥有 proto 外,也拥有独有的属性 constructor 。它的proto 指向的都是 Object.prototype ,除了 Object.prototype 本身,它自己是指向 null 。而 constructor 属性指向它们对应的构造函数对象。
5.原型链是基于 proto 的。实例只能通过其对应原型对象的 constructor 才能访问到对应的构造函数对象。构造函数只能通过其对应的 prototype 来访问相应的原型对象。
function People(name)
{
this.name=name;
//对象方法
this.Introduce=function(){
alert("My name is "+this.name);
}
}
//类方法
People.Run=function(){
alert("I can run");
}
//原型方法
People.prototype.IntroduceChinese=function(){
alert("我的名字是"+this.name);
}
//测试
var p1=new People("Windking");
p1.Introduce();
People.Run();
p1.IntroduceChinese();
function Father(){
this.name = "lisi";
this.con = function(){
console.log("aaa")
}
}
Father.prototype.use = function(){
alert("use")
}
var s = new Father();
for(var i in s){
console.log( i );
}
//name,con,use