【js基础】javascript中的原型总结

来源:互联网 发布:沈阳开盘数据恢复 编辑:程序博客网 时间:2024/06/06 03:01

前言:学习js有段时间,感觉写代码时,很少用到。看懂了过段时间又忘记了。网上关于js原型链和闭包资料满天飞,可见他们的重要性吧。暑假在家看完javascrit高级程序设计第六章,现在做一个笔记,不然估计过几天又忘记了。希望熟悉之后,以后有意识的用一下这些特性。我对于原型的理解都是基于c语言指针和内存知识类比的,可以作为参考,但不保证正确。

这篇博客new出来的对象全部称为对象实例 用于创建对象实例的函数全部称为构造函数 构造函数的原型称为原型对象。

不像java,js中没有类这样显示的定义。所以对象实例的创建都通过函数的封装。看下面栗子:

创建对象实例方法一:工厂模式

function Person(name,age,sex){    var o=new Object();    o.name=name;    o.age=age;    o.sex=sex;    o.sayContent=function(){        alert("hello world");    };    return o;}var person1=Person("Tom",18,"男");

这种模式虽然解决了创建多个相似对象问题,却没有解决对象类型问题。主要是这样创建的对象示例无法用js中的对象类型检测手段检测。即

alert(typeof person1);//objectalert(person1 instanceof Person);//falsealert(person1.constructor==Person);//false

而且工厂模式创建对象,很明显是通过函数的显现调用手段进行的。过程如下,在执行var person1=Person(“Tom”,18,”男”);语句时,调用Peson函数,执行Person函数时,先创建一块和Object对象所占内存一样大的内存,然后变量o执行创建这一块内存的地址。o即为这一块内存的地址。然后在这块内存中加入name,age,sex等对象属性值。然后返回对象o的值给person1,即person1的值为创建的那一块内存的地址。最后销毁o的值。但分配的内存不会被销毁。只有当js的垃圾回收机制检测到这一块内存没有用时才会自动释放。

创建对象实例方法二:构造函数模式

构造函数模式克服工厂模式中不能检测创建对象实例的类型问题。

function Person(name,age,sex){    this.name=name;    this.age=age;    this.sex=sex;    this.sayContent=function(){        alert("hello world");    };}var person2=new Person("Jerry",18,"女");var person3=new Person("Nary",15,"女");alert(person2 instanceof Person);//truealert(person2.constructor==Person);//true

构造函数在创建一个对象实例时,先创建一块和构造函数 一样大的内存。然后再调用构造函数,在此过程中this指向该构造函数的实例。即this指向新对象实例。然后执行构造函数里面的代码。其中通过this来向创建的内存中加入新的属性。
但构造函数模式也有缺点:如上例每个对象实例创建时都要分配一块内存,这是无可厚非的,但是在创建每一个对象实例的过程中会调用构造函数Person,在执行构造函数里面的代码

this.sayContent=function(){        alert("hello world");    };等价于this.sayContent= new Function(        alert("hello world");    );

时,每一个对象实例在添加sayConntent属性时又要再分配一块小内存,但是这些内存中的内容却一样。可以验证:

alert(person2.sayContent===person3.sayContent);//false

这样很浪费资源。

所以我们可以这样做:

function Person(name,age,sex){    this.name=name;    this.age=age;    this.sex=sex;    this.sayContent=SayContent;}function SayConttent(){    alert("hello world");}var person2=new Person("Jerry",18,"女");var person3=new Person("Nary",15,"女");alert(person2 instanceof Person);//truealert(person2.constructor==Person);//true

这样的话,每个对象实例的属性sayContent都执行函数function sayContent的地址。可以验证

alert(person2.sayContent===person3.sayContent);//true

但是这样做又破坏我们封装构造函数来创建对象实例的初衷。
所以原型模式登场。。。原型出来啦。。。。。。。。

创建对象实例方法三:原型模式

function Person(){}Person.prototype.age=18;Person.prototype.sex="男";Person.prototype.saycontent=function(){    alert("Hello World");};var person2=new Person();var person3=new Person();

先上原理图:
这里写图片描述

解释:每当我们创建一个构造函数时,这个构造函数都会默认取得一个新的属性prototype,这个属性本质上是一个指针,指向函数的原型对象。。默认状态下,每个原型对象都取得一个默认属性constructor,其本质上也是一个指针,constructor指向prototype属性所在的函数(不一定指向创建的函数,当创建的函数的prototype属性被重写,就不指向创建的函数)。而由构造函数创建的对象实例都会默认取得一个 ___proto___ 属性,他本质上也是一个指针,他指向构造函数的原型对象,不指向构造函数。

function Person(name,age,sex){    this.name=name;    this.age=age;    this.sex=sex;}Person.prototype.sayContent=function(){    alert("hello world");}var person2=new Person("Jerry",18,"女");var person3=new Person("Nary",15,"女");alert(person2.sayContent==person3.sayContent);//true

多个对象公用一个属性sayContent。上面其实为构造函数模式与原型模式混搭。这种方案在创建js对象实例时用得最多。