来自 前端知识 2019-09-21 12:48 的文章
当前位置: 金沙澳门官网网址 > 前端知识 > 正文

创制对象的,javascript中类的概念及其情势

浅谈 JS 创制对象的 8 种方式

2015/10/16 · JavaScript · 对象

初稿出处: Tomson   

  • Objct 模式
  • 厂子格局
  • 构造器情势
  • 通过 Function 对象达成
  • prototype 模式
  • 构造器与原型格局的交集格局
  • 动态原型方式
  • 掺杂工厂格局

有关javascript中类的三翻五次能够参谋阮一峰的Blog《Javascript承继机制的设计看法》,说的很透。

1.Object 模式

JavaScript

var o1 = {};//字面量的表现情势 var o2 = new Object; var o3 = new Object(); var o4 = new Object(null); var o5 = new Object(undefined); var o6 = Object.create(Object.prototype);//等价于 var o = {};//即以 Object.prototype 对象为三个原型模板,新建一个以那一个原型模板为原型的靶子 //分裂 var o7 = Object.create(null);//创建三个原型为 null 的目的

1
2
3
4
5
6
7
8
var o1 = {};//字面量的表现形式
var o2 = new Object;
var o3 = new Object();
var o4 = new Object(null);
var o5 = new Object(undefined);
var o6 = Object.create(Object.prototype);//等价于 var o = {};//即以 Object.prototype 对象为一个原型模板,新建一个以这个原型模板为原型的对象
//区别
var o7 = Object.create(null);//创建一个原型为 null 的对象

在 chrome 里查看种种新建对象的界别:
图片 1

能够看到前6种方式创制出来的对象都以一律的,第各样分裂点在于其尽管也为 Object 对象但其无任何性质(饱含未有其他能够一而再的特性,因为成立的时候从不点名其原型)

一、在javascript中实例化遭遇的难题:

2.厂子情势

JavaScript

//工厂方法1 通过二个艺术来创制对象 利用 arguments 对象获得参数设置属性(参数不直观,轻松出现难点) function createCar(){ var oTemp = new Object(); oTemp.name = arguments[0];//直接给目的增加属性,每一个对象都有一向的品质 oTemp.age = arguments[1]; oTemp.showName = function () { alert(this.name); };//各类对象都有贰个 showName 方法版本 return oTemp; } createCar("tom").showName();//在 JS 中一直不传递的实参,实际形参值为 undefined(这里的 age 为 undefined) createCar("tim",80).showName(); alert(createCar("tom") instanceof Object);//true 判别目的是还是不是 Object 类或子类

1
2
3
4
5
6
7
8
9
10
11
12
13
//工厂方法1 通过一个方法来创建对象 利用 arguments 对象获取参数设置属性(参数不直观,容易出现问题)
function createCar(){
    var oTemp = new Object();
    oTemp.name = arguments[0];//直接给对象添加属性,每个对象都有直接的属性
    oTemp.age = arguments[1];
    oTemp.showName = function () {
        alert(this.name);
    };//每个对象都有一个 showName 方法版本
    return oTemp;
}
createCar("tom").showName();//在 JS 中没有传递的实参,实际形参值为 undefined(这里的 age 为 undefined)
createCar("tim",80).showName();
alert(createCar("tom") instanceof Object);//true 判断对象是否 Object 类或子类

JavaScript

//工厂方法2 透过传参设置属性(参数直观明了) function createCar(name,age){ var oTemp = new Object(); oTemp.name = name;//间接给指标增加属性,每一个对象都有一直的习性 oTemp.age = age; oTemp.showName = function () { alert(this.name); };//每一种对象都有一个showName 方法版本 return oTemp; } createCar("tom").showName(); createCar("tim",80).showName(); alert(createCar("tom") instanceof Object);//true 决断指标是或不是 Object 类或子类

1
2
3
4
5
6
7
8
9
10
11
12
13
//工厂方法2 通过传参设置属性(参数直观明了)
function createCar(name,age){
    var oTemp = new Object();
    oTemp.name = name;//直接给对象添加属性,每个对象都有直接的属性
    oTemp.age = age;
    oTemp.showName = function () {
        alert(this.name);
    };//每个对象都有一个 showName 方法版本
    return oTemp;
}
createCar("tom").showName();
createCar("tim",80).showName();
alert(createCar("tom") instanceof Object);//true 判断对象是否 Object 类或子类

上边用《javascript高档程序设计》中的例子来做表达,若是以往概念了一个car的对象,它是Object类的实例。像下边那样的:

3.构造器情势

JavaScript

//构造器方法1 function Car(sColor,iDoors){ //表明为布局器时须要将函数名首字母大写 this.color = sColor; //构造器内直接注明属性 this.doors = iDoors; this.showColor = function(){ return this.color; };//每一个 Car 对象都有谈得来的 showColor方法版本 this.showDoor = function () { return this.doors; } }

1
2
3
4
5
6
7
8
9
10
11
//构造器方法1
function Car(sColor,iDoors){  //声明为构造器时需要将函数名首字母大写
    this.color = sColor;      //构造器内直接声明属性
    this.doors = iDoors;
    this.showColor = function(){
        return this.color;
    };//每个 Car 对象都有自己的 showColor方法版本
    this.showDoor = function () {
        return this.doors;
    }
}

应用办法1的难点很显眼,不能够是 showDoor 方法重用,每趟新建二个目的将要要堆里新开发一篇空间.革新如下

JavaScript

//构造器方法2 function showDoor(){ //定义二个大局的 Function 对象 return this.doors; } function Car(sColor,iDoors){//构造器 this.color = sColor; //构造器内直接注脚属性 this.doors = iDoors; this.showColor = function(){ return this.color; }; this.showDoor = showDoor();//各样 Car 对象分享同八个 showDoor 方法版本(方法有自个儿的效率域,不用操心变量被分享) } alert(new Car("red",2).showColor());//通过构造器成立一个对象并调用其目的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//构造器方法2
function showDoor(){      //定义一个全局的 Function 对象
    return this.doors;
}
 
function Car(sColor,iDoors){//构造器
    this.color = sColor;      //构造器内直接声明属性
    this.doors = iDoors;
    this.showColor = function(){
        return this.color;
    };
    this.showDoor = showDoor();//每个 Car 对象共享同一个 showDoor 方法版本(方法有自己的作用域,不用担心变量被共享)
}
 
alert(new Car("red",2).showColor());//通过构造器创建一个对象并调用其对象方法

地点出现的难点便是语义远远不足清除,呈现不出类的封装性,立异为 prototype 方式

复制代码 代码如下:

4.通过Function对象完结创造对象

咱俩通晓每声多美滋个函数实际是创造了一个Function 实例 JS 函数.

JavaScript

function function_name(param1,param2){alert(param1);} //等价于 var function_name = new Function("param1","pram2","alert(param1);");

1
2
3
function function_name(param1,param2){alert(param1);}
//等价于
var function_name = new Function("param1","pram2","alert(param1);");

JavaScript

var Car2 = new Function("sColor","iDoors", "this.color = sColor;"+ "this.doors = iDoors;"+ "this.showColor = function(){ return this.color; }" ); alert(new Car2("blue",3).showColor());

1
2
3
4
5
6
var Car2 = new Function("sColor","iDoors",
         "this.color = sColor;"+
         "this.doors = iDoors;"+
         "this.showColor = function(){ return this.color; }"
);
alert(new Car2("blue",3).showColor());

var oCar=new Object();
oCar.color = "red";
oCar.doors = 4;
oCar.mpg = 23;
oCar.showColor = function () {
alert(this.color);
};

5.prototype模式

  • 类经过 prototype 属性增加的品质与方式都是绑定在那些类的 prototype 域(实际为二个 Prototype 对象)中,绑定到这些域中的属性与办法独有一个本子,只会创制二遍.
  • 类的实例对象足以直接像调用本身的特性同样调用该类的 prototype 域中的属性与艺术,类能够透过调用 prototype 属性来直接调用prototype 域内的性质与方法.

在意:通过类实例化出指标后对象内无 prototype 属性,但目标可径直像访问属性一样的访谈类的 prototype 域的原委,实例对象有个村办属性__proto__,__proto__品质内含有类的 prototype 域内的品质与方法

JavaScript

办法1 function Car3(){}//用空构造函数设置类名 Car3.prototype.color = "blue";//每一个对象都分享一样属性 Car3.prototype.doors = 3; Car3.prototype.drivers = new Array("Mike","John"); Car3.prototype.showColor = function(){ alert(this.color); };//每一种对象分享二个格局版本,省里部存款和储蓄器。 var car3_1 = new Car3(); var car3_2 = new Car3(); alert(car3_1.color);//blue alert(car3_2.color);//blue alert(Car3.prototype.color);//blue car3_1.drivers.push("Bill"); alert(car3_1.drivers);//"Mike","John","Bill" alert(car3_2.drivers);//"迈克","约翰","Bill" alert(Car3.prototype.drivers);//"迈克","John","Bill" //直接修改实例对象的习性,剖析器会先去找实例对象是或不是有这么些个性(不会去找实例对象的 _proto_ 属性内的这一个类的 prototype 属性,而是径直查看那些实例是还是不是有关照的属性(与_proto_同级)) //若无则一向给那个实例对象增添该属性,但不会修改类的prototype域的同名属性,既实例对象的_proto_属性内的那个类 prototype 域属性不会被改变 car3_1.color = "red";//car3_1指标内无名氏称为color 的靶子属性,故将该属性增加到该指标上 //分析器对实例对象读取属性值的时候会先查找该实例有无同名的直白属性 //如果未有,则查找__proto__属性内保存的那多少个 当前类的 prototype 域的性子 //有就赶回,无则再三再四搜寻是或不是有原型链中的附和的办法属性 //有就再次回到,无则重回undefined alert(car3_1.color);//red alert(car3_2.color);//blue alert(car3_2.color2);//undefined //直接修改类的 prototype 域内的质量,不会影响该类的实例对象的靶子属性,但会影响实例对象的_proto_属性(_proto_质量内部存款和储蓄器放的是类的 prototype 域的内容) Car3.prototype.color = "black"; alert(car3_1.color);//red 该目的有同名的一向属性,故不会去_proto_个性内查找类的 prototype 域的品质 alert(car3_2.color);//black 受影响 //间接修改实例对象的主意,深入分析器会先去找实例对象是还是不是有这一个艺术(不会去找实例对象的 _proto_ 属性内的那贰个类的 prototype 域的不二秘诀,而是径直查看那一个实例是或不是有对应的方式(与_proto_同级)) //若无则向来给那些实例对象增多该方法,但不会修改类的prototype域的同名方法,既实例对象的_proto_属性内的那个类 prototype 域方法不会被涂改 //car3_1目的内无名氏称为 showColor 的靶子方法属性,故将该方法属性增多到该目的上 car3_1.showColor = function () { alert("new function"); } //深入分析器对实例对象调用方法属性的时候会先查找该实例有无同名的直白格局属性 //若无,则查找_proto_属性单位内部的保卫存的那多少个 当前类的 prototype 域的办法属性 //有就回到,无则继续搜寻是还是不是有原型链中的相应的点子属性 //找到就回来,无则报错 car3_1.showColor();//new function car3_2.showColor();//blue car3_1.abcd();//直接报错 //直接修改类的 prototype 域内的不二等秘书诀属性,不会默转潜移该类的实例对象的方式属性,但会影响实例对象的_proto_属性(_proto_质量内部存款和储蓄器放的是类的 prototype 域的内容) Car3.prototype.showColor = function () { alert("second function"); } car3_1.showColor();//new function 该对象有同名的艺术属性,故不会去_proto_属性内查找类的 prototype 域的方法属性 car3_2.showColor();//second function 受影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
方法1
function Car3(){}//用空构造函数设置类名
Car3.prototype.color = "blue";//每个对象都共享相同属性
Car3.prototype.doors = 3;
Car3.prototype.drivers = new Array("Mike","John");
Car3.prototype.showColor = function(){
    alert(this.color);
};//每个对象共享一个方法版本,省内存。
 
var car3_1 = new Car3();
var car3_2 = new Car3();
 
alert(car3_1.color);//blue
alert(car3_2.color);//blue
alert(Car3.prototype.color);//blue
 
car3_1.drivers.push("Bill");
alert(car3_1.drivers);//"Mike","John","Bill"
alert(car3_2.drivers);//"Mike","John","Bill"
alert(Car3.prototype.drivers);//"Mike","John","Bill"
 
//直接修改实例对象的属性,解析器会先去找实例对象是否有这个属性(不会去找实例对象的 _proto_ 属性内的那些类的 prototype 属性,而是直接查看这个实例是否有对应的属性(与_proto_同级))
//如果没有则直接给这个实例对象添加该属性,但不会修改类的prototype域的同名属性,既实例对象的_proto_属性内的那些类 prototype 域属性不会被修改
car3_1.color = "red";//car3_1对象内无名为 color 的对象属性,故将该属性添加到该对象上
 
//解析器对实例对象读取属性值的时候会先查找该实例有无同名的直接属性
//如果没有,则查找__proto__属性内保存的那些 当前类的 prototype 域的属性
//有就返回,无则继续查找是否有原型链中的对应的方法属性
//有就返回,无则返回undefined
alert(car3_1.color);//red
alert(car3_2.color);//blue
alert(car3_2.color2);//undefined
 
//直接修改类的 prototype 域内的属性,不会影响该类的实例对象的对象属性,但会影响实例对象的_proto_属性(_proto_属性内存放的是类的 prototype 域的内容)
Car3.prototype.color = "black";
alert(car3_1.color);//red 该对象有同名的直接属性,故不会去_proto_属性内查找类的 prototype 域的属性
alert(car3_2.color);//black 受影响
 
//直接修改实例对象的方法,解析器会先去找实例对象是否有这个方法(不会去找实例对象的 _proto_ 属性内的那些类的 prototype 域的方法,而是直接查看这个实例是否有对应的方法(与_proto_同级))
//如果没有则直接给这个实例对象添加该方法,但不会修改类的prototype域的同名方法,既实例对象的_proto_属性内的那些类 prototype 域方法不会被修改
//car3_1对象内无名为 showColor 的对象方法属性,故将该方法属性添加到该对象上
car3_1.showColor = function () {
    alert("new function");
}
//解析器对实例对象调用方法属性的时候会先查找该实例有无同名的直接方法属性
//如果没有,则查找_proto_属性内保存的那些 当前类的 prototype 域的方法属性
//有就返回,无则继续查找是否有原型链中的对应的方法属性
//找到就返回,无则报错
 
car3_1.showColor();//new function
car3_2.showColor();//blue
car3_1.abcd();//直接报错
 
//直接修改类的 prototype 域内的方法属性,不会影响该类的实例对象的方法属性,但会影响实例对象的_proto_属性(_proto_属性内存放的是类的 prototype 域的内容)
Car3.prototype.showColor = function () {
    alert("second function");
}
car3_1.showColor();//new function 该对象有同名的方法属性,故不会去_proto_属性内查找类的 prototype 域的方法属性
car3_2.showColor();//second function 受影响

能够阅览使用该格局即使说打打减少了内部存款和储蓄器的萧条,但依然有毛病,有些对象的性质一旦改变,全体因此类实例化得到的对象的__proto__内属性值也会跟着变(实为援引),革新如下

至今又要求那样的一个实例,你大概会像那样来定义:

6.构造器格局与原型方式的混杂方式

JavaScript

//各样对象有专门项目标品质不会与别的对象分享 function Car4(sColor,iDoors){ this._color = sColor;//私有质量变量名称头加下划线标记 this._doors = iDoors; this.drivers = new Array("迈克","John");//公有属性标志 } //全数对象分享贰个办法版本,缩小内部存款和储蓄器浪费 Car4.prototype.showColor = function () { alert(this._color); }; var car4_1 = new Car4("red",4); var car4_2 = new Car4("blue",3); car4_1.drivers.push("Bill"); alert(car4_1.drivers);//"Mike","John","Bill" alert(car4_2.drivers);//"Mike","John"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//每个对象有专属的属性不会与其他对象共享
function Car4(sColor,iDoors){
    this._color = sColor;//私有属性变量名称头加下划线标识
    this._doors = iDoors;
    this.drivers = new Array("Mike","John");//公有属性标识
}
//所有对象共享一个方法版本,减少内存浪费
Car4.prototype.showColor = function () {
    alert(this._color);
};
 
var car4_1 = new Car4("red",4);
var car4_2 = new Car4("blue",3);
 
car4_1.drivers.push("Bill");
 
alert(car4_1.drivers);//"Mike","John","Bill"
alert(car4_2.drivers);//"Mike","John"

那也是常用的创建对象形式之一

复制代码 代码如下:

7.动态原型格局

JavaScript

function Car5(sColor,iDoors,iMpg){ this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.drivers = new Array("迈克","John"); //使用标记(_initialized)来剖断是或不是已给原型赋予了其余方法,有限补助措施恒久只被创制并赋值贰次if(typeof Car5._initialized == "undefined"){//因为这里的符号是增大在类上,故假如中时期接对其开展修改,依旧有望出现重复创立的情事 Car5.prototype.showColor = function () {//为Car5增添二个寄存在 prototype 域的法子 alert(this.color); }; Car5._initialized = true;//设置二个静态属性 } } var car5_1 = new Car5("red",3,25); var car5_2 = new Car5("red",3,25);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Car5(sColor,iDoors,iMpg){
    this.color = sColor;
    this.doors = iDoors;
    this.mpg = iMpg;
    this.drivers = new Array("Mike","John");
 
    //使用标志(_initialized)来判断是否已给原型赋予了任何方法,保证方法永远只被创建并赋值一次
    if(typeof Car5._initialized == "undefined"){//因为这里的标记是附加在类上,故如果后期直接对其进行修改,还是有可能出现再次创建的情况
        Car5.prototype.showColor = function () {//为Car5添加一个存放在 prototype 域的方法
            alert(this.color);
        };
        Car5._initialized = true;//设置一个静态属性
    }
}
var car5_1 = new Car5("red",3,25);
var car5_2 = new Car5("red",3,25);

这种方式使得定义类像强类型语言比方 java 等语言的定义格局

var oCar2 = new Object();
oCar2.color = "blue";
oCar2.doors = 5;
oCar2.mpg = 25;
oCar2.showColor = function () {
alert(this.color);
};

8.混合工厂方式

JavaScript

function Car6(){ var oTempCar = new Object; oTempCar.color = "blue"; oTempCar.doors = 4; oTempCar.showColor = function () { alert(this.color); }; return oTempCar; } var car6 = new Car6();

1
2
3
4
5
6
7
8
9
10
function Car6(){
    var oTempCar = new Object;
    oTempCar.color = "blue";
    oTempCar.doors = 4;
    oTempCar.showColor = function () {
        alert(this.color);
    };
    return oTempCar;
}
var car6 = new Car6();

由于在 Car6()构造函数内部调用了 new 运算符,所以将忽略第二个 new 运算符(位于构造函数之外),
在构造函数内部创制的指标被传送回变量car6,这种格局在目的方法的内部管理方面与卓越情势(工厂方法)有着同样的难题.应尽量防止

1 赞 3 收藏 评论

图片 2

如此那般境遇的标题是各种对象都须求再行定义一次他的字段和方法。很麻烦。

二、类的概念--工厂形式贯彻:

对地方的事例举行一个包裹,利用函数的再次回到值来做小说:

复制代码 代码如下:

function createCar() {
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.doors = 4;
oTempCar.mpg = 23;
oTempCar.showColor = function () {
alert(this.color);
};
return oTempCar;
}

调用格局:

var oCar1 = createCar();
var oCar2 = createCar();

这种方法被称之为工厂格局。工厂情势看起来是便捷多了。起码创建叁个对象的时候不再须要那么多的行数。因为种种属性(color,doors,mpg)的值都是向来的,还索要重新开展更换,利用参数字传送递来兑现:

复制代码 代码如下:

function createCar(sColor, iDoors, iMpg) {
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function () {
alert(this.color);
};

return oTempCar;
}

var oCar1 = createCar("red", 4, 23);
var oCar2 = createCar("red", 4, 23);

oCar1.showColor();
oCar2.showColor();

这么做看似真的能够完毕了对象了。达成也很轻巧,调用也很方便。不过有五个不是很好的地方:

1、从语义上看,在创制对象时不曾利用new运算符,如同不是那么正式(平时创制八个对象都用多少个new运算符来完结)。

2、不适合面向对象的性状--封装。在这一个例子中,oCar1和oCar2都有协和的showColor方法,并且她们的showColor都是温馨的落到实处。不过实际是他们分享的是同叁个函数。

也会有艺术消除那个分享函数的问题,利用函数指针来化解。在createCar函数之外再次创下设三个showColor函数,而oTempCar的showColor方法指向这么些showColor函数:

复制代码 代码如下:

function showColor() {
alert(this.color);
}

function createCar(sColor, iDoors, iMpg) {
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red", 4, 23);
var oCar2 = createCar("red", 4, 23);

oCar1.showColor();
oCar2.showColor();

纵然那样消除了再次创制函数的标题,但那样的话,就使showColor函数看起来不像是对象的章程。

三、类的概念--构造函数方式贯彻:

复制代码 代码如下:

function Car(sColor, iDoors, iMpg) {
//通过构造函数的样式,会为各类对象生成单身的习性和函数
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function () {
alert(this.color);
};

本文由金沙澳门官网网址发布于前端知识,转载请注明出处:创制对象的,javascript中类的概念及其情势

关键词: