这是我对PC站构建过程中面对多个类似功能模块情况下的思考与探索
首先,我先介绍一下比较常用的创建对象的三种方法:
1.构造函数模式
先看一段代码
function person(name,age){
this.name = name;
this.age = age;
this.say = function(){
alert(this.name)
}
}
var person1 = new person('小明',18);
var person2 = new person('小红',24);
person1.say(); // 浏览器弹出‘小明’
person1.say(); // 浏览器弹出‘小红’
如果你对this还心存疑虑,请移步阮一峰博客:
http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html
我们只说一下在new的过程中发生了什么
1.创建一个新的对象;
2.建构造函数的作用域赋给新对象(因此this指向了这个新对象);
3.执行构造函数中的代码(为这个新对象添加属性);
4.返回新对象;
通过new的过程,我们发现案例暴露出一个问题,那就是person1和person2使用的方法虽然是一模一样的,但是在new的过程中,person构造函数都为新对象创建了一个say()方法,这势必造成引擎不但要多读一遍代码,内存还要多浪费地方存储,相当于:
你是一个包工头,你手底下有两名工人,两名工人都要用锤子,你就买了两把锤子分别让工人戴在身上,可是JS的单线程规则就相当于你为两名工人制定了一个规则,就是同一时间段内,只能一个人用锤子,明明一个锤子能搞定的事你非要整两个,工人戴在身上累的够呛,你还多浪费了一份钱。
所以原型模式应运而生。
2.原型模式
function person(){}
person.prototype.say = function(){alert(this.name)}
var person1 = new person();
person1.name = '小明';
person1.age = 18;
person1.say(); // 浏览器弹出‘小明’
var person2 = new person();
person2.name = '小红';
person2.age = 24;
person2.say(); // 浏览器弹出‘小红’
这里可能让你疑惑的应该是prototype这个东西,说一下,函数的prototype属性是函数创建之初JS引擎自动为函数生成的一个对象,我们称这个对象为原型对象,这个对象默认有两个属性
①constructor
②_ _ proto _ _ (这个属性是浏览器厂商自己实现的,并非JS引擎实现)
注意:
只有函数有prototype对象,而且只有prototype对象有constructor属性。
通过构造函数构造出的对象和我们自己创建的普通对象只有_ _ proto _ _ 这个属性,并且我们可以通过_ _ proto _ _ 来访问构造出此对象的构造函数的prototype对象。代码如下:
function person(){}
person.prototype.say = function(){alert(this.name)};
var person1 = new person();
var a = {};
console.log(person.prototype)
console.log(person1)
console.log(a)
![](https://img.haomeiwen.com/i8793674/bf23e847f4f8afc4.png)
注:constructor属性存在的意义在于能够让构造函数new出的对象知道是谁把它构造出的,相当于:
有一天,小明去邻居小红家玩,小红的爸爸叫老王,老王正好回家,进门看了小明一会说:“我是你爸爸”。小明就蒙逼了,当即回家告老爹,老爹一气之下去验了DNA,发现小明的亲爹果然是老王。那么老王就是person()构造函数,小明就是person1对象,小红就是person2对象,这个DNA就是constructor,小明之所以能找到亲爹就是因为DNA(constructor)的存在。
但是不得不说constructor属性在我们一般开发工作当中是用不到的,只有你去构建大型框架类JS时才用的上。
根据这个图我们可以证明出:
console.log(person.prototype === person1.__proto__)//true
console.log(person.prototype.__proto__ === a.__proto__)//true
console.log(person1.__proto__.__proto__ === a.__proto__)//true
细心的同志可能发现了person.prototype上有一个say方法,我们并没有在person1对象上直接定义这个方法,但开头我们写的代码已经验证了say方法是可用的,这是因为:
构造出的对象person1能通过_ _ proto _ _来访问这个方法
这里说明一下person.prototype并非只能添加方法,也可以在prototype添加基础数据类型的属性:
person.prototype.name = '小明';或者
person.prototype.name = '小红';
但是这样person.prototype.name只能添加一个数据,这对于我们要创建两个实例的案例来说是没有任何意义的
这就解决了构造函数不能解决的方法重复问题,但是新问题又是显而易见的,因为要为每个对象添加特定的属性,还要通过手动添加的方式,如果要是能通过构造函数的方式把参数传进去就好了,对吧。
那么构造函数和原型的组合模式就这么产生了
3.构造函数和原型的组合模式
function person(name,age){
this.name = name;
this.age = age;
}
person.prototy.say = function(){
alert(this.name)
}
var person1 = new person('小明',18);
person1.say(); //弹出小‘小明’
var person2 = new person('小红',24);
person2.say(); //弹出‘小红’
这样的组合模式就能满足我们的使用需求了,能传参数,有公共的方法,灵活性和代码性能都有了提升,原理就不用多说了,完全就是把构造函数和原型模式的优点组合在了一起
网友评论