javascript面向对象(二)--创建对象

  1 /创建对象:
  2     //最基本的   Object构造以及字面量法
  3     //一、工程模式创建:使用参数传值在构造
  4     function createObject(name,age,job){
  5         var o = new Object();
  6         o.name = name;
  7         o.age = age;
  8         o.job = job;
  9         o.sayName = function(){
 10             alert(this.name);
 11         };
 12         return o;
 13     }
 14     var person = createObject(‘zhd‘,23,‘Software Engineer‘);
 15     //该方式无法确定  该对象是一个什么样的类型(都是有Object创建的)
 16
 17     //二、构造函数模式:改进工厂模式
 18     function Person(name,age,job){  //约定俗成 首字母大写
 19         var o = new Object();
 20         this.name = name;
 21         this.age = age;
 22         this.job = job;
 23         this.sayName = function(){
 24             alert(this.name);
 25         };
 26         //也可以像下面这种方式定义,这种方式定义会导致不同的作用域链和标识符解析,例:
 27         //alert(person1.sayName == person2.sayName) //false
 28         //但创建机制还是一样的
 29         //this.sayName = new Function("alert(this.name");  //没有大括号
 30     }
 31     var person = new Person(‘zhd‘,23,‘Software Engineer‘);  //构造方法
 32     //每个对象都有一个 constructor指向构造函数,因此
 33     alert(person.constructor == Person); // true
 34     alert(person instanceof Person);    //true
 35     alert(person instanceof Object);    //true  所有的对象均继承自Object类
 36
 37     //构造函数也是函数,所有用new出来的函数,都可以做构造函数来看待
 38     var person = new Person(‘zhd‘,23,‘Software Engineer‘);
 39     person.sayName(); // zhd
 40
 41     Person(‘qi‘,23,‘Software Engineer‘); //普通函数来看待
 42     window.sayName(); // qi 只能是Global(浏览器时window)调用
 43
 44     var o = new Object();
 45     Person.call(o,‘qi‘,23,‘Software Engineer‘); //普通函数来看待
 46     o.sayName(); // qi 在 对象o中调用
 47
 48     //可以把sayName()对象转移到函数体外部,this指针的存在,可以保证在构造函数调用外面的sayName()时,
 49     //两个对象不会产生混乱
 50     function Person(name,age){
 51         this.name = name;
 52         this.age = age;
 53         this.sayName = sayName;
 54     }
 55     function sayName(){alert(this.name);}
 56
 57     //三、原型方法
 58     //对于构造函数模式来讲,可以把对象中若干个函数移出构造函数体外部,成为全局变量。
 59     //然而,这些函数并不是真正意义上的全局变量,大多数情况下仍然是声明出来的某个对象所调用
 60     //况且,方法过多让大量的方法在作为全局变量游离在构造方法之外,破坏了封装型
 61     //可以使用原型模式来解决
 62
 63     //创建的每个函数都有一个 prototype属性,这是一个指针,指向一个对象,这个对象的用途就是
 64     //包含可以由特定类型的所有实例共享的属性和方法
 65     //通过调用构造函数而创建那个对象实例的原型对象
 66     //好处就是让所有对象实例共享它所包含的属性和方法
 67     //也就是说 不必在构造函数里定义对象的信息,可以将信息直接添加到原型对象中去
 68     function Person(){};
 69     Person.prototype.name = "zhd";
 70     Person.prototype.age = 23;
 71     Person.prototype.sayName = function(){
 72         alert(this.name);
 73     };
 74
 75     var person1 = new Person();
 76     person1.sayName(); //zhd
 77     var person2 = new Person();
 78     person1.sayName(); //zhd    //所有实例共享属性和方法,与构造函数模式不同
 79
 80     alert(person1.sayName == person2.sayName); //true 没有(),这里比较的是两个指针
 81
 82     //理解原型对象  (这个对象可以理解为实实在在存在的一个对象,并且与这个函数息息相关)
 83     //只有创建一个函数,就会根据一组特定的规则为这个函数创建一个prototype属性指向函数的原型对象。
 84     //默认情况下,所有的原型对象都会自动获得一个constructor属性,这个属性包含一个指向prototype属性
 85     //所在函数的指针。例如:Person.prototype.constructor指向Person。
 86     //创建自定义构造函数后,其原型对象默认只会获取constructor属性。至于其他方法都是Object继承而来
 87     //每创建一个新实例,该实例都会包含一个指针指向构造函数的原型对象。
 88     //ECMA-262第五版称之为  [[prototype]]
 89
 90     //它们之间的关系就是:
 91     //每个新实例会有一个指针指向构造函数的原型对象。
 92     //给构造函数的原型对象赋值。
 93     //也就是说每个新实例都会得到原型对象中属性的值。
 94     //因此 alert(person1.sayName == person2.sayName)返回true
 95     //所有的实例共享构造函数的原型对象中的属性和方法
 96
 97     //可以通过 isPrototypeOf() 方法来确定是否有这么一层关系
 98     alert(person.prototype.isPrototypeOf(person1)); //true
 99
100     //ECMAScript 5中的 Object.getPrototypeOf() 可以很方便的获取一个实例的原型对象
101     alert(Object.getPrototypeOf(person1) == Person.prototype); //true
102     alert(Object.getPrototypeOf(person1).name); //zhd
103
104     //程序在读取实例属性的时候,会先后搜索两次属性的名称  以 name为例
105     //第一次在实例person1中查找name
106     //如果未找到,就会在person1的原型对象中查找name
107     //因此可以直接在实例中,定义一个与源性对象中属性相同的名字,程序就会屏蔽原型对象中的值
108     //只是在这个实例中屏蔽,不会改变原型对象的值
109     var person3 = new Person();
110     person3.name = ‘zhdqi‘;
111     alert(person3.name);    //zhdqi
112     alert(person1.name);    //zhd   不会改变
113
114     //delete person3.name;
115     //alert(person3.name);    //zhd  删掉实例同名的属性后,就会继续访问原型对象中的值
116
117     //可以使用 hasOwnProperty(); 判断访问的对象属性来自实例还是来自原型对象
118     alert(person1.hasOwnProperty("name")); //false 来自原型
119     alert(person3.hasOwnProperty("name")); //true 来自实例对象
120
121     //in操作符:可以确定在实例中能否访问某个属性,无论属性是实例还是原型对象
122     alert("name" in person1); //true name来自原型对象 只要能访问到 就是true
123     alert("name" in person3); //true  name来自实例本身
124
125     //同时使用hasOwnProperty和in能够确定访问的属性的值来自与原型对象还是实例本身
126     function hasPrototypeProperty(object,name){
127         return !hasOwnProperty(name)&&(name in object);
128     }
129     alert(hasPrototypeProperty(person1,‘name‘)); //true 能访问 且来自原型对象
130     alert(hasPrototypeProperty(person3,‘name‘)); //true 能访问 来自实例本身
131
132     //for-in能够访问对象中可枚举的属性(不论属性来自实例还是原型对象)
133     //如果原型对象某属性屏蔽了可枚举性,但实例中重新定义了该属性,那么for-in也是可以访问的
134     //使用 Object.keys(),会返回一个对象中所有可枚举实例属性的字符串数组 注意:是实例属性
135     alert(Object.keys(person.prototype)); //‘name‘,‘age‘,‘job‘
136     alert(Object.keys(person3)); //‘name‘ 实例对象的属性
137
138     //Object.getOwnPropertyNames(Person.pertotype) 返回所有实例的属性
139     alert(Object.getOwnPropertyNames(Person.pertotype)); //constructor,name,age,job,sayName
140
141     //更简单的语法
142     function Person(){}
143     Person.prototype = {
144         name:‘zhd‘,
145         age:23,
146         job:‘Software Engineer‘,
147         sayName:function(){alert(this.name);}
148     }
149
150     //!!!这样相当于重写了 prototype对象,因此 constructor指向新的constructor对象(Object)
151     //原型对象是一个已经存在的对象,因此可以在上面随意的增加删除属性与方法
152     //但是使用字面量法重新定义之后,就相当于重写该方法
153     //使用instanceof操作符还会有正确的结果,但是constructor无法确定对象的类型了
154     var friend = new Person();
155     alert(friend instanceof Object); // true
156     alert(friend instanceof Person); // true
157     alert(friend.constuctor == Person); // false
158     alert(friend.constuctor == Object); // true
159     //假如constuctor值很重要
160     Person.prototype = {
161         //constuctor:Person,      //可以直接指定  但这样会变成可枚举类型,而默认是不可枚举的
162         name:‘zhd‘,
163         age:23,
164         job:‘Software Engineer‘,
165         sayName:function(){alert(this.name);}
166     }
167     Object.defineProperty(person.prototype,"constructor",{
168         enumerable:false,   //重设constructor,使其变成不可枚举的值
169         value:Person
170     });
171
172     //实例与构造函数之间是一种松散关系,可以在原型对象上任意定义与删除方法都可以反映在实例上
173     //pertotype作为实例与构造函数之间的桥梁
174     //一旦重写了pertotype,就相当于切断了这层关系
175     function Person(){}
176     var friend = new Person();
177     Person.prototype = {        //重写了方法  桥梁被切断
178         constuctor:Person,
179         name:‘zhd‘,
180         age:23,
181         job:‘Software Engineer‘,
182         sayName:function(){alert(this.name);}
183     }
184     alert(friend.sayName); // undefined 他引用的依旧是最原始的原型对象
185
186     //原生对象的原型:即 Object,Array,String等原生引用类型的方法也是可以在其原型对象上找到
187     //例如 可以在 Array.prototype找到sort()方法,也可以在String.prototype中找到substring方法
188
189     //通过原生对象的原型,可以在原生类型上随时添加新的方法
190     //例  在String添加一个 startsWith()
191     String.prototype.startsWith = function(text){
192         return this.indexOf(text) == 0;
193     }
194     var msg = "hello world";
195     alert(msg.startsWith(‘hello‘)); //true
196
197     //原型对象的局限性
198     //这种创建对象的方式是基于共享的,在原型对象中,每一个实例都可以重新定义(修改)原型中已有的属性
199     //且不会共享。但是,如果原型中带有引用类型的变量,例如,原型中有一个数组,那么在对数组进行操作而没有
200     //重新定义的时候,那么这个被操作的数组就会被所有实例所共享
201     function Person(){}
202     Person.prototype = {        //重写了方法  桥梁被切断
203         constuctor:Person,
204         name:‘zhd‘,
205         age:23,
206         likecolor:[‘red‘,‘green‘],
207         job:‘Software Engineer‘,
208         sayName:function(){alert(this.name);}
209     }
210     var person1 = new Person();
211     var person2 = new Person();
212     person1.likecolor.push(‘blue‘);   //这里会共享
213     alert(person1.likecolor);   //red green blue
214     alert(person2.likecolor);   //red green blue
215     alert(person1.likecolor == person2.likecolor); //true
216
217     //四、结合构造函数模式以及原型对象模式创建对象  最流行的一种方法
218     //构造函数模式用于 定义实例属性
219     //原型对象模式    定义实例方法以及共享的属性
220     //每个实例都有自己的一份属性的副本,且共享着对方法的引用
221     function Person(name,age,job){
222         this.name = name,
223         this.age = age,
224         this.job = ‘Software Engineer‘
225     }
226     Person.pertotype = {
227         constuctor:Person,
228         sayName:function(){
229             alert(this.name);
230         }
231     }
232     //五、动态原型模式
233     //所谓动态原型,就是追求一种封装的效果。将原型对象的方法放到了构造函数中,通过if判断的方式动态的加载原型对象的方法
234     //判断只需要判断其中一个方法(如果有若干个方法的话),作用就是判断构造函数是否已经加载了原型对象中的方法
235     //与原型模式一样,使用字面量法重写原型会切断实例与构造函数之间的桥梁
236     function Person(name,age,job){
237         this.name = name;
238         this.age = age;
239         this.job = job;
240
241         //if(Person.pertotype.method == undefined)  /这样写也可以
242         if(typeof this.sayName != "function"){
243             //加载原型对象的函数到构造函数
244             Person.pertotype.sayName = function(){
245                 alert(this.name);
246             };
247         }
248     }
249     //六、寄生构造函数模式  与工厂模式基本相同
250     function Person(name,age){    //函数名称不再是  createObject
251         var o = new object();
252         o.name = name;
253         o.age = age;
254         o.sayName = function(){
255             alert(this.name);
256         };
257         return o;
258     }
259     var person1 = new Person(‘zhd‘,23);
260     person1.sayName(); // zhd
261
262     //在特殊场合下使用这种方式,但无法通过 instanceof 确定对象的类型,与工厂模式类似
263     //比如创造一个具有一个额外方法的特殊数组,由于不能修改Array函数,那么可以这么做:
264     function SpecialArray(){
265         var array = new Array();  //先创建一个数组
266         array.push.apply(array,arguments);  //调用apply方法接受SpecialArray的参数给array的push赋值,进而给数组赋值
267         array.toPipeString = function(){
268             return this.join("|");
269         };
270         return array;   //返回数组
271     }
272     var colors = new SpecialArray("red","green","blue");  // red,green,blue
273     colors.toPipeString(); //red|green|blue
274
275     //七、稳妥构造函数模式 :与寄生构造模式类型,但 1.新创建的实例方法不引用this 2.不能使用new调用构造函数
276     //使用于较为安全的环境(禁止使用this于new)
277     //由于没有this和new,构造函数中的数据成员无法被外部访问,只能被函数体内定义好的方法来访问
278     //在外部添加方法时,不能使用this指针,也无法在方法体内引用函数的数据成员变量
279     function Person(name,age){
280         var o = new Object();
281         //定义若干方法
282         o.name = name;
283         o.age = age;
284
285         o.sayName = function () {
286           alert(name);
287         };
288         return o;
289     }
290     var friend = Person(‘zhd‘,23);
291     friend.sayName(); //zhd
292     //alert(friend.name);  //浏览器会忽略这条语句 
时间: 2024-09-26 20:08:43

javascript面向对象(二)--创建对象的相关文章

JavaScript面向对象(二)——成员属性、静态属性、原型属性与JS原型链

前  言 上一篇博客(https://www.cnblogs.com/qdjianghao/p/10177360.html )中,我们介绍了JS中的面向对象,并详细的解释了this的指向问题.本篇博客,我们继续来学习JS的面向对象.来深入理解一下JavaScript OOP中的成员属性/方法.静态属性/方法.原型属性/方法,并且一起来探讨一下JS中的原型与原型链. 一 成员属性与成员方法 在构造函数中,通过this.属性声明.或者实例化出对象后,通过"对象.属性"追加的.都属于成员属性

javascript面向对象(二)

我们已经描述了对象的创建,那么接下来主要讲解对象的结构和对象的属性. 首先我们先看下对象和类的结构图 Person类 person的一个实例 那么在上面,我们称变量 p 是 Person类的一个实例(大家在学习或者其他的视频教学时经常听到 创建一个实例对象就是这么来的). 在p和Person之间,通过在创建new Person的时候为对象p添加了两个主要的属性. constructor:构造器 用来指向当前对象创建时,所调用的函数. __proto__:原型指针属性.通常用来指向当前构造函数的p

javascript面向对象系列——创建对象的5种模式

如何创建对象,或者说如何更优雅的创建对象,一直是一个津津乐道的话题.本文将从最简单的创建对象的方式入手,逐步介绍5种创建对象的模式 对象字面量 一般地,我们创建一个对象会使用对象字面量的形式 [注意]有三种方式来创建对象,包括new构造函数.对象直接量和Object.create()函数 var person1 = { name: "bai", age : 29, job: "Software Engineer", sayName: function(){ aler

Javascript 面向对象二:继承

现在有一个"动物"对象的构造函数. function Animal(){ this.species = "动物"; } 还有一个"猫"对象的构造函数. function Cat(name,color){ this.name = name; this.color = color; } 一. 构造函数绑定 第一种方法也是最简单的方法,使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行: function Cat

JavaScript 面向对象(三) —— 高级篇

JavaScript 面向对象(一) —— 基础篇 JavaScript 面向对象(二) —— 案例篇 一.json方式的面向对象 首先要知道,js中出现的东西都能够放到json中.关于json数据格式这里推荐一篇博客:JSON 数据格式 先看下json创建的简单对象:相比基础篇中的构造函数.原型等的创建方式,json方式简单方便:但是缺点很明显,如果想创建多个对象,那么会产生大量重复代码,不可取. JSON方式适用于只创建一个对象的情况,代码简介又优雅. 1 <!DOCTYPE html>

javascript面向对象学习笔记(二)——创建对象

javascript面向对象学习笔记(二)--创建对象 工厂模式 该模值抽象了创建具体对象de过程.用函数来封装噫特定接口创建对象的细节. function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return o; } var person1=createPerson("Chiaki&

Javascript面向对象编程(二):构造函数的继承

这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = "动物"; } 还有一个"猫"对象的构造函数. function Cat(name,color){ this.name = name; this.color = col

javascript面向对象(二)

创建对象 要创建一个对象我们可以用如下代码: var user = new Object(); user.name = '编程浪子'; user.age = 22; user.address = '四川成都'; 用这样的方法创建对象比较简单直观,也是JavaScript种创建对象最基本的方法.但是这样就有一个问题,如果我们需要创建多个对象,那么我就得写很多重复的代码.比如我们想创建另一个对象user1,我们就得重新将上面的代码重新写一遍,这在实际开发过程中是不合适的,这样如果对象过多,代码量将大

Javascript面向对象编程(二):构造函数的继承 作者:yuan一峰

Javascript面向对象编程(二):构造函数的继承 作者: 阮一峰 日期: 2010年5月23日 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = "动物"; } 还有一个"猫"对象的构造函数. function

JavaScript面向对象旅程(下)

JavaScript面向对象旅程 剪不断,理还乱,是离愁. 前面已经提到过新语言开发的两个步骤,分别是:一.定义基本的数据类型,完善结构化编程语言的设计:二.为函数类型绑定this的概念,好在对象的方法中可以引用到对象自身.下面是继续下去的思路,其主体思想是尽可能地引用传统面向对象语言的相关概念(如类.继承等)到新语言中来. 三.让对象属于某个类 这次要引入类的概念来.但是注意的是,还是前面提到过的思路,是让对象看起来属于某个类,而不是真正地构造基于类的种种语义概念. 一般来说,类包括类符号和类