javaScript中的prototype与_proto_

来源:互联网 发布:安卓备份软件 编辑:程序博客网 时间:2024/06/13 18:48

这几天读了JavaScript设计模式的继承,开始对于其中的类式继承和原型式继承中的prototype属性百思不得其解,但后来的查阅和实践让我对他更深层次地理解,纯属个人理解,有不对的内容还不吝赐教。

Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。

每个对象都有一个原型对象,但这并不意味着每个对象都有一个一个prototype属性,只有函数对象才有这个对象。如:

var b = {
name: 'hello world!'
}


b是一个对象字面值,不是一个函数对象,其实它相当于Object的一个实例。

在创建一个对象时,JavaScript会自动将其原型对象设置为其构造函数的prototype属性所指的对象。应该注意的是,构造函数本身也是一个对象,它也有自己的原型对象,但这个原型不是它的prototype所向的那个对象。作为一个对象,其构造函数是Function,因此,构造函数的原型对象实际上是Function.prototype所指向的对象。

1.类式继承中的代码如下:

function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}
function Author(name, books){
Person.call(this, name);
this.books = books;
}

Author.prototype = new Person();
Author.prototype.constructor = Author;

Author.prototype.getBooks = function(){
return this.books.toString();
}
var a  =  new Author('hudie', []);
alert(a.getName() + 'write:' + a.getBooks());

一开始对Author.prototype = new Person()这一行很不解,为什么不直接设置成Author.prototype =  Person,后来结果完全不一样,如下图所示:


且提示错误:a.getName is not a function,这是因为你相当于把Person这个对象的引用传递给了Author.prototype,后面对Author.prototype.constructor进行修改,这相当于把Person也改变了,所以是不行的,且Author的实例化对象a的中的_proto_为空,所以无法调用getName()。而如果是Author.prototype = new Person(),结果会是:

__proto__是一个对象拥有的内置属性(请注意:prototype是函数的内置属性,__proto__是对象的内置属性),是JS内部使用寻找原型链的属性。

new的过程拆分成以下三步:
(1) var p={}; 也就是说,初始化一个对象p
(2) p.__proto__ = Person.prototype;
(3) Person.call(p); 也就是说构造p,也可以称之为初始化p

沿着原型链向上追溯,就是使用__proto__属性来链接到原型(也就是Person.prototype)进行查找相应的方法和属性,上面Author的__proto__的prototype中__proto__指向Person.prototype所以可以调用Person的getName方法。

看看Author的实例化对象就很简单了(注意Author的getBooks方法应该在继承代码后,不然会被Person.prototype覆盖):


2.为了方便写一个extends函数重构代码,则如下:

function extend(subClass, superClass){
var F = function(){};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
}

function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}

function Author(name, books){
Person.call(this, name);
this.books = books;
}

extend(Author, Person);
Author.prototype.getBooks = function(){
return this.books.toString();
}
var a = new Author('hudie', []);
alert(a.getName() + 'write:' + a.getBooks());
与前面一样,它设置了prototype,然后将其constructor重设为恰当的值。作为一个改进,它添加了一个空函数F,并将它创建的一个对象实例插入原型链中。这样做可以避免创建超类的新实例,因为它可能会很庞大,而且有时超类的构造函数有一些副作用,或者会执行一些需要大量计算的任务,比较new person()和new F()便可看出:


显而易见,new F()没有name属性了。

附注:主要参考了JavaScript设计模式 Ross Harmes、Dustin Diaz。


0 0