面向对象与原型
一、创建对象
1、基本方法
1 var box = new Object(); //创建对象
2 box.name = 'Lee'; //添加属性
3 box.age = 100;
4 box.run = function(){ //添加方法
5 return this.name this.age '运行中...'; //this表示当前作用于下的对象
6 };
7
8 alert(box.run());
9
10 alert(this.anme); //这里的this代表的是window
2、工厂模式
1 //创建一个集中实例化的函数
2 function createObject(name,age){
3 var obj = new Object(); //创建对象
4 obj.name = name; //添加属性
5 obj.age = age;
6 obj.run = function(){ //添加方法
7 return this.name this.age '运行在...';
8 };
9 return obj; //返回对象引用
10 }
11
12 var box1 = new createObject('Lee',100); //创建第一个对象
13 var box2 = new createObject('Jack',200); //创建第二个对象
14
15 alert(box1.run()); //打印第一个对象实例的run()方法
16 alert(box2.run());
3、构造函数
1 function Box(name,age){ //创建一个对象
2 this.name = name; //添加一个属性
3 this.age = age;
4 this.run = function(){ //添加一个方法
5 return this.name this.age '运行中...';
6 };
7 }
注意事项:
(1).构造函数也是函数,但函数名第一个字母必须大写
(2).必须new构造函数名()
(3).必须使用new运算符,用普通函数调用一般无效
构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new运算符来调用,否则就是普通函数。
使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给this对象;
3.没有renturn语句。
构造函数方式
原型模式方法
在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。__proto__属性是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor。通过这两个属性,就可以访问到原型里的属性和方法了。
二、原型
//原型实例
1 function Box(){} //构造函数体内什么都没有,这里如果有,叫做实例属性,实例方法
2
3 Box.prototype.name = 'Lee'; //添加原型属性
4 Box.prototype.age = 100; //添加原型属性
5 Box.prototype.run = function(){ //添加原型方法
6 return this.name this.age '运行中...';
7 };
原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
原型的声明是有先后顺序的,所以,重写的原型会切断之前的原型。
//使用字面量方式创建原型
1 function Box() {};
2 Box.prototype = { //使用字面量的方式,这里{}就是对象,是Object,{}就相当于new Object
3 name : 'Lee',
4 age : 100,
5 run : function () {
6 return this.name this.age '运行中...';
7 }
8 };
原型的优点 -- 共享 -- 也是缺点
解决缺点方式
1、组合构造函数 原型模式
1 function Box(name,age){ //保持独立的用构造函数
2 this.name = name;
3 this.age = age;
4 this.family = ['哥哥','姐姐','妹妹'];
5 }
6
7 Box.prototype = { //保持共享的用原型模式
8 constructor : Box,
9 run : function(){
10 return this.name this.age "运行中...";
11 }
12 };
2、动态原型模式
1 //使用此方法,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系
2 //可以将原型封装到构造函数里
3 function Box(name,age){
4 this.name = name;
5 this.age = age;
6 this.family = ['哥哥','姐姐','妹妹'];
7
8 //原型的初始化,只要一次初始化就可以了,没必要每次构造函数实例化的时候都初始化
9 if(typeof this.run != 'function'){ //判断this.run是否存在
10 Box.prototype.run = function(){
11 return this.name this.age "运行中...";
12 };
13 }
14 }
3、寄生构造函数(= 工厂模式 构造函数)
1 function Box(name,age){
2 var obj = new Object();
3 obj.name = name;
4 obj.age = age;
5 obj.run = function(){
6 return this.name this.age "运行中...";
7 }
8 return obj;
9 }
4、稳妥构造函数
1 //在一些安全环境中,如禁止使用this(构造函数里不使用this)和new(外部实例化构造函数不使用new)
2 function Box(name,age){
3 var obj = new Object();
4 obj.run = function(){
5 return name age "运行中..."; //直接打印参数即可
6 }
7 return obj;
8 }
三、继承
1、通过原型链继承
1 function Box(){ //被继承的函数叫做超类型(父类,基类)
2 // this.name = 'Lee';
3 }
4
5 Box.prototype.name = 'Jack';
6
7 function Desk(){ //继承的函数叫做子类型(子类,派生类)
8 this.age = 100;
9 }
10
11 //通过原型链继承
12 Desk.prototype = new Box();
13
14 var desk = new Desk();
15 alert(desk.name); //就近原则,实例里有就返回,没有就去查找原型
2、借用构造函数继承(对象冒充继承)
1 function Box(age) {
2 this.name = ['Lee', 'Jack', 'Hello']
3 this.age = age;
4 }
5
6 function Desk(age) {
7 Box.call(this, age); //对象冒充,给超类型传参
8 }
9
10 var desk1 = new Desk(200);
11 alert(desk1.age);
12 alert(desk1.name);
13 desk1.name.push('AAA'); //添加的新数据,只给desk
14 alert(desk1.name);
15
16 var desk2 = new Desk(200);
17 alert(desk2.name);
3、组合继承(=原型链 借用构造函数)
1 function Box(age) {
2 this.name = ['Lee', 'Jack', 'Hello']
3 this.age = age;
4 }
5
6 Box.prototype.run = function () {
7 return this.name this.age;
8 };
9
10 function Desk(age) {
11 Box.call(this, age); //对象冒充
12 }
13
14 Desk.prototype = new Box(); //原型链继承
15
16 var desk = new Desk(100);
17 alert(desk.run());
4、原型式继承
1 //临时中转函数
2 function obj(o){ //o表示将要传递进入的一个对象
3 function F(){} //F构造是一个临时新建的对象,用来存储传递过来的对象
4 F.prototype = o; //将o对象实例赋值给F构造的原型对象
5 return new F(); //最后返回这个得到传递过来对象的对象实例
6 }
7
8 //这是字面量的声明方式,相当于 var box = new Box();
9 var box = {
10 name : 'Lee',
11 age : 100,
12 family : ['哥哥','姐姐','妹妹']
13 };
14
15 //box1就等于new F()
16 var box1 = obj(box);
17 // alert(box1.name);
18 alert(box1.family);
19 box1.family.push('弟弟');
20 alert(box1.family);
21
22 var box2 = obj(box);
23 alert(box2.family); //引用类型的属性共享了
5、寄生式继承(=原型式 工厂模式)
1 //临时中转函数
2 function obj(o){ //o表示将要传递进入的一个对象
3 function F(){} //F构造是一个临时新建的对象,用来存储传递过来的对象
4 F.prototype = o; //将o对象实例赋值给F构造的原型对象
5 return new F(); //最后返回这个得到传递过来对象的对象实例
6 }
7
8 //寄生函数
9 function create(o){
10 var f = obj(o);
11 f.run = function(){
12 return this.name "方法";
13 }
14 return f;
15 }
16
17 //这是字面量的声明方式,相当于 var box = new Box();
18 var box = {
19 name : 'Lee',
20 age : 100,
21 family : ['哥哥','姐姐','妹妹']
22 };
23
24 var box1 = create(box);
25 alert(box1.run());
6、寄生组合继承
1 //临时中转函数
2 function obj(o){ //o表示将要传递进入的一个对象
3 function F(){} //F构造是一个临时新建的对象,用来存储传递过来的对象
4 F.prototype = o; //将o对象实例赋值给F构造的原型对象
5 return new F(); //最后返回这个得到传递过来对象的对象实例
6 }
7
8 //寄生函数
9 function create(box, desk){
10 var f = obj(box.prototype);
11 f.constructor = desk; //调整原型构造指针
12 desk.prototype = f;
13 }
14
15 function Box(name,age){
16 this.name = name;
17 this.age = age;
18 }
19
20 Box.prototype.run = function(){
21 return this.name this.age '运行中...';
22 };
23
24 function Desk(name,age) {
25 Box.call(this, name, age); //对象冒充
26 }
27
28 //通过寄生组合继承来实现继承
29 create(Box,Desk); //这句话用来替代Desk.prototype = new Box()
30
31 var desk = new Desk('Lee',100);
32 alert(desk.run());
33 alert(desk.constructor);
使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给this对象;
3.没有renturn语句。
更多专业前端知识,请上 【猿2048】www.mk2048.com