Javascirpt--原型(prototype)模式的产生背景--03

之前的文章中已经阐述过,js中对象是属性的集合,属性值可以是值类型,也可以是引用类型,比如基本值,函数,或者对象。

创建对象

//创建自定义对象 **传统写法**
var person = new Object();
	person.name = "Nicholas";
	person.age = 29;
	person.job = "Software Engineer";
	person.sayName = function(){
	alert(this.name);
};

//推荐写法,通过**字面量创建**
var person = {
	name: "Nicholas",
	age: 29,
	job: "Software Engineer",
		sayName: function(){
	alert(this.name);
	}
};

工厂模式

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("Nicholas", 29, "Software Engineer");
var person2 = 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("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

构造函数模式与工厂模式的不同:
1.没有显式的创建对象
2.直接将属性和方法赋给this对象
3.没有return语句

要创建 Person 的新实例,必须使用 new 操作符。这种方式调用构造函数实际上会经历以下 4
个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。

构造函数可以当做是普通函数使用,普通函数(通过new关键字)也可以当做构造函数使用

// 当作构造函数使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"

// 作为普通函数调用
Person("Greg", 27, "Doctor"); // 添加到 window
window.sayName(); //"Greg"

// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"

当在**全局作用域**中调用一个函数时, this 对象总是指向 Global 对象(在
浏览器中就是 window 对象)。因此,在调用完函数之后,可以通过 window 对象来调用 sayName()方法,并且还返回了"Greg"。

构造函数模式缺点
每个方法都要在每个实例上重新创建一遍,重复创建实现同一个功能的Function的实例实在没有必要
上面创建的person1和person2中,都有一个sayName()的方法,但实际上person1和person2下的sayName属性被赋予的不是同一个方法,即这两个方法不是同一个Function的实例。原因是js中方法也是对象,创建person实例的时候,会为sayName new一个Function的实例。

person1.sayName==person2.sayName;//false

解决构造函数共享函数的问题
为了解决这个问题,可以将sayName方法转移到构造函数外部,定义在全局作用域,在构造函数内部将为sayName属性赋值为指向全局作用雨中SayName方法的指针,这样不同的person实例就可以共享同一个方法。

function Person(name, age, job){
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = sayName;//sayName属性赋值为:指向全局作用域中sayName方法的指针
}
//定义全局作用域中的sayName方法
function sayName(){
	alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software
var person2 = new Person("Greg", 27, "Doctor");
person1.sayName==person2.sayName;//true

这种方式解决了不同实例共享函数的问题,但是又引发了新的问题:
1.在全局作用域中定义的这些函数只能由某一个对象调用,这与全局作用域名不副实
2.如果对象需要定义更多的方法,就需要在全局作用域中定义更多的函数,自定义的引用类型就没有丝毫封装性可言

基于以上问题,javascript中提供了原型模式可以解决,下一章来介绍原型模型

猜你喜欢

转载自blog.csdn.net/weixin_40719943/article/details/106577367