博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

js 面向对象编程

Posted on 2011-10-13 14:44  ritazhou  阅读(1044)  评论(0编辑  收藏  举报

以下为学习笔记,学习的对象为阮一峰的blog.

js是基于对象的编程语言,但是它又不是oop,因为它没有class的概念。那么我们如果要把property和method封装成一个对象,从而进一不从原型对象生成一个实例对象。该如何编写我们的代码呢?

1、生成对象的原始模式。

var Cat = { name: '', color: '' }
var cat1 = {};
cat1.name = 'cat1';
cat1.color = 'yellow';

上面的代码就是最简单的封装,但是这样的写法有两个缺点,一个是代码的重用,二是其实实例和原型之间没有什么联系。

2、原始模型的改进

function Cat(name, color) {
return { name: name, color: color }
}
var cat1 = Cat('cat1', 'yellow');
var cat2 = Cat('cat2', 'black');

上面的代码貌似改进了不少,但是cat1和cat2之间没有内在的联系,不能反映出他们是同一个原型对象的实例。

3、构造函数模式

js中的构造函数模式解决了从原型生成对象实例的问题。所谓构造函数,其实就是一个普通的函数,但是内部使用了this变量。对构造函数使用this运算符,就能生成实例,并且this变量会绑定在实例对象上。

function Cat(name, color) { this.name = name, this.color = color; }
var cat1 = new Cat('cat1', 'yellow');
var cat2 = new Cat('cat2', 'black');
alert(cat1.constructor == Cat); //true
alert(cat1 instanceof Cat); // true

在用构造函数模式的时候,cat1和cat2会自动含有一个constructor属性,指向他们的构造函数。并且还可以通过instanceof运算符来验证原型对象和实例对象之间的关系。
但是构造函数模式存在一个浪费内存的问题。请看下面的例子。

function Cat(name, color) { this.name = name, this.color = color; this.type = 'Cat', this.eat = function () { alert('eat mouse') }; }
var cat1 = new Cat('cat1', 'yellow');
var cat2 = new Cat('cat2', 'black');
alert(cat1.type);
cat1.eat();
alert(cat1.eat == cat2.eat);//false;

对于cat1和cat2,虽然type和eat()方法都是一抹一样的内容,但是每次生成一次实例,都必须重复内容,从而多占用内存。

4、Prototype模式

该模式可以解决构造函数模式所造成的内存占用不必要的重复内存的问题。

function Cat(name, color) { this.name = name, this.color = color;}
Cat.prototype.type = 'Cat';
Cat.prototype.eat = function () { alert('eat mouse') };
var cat1 = new Cat('cat1', 'yellow');
var cat2 = new Cat('cat2', 'black');
alert(cat1.type);
cat1.eat();
alert(cat1.eat == cat2.eat); //true;
alert(Cat.prototype.isPrototypeOf(cat1)); //true alert(Object.prototype.isPrototypeOf(cat1));//true
alert(cat1.hasOwnProperty('name')); //true
alert(cat1.hasOwnProperty('type')); //false
alert('name' in cat1); //true
alert('type' in cat2); //true

这个时候,所有实例的type和eat()其实都在同一个内存地址,指向prototype对象,因此提高了运行效率。

用isPrototypeOf()来判定一个对象是不是某个实例的原型。

用hasOwnProperty来判定属性是否是本地属性还是继承自prototype的属性。

用in来判定某个实例是否含有某个属性,不区分本地和继承属性。