##内容目录
这一周讲课讲了一些关于JS的原理,个人认为很重要,所以想要整理记录下来
[TOC]
1. 封装
Javascript 是非常松散的面向对象语言,它不像其他面向对象语言那样有类的概念,因此,我们需要利用封装把属性和方法联合起来创建一个对象。
最原始的封装的方法是:
以这一种原型:
1
2
3
4var Cat = {
name : '',
color : ''
}
去生成实例对象:1
2
3
4
5
6 var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
这一种方法把两个属性封装在一个对象里面,但是这一种方法在应用于需要生成多个实例的时候,写起来会很麻烦,浪费资源,而且实例与原型间也没有联系。
原始模式的改进
这一种就相当于写一个函数然后去调用它
1
2
3
4
5
6
7
8function Cat(name,color){
return {
name:name,
color:color
}
}
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");
这一种虽然解决了代码重复的问题,但实例对象间不存在联系。于是又有了另一种模式–>构造函数模式。
构造函数模式
构造函数,就像构造一个普通的函数,不同的是,它的函数内部利用了 this 关键字,并且在生成实例时用了 new 运算符。
1
2
3
4
5
6
7
8
9function Cat(name,color){
this.name=name;
this.color=color;
}//原型对象
var cat1 = new Cat("大毛","黄色");//实例对象
var cat2 = new Cat("二毛","黑色");//实例对象
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这一种方法中,cat1 和 cat2 会自动含有一个 constructor 属性,指向它们的构造函数。如果我们用弹窗代码去检验它们是否指向构造函数时,可以看到结果为 true .1
2 alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true
我们还可以用 instanceof 运算符去验证实例与原型的关系1
2alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
这一种方法可以将实例与原型联系起来,但是它也存在着一个大问题–>浪费内存 !!假如原型函数里面我定义了一个方法或属性,而这个方法或属性是所有的实例对象都共有的,当我生成一个新的实例对象时,这个共有的方法或属性也会被重复生成,这就导致了不必要的内存。
于是乎,就出现了另一种组合函数模型
- 组合函数模型
这一种方法将原型与函数结合起来:1
2
3
4
5
6
7
8
9
10
11
12function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
var cat1 = new Cat("大毛","黄色");//生成实例对象
var cat2 = new Cat("二毛","黑色");//生成实例对象
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
这里的type和eat()用的是同一个内存,他们是指向原型对象的,由此节省了内存。
2. 原型链
根据我的理解,当原型既是实例又是原型对象时,原型链可以用这样一个图来表示:
当只有一层关系时,原型链是这样的图:
(内容比较多,内容未完整,资料参考:
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html
)