原型、原型链-持续更新

来源:互联网 发布:大数据时代是什么意思 编辑:程序博客网 时间:2024/05/17 23:21

循序渐进的概念,稍安勿躁:

引用类型:它是一种数据结构,用来将数据和功能组织在一起。何为数据结构,数据结构是计算机存储,组织数据的方式,它是一个具有一种或者多种特定关系的数据元素的集合。也称为对象定义,对象定义就是描述一类对象所具有的属性和方法。因此本人冒下定义:
引用类型=对象定义:一组属性和方法的集合。
对象:某个特定引用类型的实例,何为实例,就是一组具有实际属性值和方法内容的集合。

例如:    Car为汽车,是一个引用类型,他具有名字、品牌、制造商、按使用的分类等属性,也有前进,倒车,刹车等操作方法。    jeep牧马人则是一个对象,他有名字:牧马人,品牌为jeep,制造商为克莱斯勒,属于纯正越野车,当然具有它独有的前进,倒车,刹车等方法。

引用类型是抽象的模型,而对象则是具体的事物

引用类型又根据自身具有的不同的属性和方法进行分类:Object类型、Array类型、Date类型、
RegExp类型Function类型、Boolean类型、Number类型、String类型。

理清了引用类型与对象的定义,那怎么样创建对象呢,在js中利用new操作符和一个构造函数来创建。如:

var obj = new Object();//Object为构造函数。

构造函数为何物?首先它是一组代码的集合,为了完成特定的任务。任务?为对象实例创建属性和方法。
为何要使用new关键字呢,new在此不只是三个字母,它代表的是一组特定操作的集合,但是它执行了那些操作呢:

1、创建了一个新对象,相当于使用字面量的方式{};2、将构造函数的原型赋值给对象的_proto_属性:obj._proto_ = Object.prototype,通过这一步,对象继承了构造函数的原型上的属性和方法3、将构造函数的作用于传给新对象:Object.call(this);4、执行构造函数,这时候通过构造函数创建的属性和方法就属于obj了5、返回新对象

这时候,构造函数,原型对象,对象之间就存在了如下关系:

这里写图片描述

当创建的obj对象又是一个对象的原型的时候:

这里写图片描述

这里String()的原型为String Prototype,它本身又是Object的实例,所以其中含有一个proto属性,指向其原型,也就是Object的原型对象。其余的原生类型,诸如Function,RegExp等,所有函数的默认原型都是Object的实例。

对于函数的实例化,相对复杂一些

函数的三种声明方式:

1var fn = new Function("alert(this)");2var fn = function(){alert(this)};3function fn(){alert(this)}

这三种方式都可以创建函数,但是他们是有区别的。
这三种方法创建的函数都是【Function引用类型】的实例,因此他们的constructor属性都指向Function(){},他们的_proto_属性也都指向Function的原型对象。然而,所有函数在创建你的时候都会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象,原型对象也会获取一个constructor属性,指向函数。
这里写图片描述
Object Prototype是所有的实例所共享的属性和方法的集合。
1、【原型对象】就是某一类特定的引用类型所共同具有的属性和方法的集合,不同的【原型对象】拥有不同的属性和方法,因此使用不同的原型的【实例对象】就会拥有不同的属性和方法。
2、原型链继承的是堆内存中共享的属性和方法,并不是为每个对象创建相同的属性和方法。
3、通过在对象上设置固定的属性_proto_用于存储原型的指针,来实现相互间的关系,原型链其实就是一组_proto_的链接,在进行原型链查找的时候也是通过这个来完成的。
4、构造函数不是制造对象的函数,它是一组代码,只是用来为对象修改其属性和方法。
5、原型对象是被动态创建的吗?是先创建了函数还是先创建了原型对象?是按照什么样的规则创建的?
6、原型对象被创建时只有一个属性,constructor,这个属性也是被【实例对象】共享的,因此每个实例对象都拥有的constructor属性的值都相同,都指向其构造函数。
7、继承时为什么要通过原型链,为什么不能把直接把一个构造函数的_proto_的值与另一个构造函数的原型链接起来,或者其他,如:

function A(){};function B(){};1、B._proto_ = new A();2、B._proto_ = a.prototype;//这两种方式实现的,可以通过B访问到的,是通过\_proto_链查找的A的原型中的东西。而B的实例,则未有这种链接,所以未实现对A的继承。//根据查找顺序,下面应该是通过实例对象的_proto_查找,也就是构造函数的原型,因此要将原型对象与A建立联系。1、B.prototype._proto_ = A.prototype;//可以达到效果2、B.prototype._proto_ = new A();//这种通过将A的实例赋值的方式,会不会访问到A中的实例属性呢,实验证明,会,它现在A实例中查找,然后再去A的原型中查找。所以,想要完全继承A,那就应该采用new A()也就是实例赋值的方式。//既然想要操作的是B的原型与A建立联系,那为什么不直接改变呢,看下文:3、B.prototype=A.prototype;//也可以达到继承A原型的效果4、B.prototype=new A();//可以达到//但是他们有什么异同呢1和3中,因为都是指针传递,说白了,就是同一块空间。3中如果改变了B.prototype,那A的原型也跟着更改了,失去了独立性,可以舍弃这种方式。剩余三种:1、B.prototype._proto_ = A.prototype;2、B.prototype._proto_ = new A();4、B.prototype=new A();//他们都能达到继承的效果,只是效果不一样,如果B的原型本来就一些属性和方法,又不想被覆盖,那用前两种。前两者中不想继承A的实例属性就用1,想要继承A的实例属性,那就用2.书中介绍的继承方式几本采用第四种,因为是新建关系,所以4简洁明了。

查找顺序:1、实例对象中查找 2、构造函数的原型中找3、原型链往上找
记住,这些地方都是指针

综上所述,构造函数构造出具有特定属性和方法的对象,这些对象因为拥有存储着原型指针的_proto_属性,因此得以继承了原型所具有的属性和方法,而在使用的时候便使用就近查找的方法逐层查找。

    var str_1 = new String();    var str_2 = new String();    str_1._proto_=== str_2._proto_;//true
0 0
原创粉丝点击