JavaScript之面向对象与原型笔记整理--------创建对象(1)

创建对象

1、通过Object方法

创建一个box对象,然后给这个对象新建属性和方法,如下:

另:属性相当于变量,在一个作用域里面就变成了属性;方法其实是函数,在一定作用域下就变成了方法。

1 var box = new Object();             //创建一个Object对象
2 box.name = 'Lee';                   //创建一个name属性并赋值
3 box.age = 20;                       //创建一个age属性并赋值
4 box.run = function(){               //创建一个run方法并返回值
5     return "姓名:" + this.name + ",年龄:" + this.age;
6 }
7 console.log(box.name);             //Lee
8 console.log(box.age);              //20
9 console.log(this.age);             //undefined 因为此时this指代window

this表示new Object()实例化出来的对象,即当前作用域下的对象。

this要放在一个作用域下,比如box.run(){},这个是box作用域下的方法,即可用this来表示。

在run()方法里的this就指代box本身。

缺点:若想创建一个类似的对象,就会产生大量的代码。如下:

var box1 = new Object();           
box1.name = 'Lee';                 
box1.age = 20;                       
box1.run = function(){            
     return "姓名:" + this.name + ",年龄:" + this.age;
 }


var box2 = new Object();           
box2.name = 'Lily';                 
box2.age = 18;                       
box2.run = function(){            
     return "姓名:" + this.name + ",年龄:" + this.age;
 }

...

此时,新添加了对象box2,若继续添加(比如有十个就得写十次),则产生大量类似代码,为了解决多个类似对象声明的问题,可以使用工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。

2、工厂模式

 1  function createObject(name,age){
 2     var obj = new Object();              //创建对象
 3     obj.name = name;                     //添加属性
 4     obj.age = age;
 5     obj.run = function(){                //添加方法
 6         return "姓名:" + this.name +  ",年龄:" + this.age;  
 7     };
 8     return obj;                          //需要返回这个对象,返回对象引用
 9  }
10    
11  var box1 = createObject('Lee',20);      //创建第一个对象
12  var box2 = createObject('Lily',18);     //创建第二个对象
13  console.log(box1.run());                //姓名:Lee,年龄:20
14  console.log(box2.run());                //姓名:Lily,年龄:18

工厂模式解决了重复实例化的问题,但是还有一个问题,识别问题。

缺点:无法搞清楚他们到底是那个对象的实例,都是Object。如下

 

 1    function createObject(name,age){
 2       var obj = new Object();            
 3       obj.name = name;                
 4       obj.age = age;
 5       obj.run = function(){              
 6           return "姓名:" + this.name +  ",年龄:" + this.age;  
 7       };
 8       return obj;                      
 9    }
10 
11   function createObject2(name,age){
12       var obj = new Object();            
13       obj.name = name;                
14       obj.age = age;
15       obj.run = function(){              
16           return "姓名:" + this.name +  ",年龄:" + this.age;  
17       };
18       return obj;                      
19    }
20 
21     
22   var box1 = createObject('Lee',20);      //创建第一个对象
23   var box2 = createObject('Lily',18);     //创建第二个对象
24   var box3 = createObject2('Lucy',25);     //创建第三个对象
25   console.log(box1 instanceof Object);    //true,box1属于Object对象
26   console.log(box2 instanceof Object);    //true,box2属于Object对象
27   console.log(box3 instanceof Object);    //true,box2属于Object对象

不管怎样他们都是Object对象,就无法区分谁到底是谁的对象了,其实box1和box2都是第一个工厂的Object,box3是第二个工厂的Object。此时无法区分。

 

采用构造函数可用来创建特定的对象。

3、构造函数

 1 function Box(name,age){                             //创建一个对象
 2      //此处无new,自动var obj = new Object()
 3      this.name = name;                              //添加属性
 4      this.age = age;
 5      this.run = function(){                         //添加方法
 6         return "姓名:" + this.name + ",年龄:" + this.age;
 7      }; 
 8      //此处无return,自动返回
 9 } 
10 
11 var box1 = new Box('Lee',20);                       //实例化
12 var box2 = new Box('Luck',8); 
13 console.log(box1.run());                            //姓名:Lee,年龄:20
14 console.log(box2.run());                            //姓名:Luck,年龄:8

 

使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,但问题是,这里并没有new Object(),为什么可以实例化Box(),这个是哪里来的呢?

使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:

(1)构造函数方法没有显示的创建对象(new Object()),但后台会自动var obj = new Object();

(2)直接将属性和方法赋值给this对象,此时this相当于obj;

(3)没有return语句,无需返回对象引用,后台自动返回。

 

构造函数的方法有一些规范:

(1)函数名和实例化构造名相同且第一个字母大写。

(2)必须new 构造函数名() ,例如 new Box()。

(3)必须使用new运算符。

 

接下来看识别对象问题,如下:、

 1  function Box(name,age){                          
 2        this.name = name;                              
 3        this.age = age;
 4        this.run = function(){                     
 5           return "姓名:" + this.name + ",年龄:" + this.age;
 6        }; 
 7   }
 8 
 9  function Desk(name,age){                          
10        this.name = name;                              
11        this.age = age;
12        this.run = function(){                     
13           return "姓名:" + this.name + ",年龄:" + this.age;
14        }; 
15   }  
16  
17  var box1 = new Box('Lee',20);                       
18  var box2 = new Box('Luck',8); 
19  var box3 = new Desk('Lily',22);   
20  console.log(box1 instanceof Box);    //true
21  console.log(box2 instanceof Box);    //true
22  console.log(box3 instanceof Box);    //false
23  console.log(box3 instanceof Desk);    //true

可以看出,box1,box2属于Box对象,box3属于Desk对象。解决了对象识别问题。

构造函数用普通函数调用一般是无效的,必须使用new运算符。比如直接console.log(Box('Lee',20));此时控制台输出undefined。

 

 

补充:

接下来探究一下构造函数内部的方法问题,先看例子:

 function Box(name,age){                          
         this.name = name;                              
         this.age = age;
         this.run = function(){                     
            return "姓名:" + this.name + ",年龄:" + this.age;
         }; 
   }

var box1 = new Box('Lee',20);
var box2 = new Box('Lee',20);
//构造函数体内方法值是相等的
console.log(box1.name == box2.name);           //true
console.log(box1.age== box2.age);              //true
console.log(box1.run()== box2.run());          //true
//比较的是引用地址,所以不相等
console.log(box1.run== box2.run);              //false

此时说明box1和box2的引用地址不同。

改进方法:

 function Box(name,age){                          
         this.name = name;                              
         this.age = age;
         this.run = run;
 } 
 function run(){       //通过外面调用保证引用地址一致              
         return "姓名:" + this.name + ",年龄:" + this.age;
 }

 var box1 = new Box('Lee',20);   
 var box2 = new Box('Lee',20);

 console.log(box1.run== box2.run);              //true

虽然使用了全局的函数run()来解决了保证引用地址一致的问题,但这种方式又带来了一个新的问题,全局中的this在对象调用的时候是Box本身,意思为:box1.run()时,此时this代表Box本身,而当做普通函数调用的时候,意思为:run()时,this又代表window。

此时run()也可以被其他调用。

 

posted @ 2018-08-14 16:21  灭世的蜜糖  阅读(152)  评论(0编辑  收藏  举报