javascript——面向对象程序设计,2

  1 <script type="text/javascript">
  2         //1、理解原型对象
  3         //2、原型与in操作符
  4         //3、更简单的原型语法
  5         //4、原型的动态性
  6         //5、原生对象原型
  7         //6、原型对象的问题
  8 
  9         //1、无论什么时候,只要创建了一个函数,就会根据一组特定的规则,为该函数创建一个prototype属性,该属性指向函数的原型对象
 10         //在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针
 11         //如
 12         function Person(){
 13 
 14         }
 15         //Person.prototype.constructor 指向Person
 16         //创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性,至于其他方法则都是从Object继承而来
 17         //当调用函数的创建一个新实例之后,该实例的内部包含一个指针(内部属性)指向构造函数的原型对象
 18         //在Firefox、safari、chrome在每个对象上都支持一个属性_proto_访问
 19         var p1=new Person();
 20         alert(Person.prototype.isPrototypeOf(p1))
 21 
 22         alert(Object.getPrototypeOf(p1)==Person.prototype)
 23 
 24         //虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性
 25         //而该属性的名称与原型的中的实例同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。eg:
 26         function Person() {
 27         }
 28         Person.prototype.name="amber";
 29         Person.prototype.age=23;
 30         Person.prototype.job="software engineer";
 31         Person.prototype.sayName=function(){
 32             alert(this.name)
 33         }
 34 
 35         var person1=new Person();
 36         var person2=new Person();
 37         person1.name="amber.Xu";
 38         alert(person1.name);//amber.xu --来自实例
 39         alert(person2.name);//amber --来自原型
 40 
 41         delete  person1.name;
 42         alert(person1.name);//amber --来自原型
 43 
 44         //使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,这个方法(从Object继承而来)
 45         //只在给定属性存在于对象实例中时,才会返回true
 46         function Person() {
 47         }
 48         Person.prototype.name="amber";
 49         Person.prototype.age=23;
 50         Person.prototype.job="software engineer";
 51         Person.prototype.sayName=function(){
 52             alert(this.name)
 53         }
 54         var person1=new Person();
 55         var person2=new Person();
 56 
 57         alert(person1.hasOwnProperty("name"));//false 来自实例
 58 
 59         alert(person2.hasOwnProperty("name"));//false 来自实例
 60 
 61         person1.name="amber.xu";
 62         alert(person1.name);
 63         alert(person1.hasOwnProperty("name"));//true 来自实例
 64 
 65         delete person1.name;
 66         alert(person1.name);
 67         alert(person1.hasOwnProperty("name"));//false 来自原型
 68 
 69 
 70 
 71         //2、原型与in操作符
 72         //in 有两种使用方式,一个是的单独使用和在for-in 中使用。在单独使用时,in操作符会在对象能够访问给定属性时返回true
 73         //无论该属性时来自原型还是实例
 74         function Person() {
 75         }
 76         Person.prototype.name="amber";
 77         Person.prototype.age=23;
 78         Person.prototype.job="software engineer";
 79         Person.prototype.sayName=function(){
 80             alert(this.name)
 81         }
 82         var person1=new Person();
 83         var person2=new Person();
 84         alert("name"  in person1);//true 来自原型
 85         alert("name"  in person2);//true 来自原型
 86         alert("height"  in person1);//false
 87 
 88 
 89         //这样就可以封装一个函数(给定属性是否是来给定对象的原型)
 90         function hasPrototypeProperty(object,name){
 91             return !object.hasOwnProperty(name) && (name in object);
 92         }
 93         alert("----------------------------------");
 94         alert(hasPrototypeProperty(person1,"name"));//true
 95 
 96         person1.name="张三";
 97         alert(hasPrototypeProperty(person1,"name"));//false
 98 
 99 
100         //使用for-in 返回的是所有能够通过对象访问、可枚举的属性,其中既包含原型属性也包含实例属性。
101         //屏蔽了原型中不可枚举属性(将Enumerable标记为false的属性)的实例属性也会在for-in中返回
102         //ie早期版本总中有一个bug:屏蔽了原型中不可枚举属性的实例属性也不会在for-in中返回
103         //eg:
104         var o={
105             toString:function(){
106                 return "my object";
107             }
108         };
109 
110         for(var prop in o){
111             if(prop=="toString"){
112                 alert("找到了");//在ie早期版本中不会显示
113             }
114         }
115 
116         //要取得对象上所有可枚举的属性,可以使用ECMAScript5的Object.keys()方法。接受一个对象作为参数,
117         //包含所有可枚举属性的字符串数组
118         function Person() {
119         }
120         Person.prototype.name="amber";
121         Person.prototype.age=23;
122         Person.prototype.job="software engineer";
123         Person.prototype.sayName=function(){
124             alert(this.name)
125         }
126         var person1=new Person();
127         var person2=new Person();
128         var  keys=Object.keys(Person.prototype);
129         alert(keys)
130 
131         person1.name="amber.Xu";
132         person1.age=23;
133         var keys=Object.keys(person1);
134         alert(keys)
135 
136         alert("-----------------------------------------")
137         //如果想要得到所有的实例属性不管他是否可以枚举,都可以使用
138         alert(Object.getOwnPropertyNames(person1));
139         alert(Object.getOwnPropertyNames(Person.prototype));
140 
141         alert("更简单的原型语法-----------------------------------------")
142         //3、更简单的原型语法
143         function Person() {
144 
145         }
146 
147         Person.prototype={
148             name:"AMBER",
149             age:23,
150             job:"software",
151             sayName:function(){
152                 alert(this.name)
153             }
154         }
155 
156         //这样写之后constructor属性不再指向Person函数,而是指向Object构造函数。
157         //尽管通过instanceof操作符还能返回正确的结果,但是通过constructor已经无法确定对象的类型了,eg:
158         var friend=new Person();
159         alert(friend instanceof Person)//true
160         alert(friend instanceof Object)//true
161         alert(friend.constructor==Person);//false
162         alert(friend.constructor==Object);//true
163         //如果constructor对你真的很重要,可以向下面一样设置成适当的值
164 
165         function Person() {
166 
167         }
168 
169         Person.prototype={
170             constructor:Person,
171             name:"AMBER",
172             age:23,
173             job:"software",
174             sayName:function(){
175                 alert(this.name)
176             }
177         }
178         var friend=new Person();
179         alert("手动设置constructor-----------------------------------------")
180         alert(friend.constructor==Person);//true
181 
182         //这种手动的添加了constructor会使constructor变成可枚举的元(原生的constructor属性时不可枚举的)。
183         //这种情况下就可以使用
184         Object.defineProperty(Person.prototype,"constructor",{
185             enumerable:false,
186             value:Person
187         });
188 
189 
190         //原型的动态性
191         var friend=new Person();
192         Person.prototype.sayHi=function(){
193             alert("Hi");
194         }
195 
196         friend.sayHi();//Hi (正常执行)
197         //因为实例和原型之间是松散的连接关系,实例与原型之间的连接只不过是一个指针,而非副本
198         //当我们调用sayHi()方法时,首先会在实例中搜索名为sayHi的方法,在没找到的情况下会搜索原型。
199 
200         //但是,如果是重写整个原型对象,那么情况就不一样了。
201         //我们知道,调用构造函数时会为实例添加一个指向最初原型的Prototype指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。
202         //请记住:实例中的指针仅指向原型,而不指向构造函数。eg:
203         function A(){}
204         var a1=new A();
205         A.prototype={
206             constructor:A,
207             name:"AMBER",
208             age:23,
209             job:"software",
210             sayName:function(){
211                 alert(this.name)
212             }
213         }
214         alert("ERROR-------------------------------------");
215         alert(a1.sayName());
216         //我们创建了一个A的实例,然后又重写了其原型对象,然后在调用a1.sayName()发生了错误,因为a指向的原型中不包含以该名字命名的属性/方法
217 
218         //原生对象的原型
219         //原型模式的重要性不仅体现在创建自定义类型方面。就连所有的原生的引用类型,都是采用这种模式创建的。所有的原生引用类型
220         //都在其构造函数的原型上定义的方法 eg:
221         alert(typeof Array.prototype.sort);//function
222         alert(typeof String.prototype.substring);//function
223         //不仅可以在原生对象的原型取得虽有默认方法的引用,而且可以定义新的方法
224         //为String类型添加一个startsWith()的方法
225         String.prototype.startsWith=function(text){
226             return this.indexOf(text) == 0;
227         };
228         var msg="Hello";
229         alert(msg.startsWith("H"));
230 
231         //我们并不建议这样做。
232 
233         alert("原型对象的问题");
234         //6、原型对象的问题  实例
235         function Ques() {
236         }
237 
238         Ques.prototype={
239             constructor:Ques,
240             name:"amber",
241             age:23,
242             job:"IT",
243             friends:["张三","李四"],//引用类型
244             sayName:function(){
245                 alert(this.name)
246             }
247         };
248 
249         var q1=new Ques();
250         var q2=new Ques();
251         q1.friends.push("王五");
252         alert(q1.friends);//
253         alert(q2.friends);//
254         alert(q1.friends===q2.friends);
255     //相信大家已经看到了问题,当我创建了两个实例q1、q2,当我为q1的“朋友”添加了“王五”之后,q2的”朋友“也有了三个张三、李四、王五
256     //那是因为数组存在于Ques.prototype上,而非q1上。所以出现了如上结果。
257 
258     //而正是这个问题,我们很少看到有人单独使用原型模式的原因所在。
259     </script>