面向对象与原型
一、创建对象
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语句。