浅谈JS面向对象之创建对象

时间:2023-03-08 20:56:15

hello,everybody,今天要探讨的问题是JS面向对象,其实面向对象呢呢,一般是在大型项目上会采用,不过了解它对我们理解JS语言有很大的意义。

首先什么是面向对象编程(oop),就是用对象的思想去写代码,那什么是对象呢,其实我们一直在用,像数组 Array  时间 Date 都是对象,并且这些对象是系统创建的,所以叫系统对象,而我们自己当然也可以创建对象,一般对象有两部分组成:

1 方法 (动态的,相当于对象下面的函数)比如Array 的push(),sort()方法

2  属性 (静态的,相当于对象下面的变量)Array的 length属性

OK,既然存在面向对象的编程,那么一定有它的优点,那么我们来看看它的四大特点:

抽象:抓住核心问题
封装:只能通过对象来访问方法
继承:从已有对象上继承出新的对象
多态:多对象的不同形态

这些特点呢,一开始理解是比较抽象的,只有我们在实践起来更能理解它的意义。不过我们做简单的介绍。

抽象:我们知道呢,不同的对象下面的方法是不一样的,比如数组有属于数组的方法属性,时间对象有属于它的方法属性,我们不能把时间对象的方法加给数组,把很多的方法分门别类,放到不同的对象下面,就是一种抽象,更好的管理。

封装:这个就比较好理解了,就是每个方法必须得在指定的对象下用。

继承:假如我们有两个弹窗,第二个弹窗相比第一个弹窗仅仅是多了一个功能,这个时候,就适合用继承,第二个可以继承第一个的功能,然后在这基础上再增加功能,继承提高了我们对代码的复用。

多态:也是代码复用的一种形式,用的不太多,比如有一个电脑,我们只用一个接口,然后连接不同的设备,这些设备可以实现不同的功能。听起来比较抽象,一般后端语言用的比较多。

下面我们来具体看面向对象的创建以及创建模式的演变

1 创建一个面向对象

//创建一个面向对象
var obj = new Object(); //创建一个空对象
obj.name = 'haha';
obj.showName = function(){
   alert(obj.name);

}
obj.showName();

这个栗子很简单,存在的问题是,当我们有多个面向对象的时候,重复代码过多,需要封装,所以有了下面的方法

2  工厂方式

function CreatePerson(name){
    //原料
    var obj = new Object();
    //加工
    obj.name = name;
    obj.showName = function(){
       alert(this.name);
   }
   //出厂
   return obj;
}

var p1 = CreatePerson('haha');
p1.showName();
var p2 = CreatePerson('hehe');
p2.showName();

这其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式,但为了与我们的系统对象(Array等)保持一致,所以我们要进行改造,成为构造函数模式

3 构造函数模式

我们要通过这三个方面来改变:1 函数名首字母大写  2 New 关键字提取  3  this指向为新创建的对象

function CreatePerson(name){   //函数名首字母大写
     //var this=new Object(); //系统会偷偷在这里声明一个对象赋给this替咱们做,不用写
     this.name = name;      this.showName = function(){         alert(this.name);      }     //return this;//函数的默认返回值就是this即这个对象(隐式返回 不用自己再写返回值)

} 
var p1 =new CreatePerson('haha'); //当用new去调用一个函数:这个时候this指的就是创建出来的对象 而且函数的默认返回值就是this即这个对象(隐式返回 不用自己再写返回值) p1.showName();var p2 = new CreatePerson('hehe'); p2.showName();

所以最终的代码是这样的

function CreatePerson(name){
     this.name = name;
     this.showName = function(){
        alert(this.name);
     }
}
var p1 =new CreatePerson('haha');
 p1.showName();
var p2 = new CreatePerson('hehe');
 p2.showName();

但是函数构造模式也存在相应的问题:

alert(p1.showName==p2.showName);//false

测试这个代码,两个方法是不相同的,也就是说这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用,肯定不是我们所希望的。所以就有了下一种方法,原型模式

4 原型模式

我们创建的每个函数都有原型(prototype),从字面意思看,就是指最原始的,原型是加在构造函数下面的,这个时候,通过这个构造函数创建出来的对象,都能共享这个原型下的方法和属性。

看个栗子(原型+构造)

function CreatePerson(name){
    this.name = name;
}
CreatePerson.prototype.showName = function(){
    alert(this.name);
}
var p1 =new CreatePerson('haha');
p1.showName();
var p2 = new CreatePerson('hehe');
p2.showName();

alert(p1.showName==p2.showName);//true

通过最后一句的测试为true,可以看到在构造函数的原型下面加的方法showName()方法是所有通过这个构造函数创建出来的对象所共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2的showName。

所以我们在构造对象的时候,一般是原型模式和构造模式组合使用,变化的用构造模式 不变的公用的用原型模式,就像上面的这个栗子,属性用的构造函数,因为一般不同对象属性都不同,方法用原型模式。

(补充):

原型和普通函数的区别(相当于style和class的区别)
  1 原型优先级低

function Thing(){}
var p =new Thing();
Thing.prototype.num= 1;
p.num = 2;
alert(p); //2 会优先在自己下面找,再去原型里面找
2 原型重用性高

3 原型所有东西共享一份

在这里我要介绍一个重要的属性就是constructor

1  它指的是对象的构造函数

2  每个自定义的构造函数都有的属性,当你写完一个构造函数的时候,系统程序会自动在函数的原型下添加对应的构造函数,比如有个自定义构造函数Aaa,系统会自动帮你添加这句话:

Aaa.prototype.construnctor = Aaa;(每个函数都有 都是自动生成的)

所以每个构造函数出生后,原型下面都有这样一个属性了。可以测试一下

 function Aaa(){}
 var a1 = new Aaa();
 a1.constructor  //Aaa函数

3 所以既然是原型下面的,证明构造函数也是可以被修改的。

 function Aaa(){}
 Aaa.prototype.construnctor=10;//添加
 var a1 = new Aaa();
 a1.constructor  //10

不过要避免修改这个属性。

4 不过有一种情况,我们需要修改,为了创建对象的代码更方便,你一定见过这样的代码,采用Json的方式在原型下加方法,也就是字面量法:

function Aaa(){}
Aaa.prototype = {
    num1:function(){alert(10);},
    num2:function(){alert(20);}
 } 
//这种方式相当于重新赋值了Aaa的原型 ,所以也覆盖掉了系统默认添加的这个:Aaa.prototype.construnctor = Aaa; 
var a1 = new Aaa();

a1.constructor //object

这个时候弹出的构造函数竟然变成了object,这是为什么呢,首先我们要知道object是所有对象的最初始的大boss,所有的对象都属于object,其次上面有讲过,每个最开始的构造函数的原型下面都有这样一句话,Aaa.prototype.construnctor = Aaa;这个例子的赋值方式,已经不是在原型上增加方法了,它属于一种赋值的方式,所以就把原来的构造函数给覆盖了,因此我们在写的时候需要修正一下原型的指向。

function Aaa(){}
Aaa.prototype = {
     constructor:Aaa,
     num1:function(){alert(10);},
     num2:function(){alert(20);}
}
var a1 = new Aaa(); a1.constructor // Aaa

关于JS面向对象之构造对象就先说到这里,其实还有别的不常用的模式,后续会继续补充,如果疏漏,欢迎补充,我是沐晴,不见不散