JavaScript设计模式

JavaScript设计模式

该篇博客参考《JavaScript高级程序设计》及《你不知道的JavaScript(上)》总结,在开发过程中,可以按自己的需求借用设计模式来优化代码。

目录

  • 工厂模式
  • 构造函数模式
  • 原型模式
  • 构造函数模式和原型模式的组合

工厂模式

function createPerson(name,age,job){ //进入工厂
    var o = new Object();//产品初态
    o.name = name;//为产品添加特性
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    }
    return o;//产品出厂
}
var person1 = createPerson("Mike",20,"teacher");
var person2 = createPerson("Alice",22,"doctor");
console.log(person1.constructor);

工厂模式可类比工厂加工,函数外层相当于一个工厂,每次调用createPerson(),都会创建一个对象,并在为对象添加属性和方法后将其返回。工厂模式虽然能解决创建相似对象的问题,但却没有解决对象识别的问题,即无法判断对象的类型。若想了解判断对象的类型,可查看js中判断对象数据类型的方法

构造函数模式

构造函数:函数本身并不是构造函数,然而,当在普通的函数调用前面加上new关键字之后,就会把这个函数调用变成一个“构造函数调用”。

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}
var person1 = new Person("Mike",20,"teacher");
var person2 = new Person("Alice",22,"doctor");
console.log(person1.sayName == person2.sayName);//false
console.log(person1.constructor);
console.log(person2.constructor);
//person1.constructor == person2.constructor == Person(name,age,job){}

Person()函数与java中的构造函数相似,将具有相同属性和方法的实例用一个通用的构造函数实例化,将属性值在用new时通过参数传递,得到有着不同属性值的实例。构造函数模式与工厂模式有几个不同之处,一是没有在函数内部显示地创建对象,二是用this将构造函数的作用域赋给新对象,这种方式会返回一个对象,不需要使用return语句。
在JavaScript中,函数也是对象,在构造函数中写的方法,在每次Person()实例化时都会实例化一个sayName函数,而所有由Person实例化对象的方法都不同,因此console.log(person1.sayName == person2.sayName)为false。
除此之外,在工厂模式中提到工厂模式无法判断对象的类型,而构造函数则可以将它的实例标识为由这种构造函数构造的一种特定的类型。在用构造函数new出来的实例中,看起来person1.constructor === Person意味着person1确实有一个指向Person的属性,但是事实不是这样,实际上,.constructor引用被委托给了Person.prototype,而Person.prototype.constructor默认指向Person。

var o = new Object();
Person.call(o,"Mike",25,"boss");
o.sayName();//"Mike"

原型模式

JavaScript中的对象有一个特殊的prototype内置属性,其实就是对其他对象的引用,这种一层指向下一层的引用就形成了原型链。在进行属性查找时都会查找原型链,直到找到属性或者查找完整条原型链。

function Person(){
    Person.prototype.name = "Mike";
    Person.prototype.age = 22;
    Person.prototype.job = "teacher";
    Person.prototype.sayName = function(){
        alert(this.name);
    }
}
var person1 = new Person();
person1.sayName();//"Mike"
var person2 = new Person();
person2.sayName();//"Mike"
console.log(person1.sayName == person2.sayName);//true
console.log(Person.prototype.constructor == person1.constructor);//true
//Person.prototype.constructor == person1.constructor == Person(name,age,job){}

在上述代码中,直接将属性添加到Person的prototype属性中,在调用构造函数Person()创造的对象中,都有相同的属性及方法。然而,与上面构造函数模式有个最大的区别是:这些对象的属性和方法是所有实例共享的,如输出person1.sayName == person2.sayName为true。

仔细观察可以发现,Person()创建的新对象都是相同,在实际开发中,这样似乎并没有意义。虽然可以通过对象实例访问保存在原型中的值,但是却不能通过对象实例来改变原型中的值。如果在实例对象中定义与原型中同名的属性,则实例对象的属性就会覆盖原型中的同名属性,也可以通过这种方式给各个对象实例设置属于自己的属性值。

function Person(){
    //同上
}
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
console.log(person1.name);//"Greg"
console.log(person2.name);//"Mike"

用一句话来说,当为对象实例添加一个属性时,这个属性会屏蔽原型对象中保存的同名属性。若想重新访问原型中的属性,可用delete操作符完全删除实例属性,再访问该属性时,该属性就为原型对象中的属性值。

delete person1.name;
console.log(person1.name);//"Mike"

原型模式的几个问题:
* 初始化时,所有对象具有相同的属性及方法,且属于所有属性共有。即使可以通过重新设置属性值。若是需要实例化许多对象,使用原型模式,浪费了大量资源。除此之外,如果含有引用类型值的属性,那么一旦更改一个实例对象中的属性,其他所有由该构造函数实例化对象的该属性均改变,这并不是我们想要的。

构造函数模式和原型模式的组合

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby","Court"];
}
Person.prototype = {
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}
var person1 = new Person("Mike",22,"teacher");
var person2 = new Person("Greg",27,"doctor");
person1.friends.push("Van");
console.log(person1.friends);//"Shelby,Court,Van"
console.log(person2.friends);//"Shelby,Court"
console.log(person1.friends === person2.friends);//false
console.log(person2.sayName) === person2.sayName);//true

在上述代码中,Person()为构造函数,设置了由Person实例化的对象所需的所有属性,friends属性值为引用类型(数组),每个实例对象的属性各不相干,即使是引用类型的属性值,改变person1.friends的值,但person2.friends的值不变。而constructor属性和sayName方法由所有实例共享,因此将它们放在原型中定义。这两种模式的组合,最大限度的节省了内存,是现在使用最广泛的模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值