JS面向对象与原型

Posted 可可西里的海

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS面向对象与原型相关的知识,希望对你有一定的参考价值。

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

以上是关于JS面向对象与原型的主要内容,如果未能解决你的问题,请参考以下文章

js面向对象与原型

VSCode自定义代码片段——JS中的面向对象编程

JS面向对象与原型

VSCode自定义代码片段9——JS中的面向对象编程

简单粗暴地理解js原型链--js面向对象编程

简单粗暴地理解js原型链--js面向对象编程