您的位置:首页 > Web前端 > JavaScript

JS原型--初理解

2016-04-08 21:09 232 查看
在JavaScript中, 原型的理解关乎到继承机制的理解,而继承是一门OO语言最重要的一部分。

所以,理解原型的重要性不言而喻。

幸好,原型的初步理解还是相对比较容易的,只需要在脑海里建立好正确的思路。

理解原型首先要理解三个基本概念:原型对象、构造函数、实例对象。

构造函数:在JavaScript中任何一个用关键字function定义的函数都有可能作为构造函数来使用。这也就是说,在JavaScript中,没有什么特别的语法来定义哪些函数是构造函数,只有在一个函数前面用上new关键字,那么这个函数就成了构造函数。

function funname(){
//这里定义函数体。
}
//上面是普普通通,用函数声明语句声明的一个函数。然后....
var fun=new funname();


是的,funname()成了一个构造函数了。

实例对象:实例对象本质上是一个对象,就像你是人,当然你也是男人或者女人一样。实例对象是由new关键字后面再加构造函数创造出来的对象。

var fun=new funname();
//fun存储的就是一个实例对象。


原型对象:原型对象本质上也是一个对象,就像实例对象一样,只是功能和作用有所不同的对象罢了。

好!原型的起点,我觉得应该从构造函数开始讲。

在JavaScript中一旦声明了一个函数,该函数就会自动获得一个属性名为prototype的属性(为什么函数有属性?因为函数是对象啊),这个属性里存放的是一个指针,该指针指向了函数的原型对象。

这也就是说,在声明了一个函数,JavaScript不仅仅会只给你创建了一个函数,而且还给这个函数创建了一个和该函数有关联的对象,而这个对象就是原型对象。

这就是典型的买一送一。

现在我们知道构造函数有一个属性prototype可以指向它的原型对象。

function funame(){
//这里定义函数体。
}

funame.prototype
//是的,通过这个式子就可以访问到原型对象。
//不要问我原型对象的名字是什么,因为我也不知道,原型对象就像一个构造函数的副产物。
//也不要问我原型对象什么时候创建的,不是说了吗?和函数一同创建的,也就是说有函数的地方就有一个和该函数相关的原型对象。


上面说过,函数创建出来后天生就带一个prototype属性指向它的原型对象。

而原型对象也不例外,随着函数被创建后就天生带有一个属性名为constructor的属性,该属性值也是一个指针,指向的是和它一起被创建的构造函数。

function funame(){
//这里定义函数体。
}

funame.prototype
//这是访问原型对象。

funame.prototype.constructor
//所以很自然的,这是访问构造函数。


到了现在,我们要在脑海里构建一个思路:一个构造函数,一个原型对象,他们各自拥有一个属性互相指向对方。

最后是实例对象,前面说过,所谓实例对象就是用new和构造函数创建出来的,当它被创建出来后,天生又自带了一个[[prototype]]的内部属性。这个内部属性通常情况下是不能访问的。该内部属性存储的也是一个指针,这个指针指向的就是,和创建它的构造函数一起被创建的原型对象



画的很是简陋!

讲了这么多,那原型是用来干嘛的呢?它最大的用途应该是实现继承。



一图胜万语。

下面列几个关键知识点:

实例对象可以访问到它所指向的原型对象中所有的属性和方法。也就是说:实例对象1可以访问到原型对象1、原型对象2、原型对象3、原型对象4中所有的方法和属性。

构造函数中的prototype属性是可以被赋值改变。
funame.prototype=new gouzaofun();
这也是原型链形成的基础。

图中有些构造函数和原型对象之间不再是相互指向的关系是因为,原本相互指向的原型对象被赋值改变了。

下面是一些代码实例:

;(function(abc){
//定义一个自启动函数。
var abcd=function(){

//自定义一个构造函数。
function Gouzao(){
//在自定义一个构造函数时,(其实自定义所有函数都一样),函数就会根据特定的规则为自己创建一个prototype属性,
// 这个属性指向了函数的原型对象。
//关于原型对象:在默认情况下,在自定义了一个函数之后,该函数的原型对象默认只会取得一个constructor属性
// (该属性指向构造函数,不过该属性很容易就会被修改),剩下了其他方法都是从Object继承来的
this.a = 211;
this.b=function(){
alert('sd');
};
}

//在构造函数的原型对象中添加属性或方法。
Gouzao.prototype={
//  注意:如果使用这种方法声明原型对象中的属性,相对于重新定义了Gouzao.prototype中引用的原型对象,那么也就是说,
//  在创建一个函数时,原本有一个指向的原型对象就会被抛弃了,而且重新定义的原型对象的constructor属性
// 并不是指向Gouzao函数,而是指向了Object构造函数。
//  注意:对象声明是  属性 :属性值,而不是,属性 = 属性值。
constructor : Gouzao,
c : "20",
d : function(){
alert('sdsdsd');
}
};

var o = new Gouzao();
//当调用构造函数创建一个新实例的时候,该实例内部(其实就是对象内部)将包含一个
// 指针[[prototype]](不过这个指针是一个内部属性),它指向原型对象。通常情况下这个属性是不
// 可访问的,除非浏览器商专门定义方法来访问该指针,事实上真的有这种方法,下面有讲到。

// 关于这个内部属性还有一点要注意,就是这个属性表示的是原型对象和实例对象之间的关系,而不是与构造函数之间。并且实际
// 上实例对象和构造函数只存在单方面的联系:就是构造函数创建了实例对象。就是说实例对象内没有任何直接的属性和构造函数有关系。
//               但是考虑以下代码:
var o_gouzaohanshu = o.constructor;
document.writeln(o_gouzaohanshu);

//运行后发现返回的是o构造函数,这是为什么?是因为继承,在实例对象中式可以直接读取原型对象中的属性的,而原型对象中就有指向构造
//               函数的属性,所以才有这种结果。

var yuanxingguanxi =   Gouzao.prototype.isPrototypeOf(o);//true就是有关系,false就是木有关系。
document.writeln(yuanxingguanxi);
// 不过,虽然无法访问到该属性,但是可以通过 isPrototypeOf()来确定原型对象和实例之间是否存在那种关系。
// 也就是说这个方法其实测的是:是否调用该方法的原型对象和传入该方法的对象是否存在内部属性上的联系,也可以说是继承关系。

var huodeneubushuxingdeyinyong = Object.getPrototypeOf(o).c;
document.writeln(huodeneubushuxingdeyinyong) ;
//这是新增加的一个方法,目的就是为了获取对象的内部属性[[prototype]]的引用。所以说,上面一直说无法获取,而现在竟然可以获取了,我去!!

var o1= new Gouzao();
//               alert(Gouzao.prototype.constructor);
//          构造函数自动获得一个prototype属性,该属性指向构造函数的原型对象。
//           所有的原型对象都会自动获得一个constructor属性,该属性指向一个包含prototype属性的函数的指针。

//               Object.nihao=80;
//               对象是无法直接访问到它的原型对象,但是构造函数可以访问到所指向的原型对象,所以可以间接的访问。
//               这是因为对象包含的指向其原型对象的属性是一个内部属性,常规情况下是不可访问的。
//               o.prototype=o1;
//               o1.nihao="007";

};
window.jquery=window.$=abcd;
})(window);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: