代码如下:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>创建对象的模式</title>
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!--<link rel="stylesheet" type="text/css" href="main.css"/>-->
8 <!--<script src="main.js"></script>-->
9 </head>
10 <body>
11 <script>
12 //js中没有类的概念,所以开发人员使用函数来封装特定接口从而创建对象
13 //1.工厂模式,解决了创建多个相似对象的问题,但是没有解决对象识别问题
14 function t1(name,age,sex){
15 var o={};
16 o.name=name;
17 o.age=age;
18 o.sex=sex;
19 return o;
20 };
21 var p1=t1('张三',21,'male');
22 var p2=t1('Alice',23,'female');
23 console.log(p1,p2);
24 console.log(typeof p1,typeof p2);
25
26 // 2.构造函数模式
27 function T2(name,age,sex){
28 this.name=name;
29 this.age=age;
30 this.sex=sex;
31 this.showInfo=function(){
32 console.log(this.name+' '+this.age+' '+this.sex);
33 }
34 }
35 var p3=new T2('李四',25,'male');
36 var p4=new T2('Mary',22,'female');
37 //此时对象的constructor是用来标识对象类型的
38 console.log(p3,p4,p3.constructor===T2,p4.constructor===T2);
39 console.log(p3 instanceof Object,p3 instanceof T2);
40
41 //如果将构造函数作为普通函数调用,那么属性和方法都被添加到全局对象,这里是window
42 T2('ww',29,'male');
43 console.log(window.name,age,sex);
44
45 // 构造函数模式存在的缺陷:构造函数里面的方法(上面指showInfo)不是共享的,即每次的showInfo不相同
46 console.log(p3.showInfo===p4.showInfo);
47
48 // 3.原型模式
49 function T3(){
50 }
51 T3.prototype.name='Aya';
52 T3.prototype.age=100;
53 T3.prototype.showInfo=function(){
54 console.log(this.name);
55 };
56
57 var p5=new T3();
58 p5.showInfo();
59 var p6=new T3();
60 p6.showInfo();
61 console.log(p5.showInfo===p6.showInfo);
62 // 实例中的属性或方法会覆盖原型中的属性或方法
63 p5.name='xiaoming';
64 p5.showInfo();
65 delete p5.name;
66 p5.showInfo();
67 // js引擎对属性的寻找都是从下往上追溯的
68
69 // 使用hasOwnProperty()可以检测属性在实例上,还是在原型上
70 p6.name='nicai';
71 console.log(p6.hasOwnProperty('name'));
72 // 使用in,属性在原型上或者实例上,均返回true
73 console.log('name' in p5,'name' in p6);
74
75 // 所以当hasOwnProperty()返回false,而in返回true,那么属性位于原型上
76 if (!p5.hasOwnProperty('name') && 'name' in p5){
77 console.log('name属性在原型上');
78 }
79
80 // 原型模式更直观的可以写为下面形式:
81 function T4(){}
82 T4.prototype={
83 name:'abc',
84 age:100,
85 sayHi:function(){
86 console.log(this.name);
87 }
88 }
89 // 原型模式存在的问题:1.所有属性初始值一样;2.最大的问题,当含有引用类型时,一个实例对象的修改会导致其它实例对象也跟着修改
90 function T5(){}
91 T5.prototype={
92 constructor:T5,
93 name:'abc',
94 age:100,
95 arr:[1,2,3]
96 }
97 var p7=new T5();
98 var p8=new T5();
99 //所有实例对象的引用类型会相应变化
100 p7.arr.unshift(0);
101 //实例对象的基本类型倒不影响
102 p7.name='Bob';
103 console.log(p7.arr,p8.arr,p7.name,p8.name);
104
105 // 4.组合使用构造函数模式与原型模式
106 // 是目前在ECMAScript使用最广泛、认可度最高的一种创建自定义类型的方法
107 function Person(name,age){
108 this.name=name;
109 this.age=age;
110 this.friends=['Alice','Bob'];
111 }
112 Person.prototype={
113 constructor:Person,
114 sayHello:function(){
115 console.log(this.name);
116 }
117
118 };
119 var per1=new Person('Apple',1000);
120 var per2=new Person('Blue',10);
121 per1.friends.push('cat');
122 console.log(per1.friends,per2.friends);
123 console.log(per1.sayHello===per2.sayHello);
124
125 // 5.动态原型模式
126 function Person1(name,age){
127 this.name=name;
128 this.age=age;
129 if(typeof this.sayHello !== 'function'){
130 Person1.prototype.sayHello=function(){
131 console.log(this.name);
132 }
133 }
134 }
135 var per3=new Person1('Bill',111);
136 console.log(per3);
137
138 // 6.寄生(parasitic)构造函数模式
139 // 其实与工厂模式一样,除了使用构造函数和new操作符
140 function Person2(name,age){
141 var o={};
142 o.name=name;
143 o.age=age;
144 return o;
145 }
146 var per4=new Person2('Egg',100);
147
148 // 7.稳妥(durable)构造函数
149 // 与寄生构造函数模式类似,但两处不同点:1.新创建对象的实例方法不使用this 2.不使用new 调用构造函数
150 // 稳妥构造函数适合在某些安全环境下
151 function Test3(age){
152 var o={};
153 o.showName=function(){
154 console.log(age);
155 };
156 return o;
157 }
158 var per5=Test3(100);
159 console.log(per5);
160 </script>
161 </body>
162 </html>
运行结果:
参考<<JavaScript高级程序语言设计>>