创建对象
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()也可以被其他调用。