javascript 原型模式的工作原理 到 对象模式的探寻(上)

来源:互联网 发布:北京集佳待遇知乎 编辑:程序博客网 时间:2024/05/25 12:20

谈到Javascript面向对象,有几个非常重要的知识点:

  • 创建对象的模式
  • 原型与原型链
  • 继承方式

在Javascript中创建单个对象可以通过很简单的如下两种方式

//Object 实例化var person = new Object();person.name = "Nick";person.sayName = function(){    alert(this.name);};//对象字面量var persion = {    name: "Nick",    sayName: function(){        alert(this.name);    }};

但是这样的缺点就是

  • 创建多个相似对象时,产生大量重复代码
  • 对象识别问题,无法知道一个对象的类型

为了解决这些问题,在javascript的发展过程中,各位前辈大牛使用了以下模式:

  1. 工厂模式
  2. 构造函数模式
  3. 原型模式
  4. 组合模式(构造函数+原型模式)
  5. 其他模式
/**工厂模式**///通过函数工厂来创建//缺点:没有解决对象识别的问题。function createPerson(name){    var o = new Object();    o.name = name;    o.sayName = function(){        alert(this.name);    };    return o;}var personInstance = createPerson("Nick");/**构造函数模式**///ECMAScript 中的构造函数可以用来创建特殊类型的对象。//缺点:对象中的方法无法共享,每个方法在每个实例中都重新创建了一遍。funtion Person(name){    this.name = name;    this.sayName = function(){        alert(this.name);    };}var personInstance = new Person("Nick");/****在这里js引擎会执行以下步骤: 1. 创建一个对象 O 2. 将构造函数的作用域赋给 O ,即this指向了 O 3. 执行构造函数的代码,即为 O 添加了属性 4. return 新对象通过构造函数创建的对象,可以通过 constructor属性 或者 instanceof 操作符来识别对象类型。****/

原型模式
每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象即原型对象,里面包含了该类型所有instance共享的属性和方法。

function Person(){}//在这里我们对prototype完全重写了,所以它的constructor默认不会指向Person函数,需要我们重新加上。Person.prototype = {    constructor: Person,    name : "Nick",    sayName : function(){        alert(this.name);    }};var personInstance = new Person();//这里创建的实例 personInstance 并没有对prototype对象中的任何属性进行copy,而是在自己这边添加了一个指针[prototype]访问prototype对象。

这里写图片描述
需要注意的是 原型的重写一定要在 对象实例化之前,否则会出错。因为实例的指针指向的原型已经被重写了,所有自定义属性都为空。
这里写图片描述
原型模式的问题
原型模式在实现创建多个相似对象和识别对象的基础上,还提供了共享的功能,节省了大量内存。但是正是共享导致了一些问题,前面有说过所有实例共享prototype对象中的属性。那么当实例化的 instance 需要独享的属性呢? 当然,我们可以通过在实例中重写来覆盖prototype中的属性来实现。但是对于引用类型来说就有一定的问题了。

function Person(){}Person.prototype = {    constructor: Person,    friends: ["s","f"]}var person1 = new Person();var person2 = new Person();person1.friends.push("gg");console.log(person1.friends);console.log(person2.friends);person1.friends = ["1","2"];console.log(person1.friends);console.log(person2.friends);/**[s,f,gg][s,f,gg][1,2][s,f,gg]**/

从上面的代码我们可以得知,如果对引用类型的属性进行操作的时候,也必须进行完全重写才能实现各自有各自的属性。否则将直接修改到prototype上的属性。

最终我们通过组合构造函数模式和原型模式得到的模式,是目前使用最广泛的一种自定义类型的方式。

function Person(name,friends){    this.name = "Nick";    this.friends = ["s","f"];}Person.prototype = {    constructor : Person,    sayName : function(){        console.log(this.name);    }}

其他还有 如 动态原型模式、寄生构造函数模式、稳妥构造函数模式等,这里不做一一介绍。

0 0
原创粉丝点击