面向对象与原型

  • 创建对象的几种方法
  1. 基本对象的创建方法

最基础的对象创建方式

1
2
3
4
5
6
var box = new Object(); //创建对象
box.name= 'Lee'; //添加属性
box.age=100;
box.run= function(){
return this.name+this.age+'运行中' //this表示当前作用域下对象
}

  1. 使用字面量创建

作为一门脚本语言那应该有和其他兄弟们一样的范儿,于是出现了对象字面量的定义方式:

1
2
3
4
5
6
7
var box = {
name : "tangwei",
bar : "js",
sayWhat : function() {
console.log(this.name + "said:love you forever");
}
}

  1. 工厂模式

字面量实际上是我们在实际中最常用的对象定义方式,但是我要有好多拥有相似属性的对象(想想都让人激动。。。)怎么办呢?那要是一个个的定义,就会产生大量的代码,何不建个工厂,批量的生产出我们的对象呢,于是,javascript世界中“工厂模式”诞生了!

1
2
3
4
5
6
7
8
9
10
11
function creationGf(name,bar){
var o = new Object();
o.name = name;
o.bar = bar;
0.sayWhat = function() {
alert(this.name + "said:love you forver");
}
return o; //返回对象引用
}
var Gf1 = creationGf("binbing","d");
var Gf2 = creationGf("bi","ddd");

工厂模式解决了集中实例化的问题,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

如果我们再创建一个 creationGf2对象

1
var Gf3 = creationGf("aaa","xxx");

这时候我们无法搞清Gf3是属于creationGf对象还是属于creationGf2

1
2
3
4
alert(typeof Gf1); //Object
alert(typeof Gf2); //Object
alert(typeof Gf3); //Object
alert(Gf1 instanceof Object); //true

  1. 构建函数
1
2
3
4
5
6
7
8
9
function Gf(name,bar){
this.name = name;
this.bar = bar;
this.sayWhat = function(){
alert(this.name + "said:love you forever");
}
}
var gf1 = new Gf("vivian","f");
var gf2 = new Gf("vivian2","f");

注意:这里我们使用一个大写字母开头的构造函数替代了上例中的createGf,注意按照约定构造函数的首字母要大写。
在这里我们创建一个新对象,然后将构造函数的作用域赋给新对象,调用构造函数中的方法。
上面的方式似乎没什么不妥,但是我们可以发现,两个实例中调用的构造函数中的sayWhat方法不是同一个Function实例:

1
console.log(gf1.sayWhat == gf2.sayWhat); //false

调用同一个方法,却声明了不同的实例,实在浪费资源。我们可以优化一下将sayWhat函数放到构造函数外面声明:

1
2
3
4
5
6
7
8
function Gf(name,bar){
this.name = name;
this.bar = bar;
this.sayWhat = sayWhat
}
function sayWhat(){
alert(this.name + "said:love you forever");
}

这样解决了,多个实例多次定义同一个方法实例的问题,但是新问题又来了,我们定义的sayWhat是一个全局作用域的方法,但这个方法其实是没法直接调用的,这就有点矛盾了。如何更优雅的定义一个具备一定封装性的对象呢?我们来看一下javascript原型对象模式

------本文结束感谢阅读------