JS构造对象模式、继承方式、原型链

构造对象模式

工厂模式

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(“Greg”, 27, “Doctor”);

优点:解决了创建多个相似对象,重写代码的问题
缺点:没有解决对象识别问题,及函数重用问题

构造函数模式

function Person(name, age, job){
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = function(){
		alert(this.name);
	};
}
var person1 = new Person(“Greg”, 27, “Doctor”);

特点:没有显式地创建对象、直接将属性和方法赋给了this对象、没有return语句
要创建新实例必须使用new操作符,这种方式下会经历4个步骤:
创建一个新对象
将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
执行构造函数中的代码
返回新对象
每个实例都有constructor属性:

person1.constructor == Person 	// true

还可以实例检测:

person1 instanceof Person		// true

优点:解决了工厂模式未解决对象识别问题
缺点:仍然没有解决函数重用问题

原型模式

我们创建的每个函数都有一个prototype属性,是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法

function Person(){}
Person.prototype.name = “Nicholas”;
Person.prototype.age = 29;
Person.prototype.sayName = function(){
	alert(this.name);
}

var person1 = new Person();
person1.sayName();		// “Nicholas”

优点:解决了函数重用问题
缺点:省略了为构造函数传递初始化参数这一环节(纯原型模式,构造函数是空的)。 对于包含引用类型值的属性来说,共享存在问题

1.理解原型对象

在默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性是一个指向prototype属性所在函数的指针

当调用构造函数创建一个实例后,该实例内部将包含一个指针[[prototype]],指向构造函数的原型对象,在某些浏览器中可以通过实例的__proto__属性访问到这一指针
在这里插入图片描述

如果[[Prototype]]指向调用isPrototypeOf()方法的对象,那么这个方法就返回true:

Person.prototype.isPrototypeOf(person1);	// true
// Object.getPrototypeOf(), 可以返回[[Prototype]]的值,例:
Object.getPrototypeOf(person1) == Person.prototype; // true

当代码从对象中读取属性时,都会由对象实例本身开始,然后依次沿着原型链向上搜索

虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值,如果尝试重写,将会创建一个同名的属性,屏蔽掉原型中的那个属性

使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,只有给定属性是存在于对象实例中是,才会返回true

2.原型与in操作符

in 操作符会在通过对象能访问到给定属性时返回true,无论该属性存在于实例中还是原型中,例

"name" in person1		// true

for - in 循环时:返回的是所有能够通过对象访问的、可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的属性(包括不可枚举的)

Object.keys(): 接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组

*组合使用构造函数模式和原型模式

这种构造函数与原型混成的模式,是目前中使用最广泛、认同度最高的一种创建自定义类型的方法。
构造函数用于定义实例属性,而原型模式用于定义方法和共享的属性

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);
	}
}

动态原型模式

它把所有的信息都封装在了构造函数中,而不是构造函数和原型初始化分开写

function Person(name, age, job){
	this.name = name;
	this.age = age;
	this.job = job;
	
	if(typeof this.sayName != "function"){
		Person.prototype.sayName = function(){
		alert(this.name);
		}
	}
}

寄生构造函数模式

除了使用 new操作符并把使用的包装函数叫做构造函数之外,这个模式跟 工厂模式其实是一模一样的
很少使用这种构造模式

function SpecialArray(){
	var values = new Array();
	values.push.apply(values, arguments);
	values.toPipedString = function(){
		return this.join(|);
	};
	return values;
}
var colors = new SpecialArray(“red”,”blue”,”green”)

稳妥构造函数模式

稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用this;二是不使用new操作符调用构造函数

function Person(name, age, job){
	var o = new Object();
	// 可以在这里定义私有变量和函数
	// 添加方法
	o.sayName = function(){
		alert(name);
	}
	// 返回对象
	return o;
	}

继承

原型链

ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法
让原型对象等于另一个类型的实例,其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
即: SubType.prototype = new SuperType();
在这里插入图片描述

注:上图中的SubType Prototype对象实际上是SuperType类型的实例
并且instance.constructor 指向SuperType(),因为原来的SubType.prototype被替换了

1.确定原型和实例的关系

第一种方式:使用instanceof操作符,只要用这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回true,例:

instance instanceof Object 		// true

第二种方式:使用isPrototypeOf()方法,同样,只要是原型链中出现过的原型,都返回true

Object.prototype.isPrototypeOf(instance)	// true

原型链的缺点:当原型包含引用类型的值时,引用类型的值会被所有实例共享(可以写); 在创建子类型的实例时,不能向超类型的构造函数中传递参数

实践中很少会单独使用原型链
借用构造函数
有时也叫伪造对象或经典继承
基本思想即在子类型构造函数的内部调用超类型构造函数

优点:可以在子类型构造函数中向超类型构造函数传递参数
缺点:纯借用构造函数无法解决函数复用问题(因为没有用到原型链)

*组合继承

也叫做伪经典继承,指的是将原型链和借用构造函数的技术组合到一块
思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

function SuperType(name){
	this.name = name;
	this.colors = [“red”,”blue”, “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);
};

组合继承是JS中最常用的继承模式
缺点:会调用两次基类型的构造函数,使用原型对象中包含重复的属性

原型式继承

想法是借助已有的对象创建新对象

function object(o){
	function F(){}
	F.prototype = o;
	return new F();
}

返回了一个对象实例,而这个实例是继承自o的
ECMAScript5通过新增Object.create()方法规范化了原型式继承,参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象
第二个参数的每个属性都是通过自己的描述符定义的,例:

var anotherPerson = Object.create(person, {
	name:{
		value :”Greg”
	}
});

寄生式继承

寄生式继承的思路与寄生构造函数和工厂模式类型,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再返回对象

function createAnother(original){
	var clone = object(original);
	clone.sayHi = function(){
		alert(“hi”);
	};
	return clone;
}

首先是直接生成了一个实例,然后又给这个实例添加了一些额外的属性增强对象
同样,额外添加的函数,也得不到复用
寄生组合式继承
通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已

function inheritPrototype(subType, superType){
	var prototype = object(superType.prototype);	创建对象
	prototype.construct = subType;					增强对象
	subType.prototype = prototype;					指定对象
}

这样,使得超类型的构造函数只调用一次,不会在原型对象中创建重复的属性,解决了组合继承的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tanleiDD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值