js的几种常见的函数模式

面向对象编程

  • 工厂模式

    原理:
    能够根据接受的参数来构建一个包含所有必要信息的对象,可以无数次的调用这个函数,每次他都会返回一个包含传入参数的相关属性和方法的对象。
    缺点:
    工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题。
    样例:
function creatPerson (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 = creatPerson('zhangsan',20,'打工仔');
var person2 = creatPerson('lisi',21,'老板');
  • 构造函数模式

    原理:
    ECMAScript中的构造函数可用来创建特定类型的的对象;所以我们可以创建自定义的构造函数(object,Array属于原生构造函数),从而定义自定义对象类型的属性和方法。
    样例:
function GreatPerson (name,age,job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = function () {
		alert(this.name)
	};
}
var person1 = new CreatPerson('zhangsan',20,'打工仔');
var person2 = new CreatPerson('lisi',21,'老板');

与工厂函数的区别

  1. 没有显式的创建对象
  2. 直接将属性和方法赋给了this对象
  3. 没有return语句
    使用构造函数注意点
  4. 构造函数始终都应该以一个大写字母开头
  5. 要创建构造函数的实例,必须使用new 操作符
  6. 使用instanceof 操作符可以检测构造函数的类型
  7. 任何函数,只要通过new操作符来调用,那他就可以作为构造函数;而任何函数如果没有使用new操作符来调用,那么跟普通函数也就没什么两样。
    构造函数缺点
    构造函数的每个方法在每个实例上都要创造一遍,因为ECMAScript中的函数是对象,因此每定义一个函数也就是实例化一个对象。
  • 原型模式
    原理
    每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法;换句话说prototype就是通过调用构造函数而创建的那个对象实例的原型对象,使用原型对象的好处是可以让所有对象实例共享他所包含的属性和方法。
    样例
function Person () {}
	Person.prototype.name = 'zhangsan';
	Person.prototype.age = 18;
	Person.prototype.job = 'boss';
	Person.prototype.sayName = function () {
		alert(this.name)
	}
var person1 = new Person()
	person1.sayName();//zhangsan
var person2 = new Person()
	person2.sayName(); // zhangsan
	alert(person1.sayName == person2.sayName); //true

找寻实例的原型对象方法
Object.getProtootypeof(实例);
缺点
虽然可以通过对象实例访问保存在原型中的值,但是不能通过实例对象重写原型中的值。如果我们在实例中添加了一个属性,而且该属性与原型中的属性重名,那么我们会在实例中创建该属性,该属性会屏蔽原型对象中的那个属性
注意
1.使用delete操作符可以完全删除某个实例属性,从而恢复实例访问原型上的某个属性
2.使用hasOwnProperty()方法可以检测一个属性是存在实例中还是原型中。
例如:person1.hasOwnProperty(name)//返回true/false

更简单的原型语法
通过字面量的方法来重写原型对象

function Person () {}
	Person.prototype = {
		name:'zhangsan',
		age:18,
		job:'boss',
		sayName:function () {
			alert(this.name)
		}
}

优点
只要敲一遍Person.prototype;
缺点
constructor属性不再指向Person了,因为每创建一个函数,就会同时创建他的prototype对象,这个对象也会自动获得constructor属性,而我们的这种写法本质上已经完全重写了默认的prototype对象,因此constructor属性也变成了新对象的constructor属性(指向Object),不再指向Person了。
这个问题怎么解决
手动更改constructor的指向

function Person () {}
	Person.prototype = {
		**constructor:Person**,
		name:'zhangsan',
		age:18,
		job:'boss',
		sayName:function () {
			alert(this.name)
		}
}
  • 组合使用构造函数模式和原型模式

    原理
    构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
    优点
    每个实例都将有独自的属性但同时又共享着对方法的引用,最大限度的节省了内存。
    样例
function Person (name,age,job) {
	this.name = name;
	this.age = age;
	this.job = job;
}
	Person.prototype = {
		constructor:Person,
		sayName:function(){
			alert(this.name);
		}
	}
var person1 = new Person('zhangsan',18,'打工仔');
var person2 = new Person('lisi',20,'boss');
console.log(person1.name == person2.name); //false
console.log(person1.sayName == person2.sayName) //true

  • 寄生构造函数模式

原理
创建一个函数,该函数的作用仅用于封装创建对象的代码,然后再返回新创建的对象。
样例

function Person (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 friend = new Person('zhangsan',18,'boss');
friend.sayName();//zhangsan

解决大家疑惑的一段话:
这个模式其实和工厂模式是一样的,构造函数在不返回值的情况下,会默认返回新对象实例。而通过在构造函数的末尾添加return语句,可以重写构造函数时返回的值;

用途:
这个模式可以在特殊的情况下为对象创建构造函数;
假设
我们想创建一种具有额外方法的特殊数组,由于不能直接修改Array构造函数,因此可以使用这种模式

function SpecialArray () {
	//创建数组
	var values = new Array();
	//添加值 
	values.push.apply(value,arguments);
	//添加方法
	values.toPipedString = function () {
		return this.join("|");
	}
	return values;
}
var colors = new SpecialArray('red','green','blue');
alert(colors.toPipedString());//"red|green|blue"

说明
返回的对象与构造函数或者构造函数的原型属性之间没有关系;也就是说构造函数返回的对象与在构造函数外部创建的对象没有什么不同,为此,不能依赖instanceof操作符来确定对象类型。由于有以上问题所以建议在可以使用其他模式的情况下,不要使用这用模式(有没有一种想打人的冲动~- ~)

———————————————————————————————————
接下来说继承,大家可能会觉得和上面有所重复,其实呢,真的是有点重复的意思。上面是面向对象的几种编程模式,其实就是用到了继承的东西。 蛤~~ 忒 ,是哪个鸟人在这里胡说八道!!各位看官放心哈,后面都是好东西(有重复的也不承认,你们不看,我不就白写了吗)。

继承

  • 概念:
    ECMAScript只支持实现继承,而其实现继承主要依靠原型链实现(还有一种继承叫做接口继承)
  • 原型链基本思想:
    利用原型让一个引用类型继承另一个引用类型的属性和方法
继承方法
  • 借用构造函数
    原理
    即在子类型构造函数内部调用[超类型构造函数](我理解为:父类型构造函数)
    样例
function SuperType () {
	this.color = ['red','green'];
}
function SubType () {
	//继承SuperType
	SuperType.call(this);
}
var instance1 = new SubType();
	instance1.color.push('white');
	alert(instance1.color)//'red,green,white'
  • 组合继承(伪经典继承)
    原理
    使用原型链实现对原型属性和方法继承,而通过借用构造函数实现对实例属性继承
    优点
    既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有他自己的的属性。
    不足
    无论在什么情况下,都会调用两次超类型构造函数 :
    1.创建子类型原型的时候,
    2.在子类型构造函数的内部
    样例
function SuperType (name) {
	this.name = name;
	this.color = ['red','green'];
}
SuperType.protoType.sayName = function () {
	alert(this.name);
}
function SubType (name,age) {
	//继承属性
	SuperType.call(this,name);
	this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
	alert(this.age);
}
//实例
var instance1 = new SubType('zhangsan',18);
instance1.sayName();//zhangsan
instance1.sayAge();//18
  • 原型式继承
    原理:
    借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
    先创建一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的新实例。从本质上讲对传入其中的对象执行一次浅复制。
    样例
function object (o) {
function F () {};
	F.prototype = o;
	return new F();
}
var person = {
	name:'zhangsan',
	color:['red','green']
}
var another = object(person);
	another.color.push('blue');
	alert (another.color);//'red,green,blue'

ECMAScript5通过新增Object.create()方法规范了原型式继承;
这种方法接收两个参数:

  1. 用作新对象原型的对象;
  2. 为新对象定义额外属性的对象(可选);
    样例
var person = {
	name:'zhangsan',
	color:['red','green']
}
var another = Object.create(person,{age:18});
another.color.push('blue');
alert (another.color);//'red,green,blue'
  • 寄生式继承
    原理:
    创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后在像真的是它做了所有工作一样返回对象。
    样例
function createAnother (original) {
	var clone = Object.create(original);//调用函数创建一个新对象
	clone.sayHi = function() {  //以某种方式增强这个对象,或者说给他增加新的方法和属性
		alert('hi');
	}
	return clone;
}
//看一下实例;
var person = {
	name = 'zhangsan',
	age = 18
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

缺点
使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点个构造函数相似,这个缺点将会在下个继承方式中弥补

  • 寄生组合式继承
    原理
    不必为了指定子类型的原型而调用超类型的构造函数,我们所需的无非就是超类型的一个副本而已;本质上,就是使用寄生式继承来继承超类型的原型,然后将结果指定给子类型的原型。(在一个方法体内声明一个空对象继承父对象的原型,将该对象的constructor属性指向子元素,然后将其赋给子对象的原型)
    样例
			//继承原型(英语不好的同学,我给你翻译了哈!)
function inheritPrototype (subType,superType) {
	var prototype = Object.create(superType);//创建对象
		prototype.constructor = subType;//增强对象
		subType.prototype = prototype;//指定对象
}



//看个我怎么用吧

function SuperType (name) {
	this.name = name;
}
SuperType.prototype.sayName = function () {
	alert (this.name)
} 

function SubType (age,name) {
	this.age = age;
	SuperType.call(this,name); //使用方法继承SuperType实例属性(又叫拷贝继承)
}
inheritPrototype (subType,SuperType);//继承SuperType原型
var instance = new SubType('zhangsan',18);
instance.sayName();//zhnagsan

面向对象的程序设计介绍完毕。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值