面想对象编程
-
工厂模式
原理:
能够根据接受的参数来构建一个包含所有必要信息的对象,可以无数次的调用这个函数,每次他都会返回一个包含传入参数的相关属性和方法的对象。
缺点:
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题。
样例:
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,'老板');
与工厂函数的区别:
- 没有显式的创建对象
- 直接将属性和方法赋给了this对象
- 没有return语句
使用构造函数注意点: - 构造函数始终都应该以一个大写字母开头
- 要创建构造函数的实例,必须使用new 操作符
- 使用instanceof 操作符可以检测构造函数的类型
- 任何函数,只要通过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()方法规范了原型式继承;
这种方法接收两个参数:
- 用作新对象原型的对象;
- 为新对象定义额外属性的对象(可选);
样例:
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
面向对象的程序设计介绍完毕。
转载:https://blog.csdn.net/weixin_43513495/article/details/101315667