面向对象与原型1---创建对象的方法
1.创建一个对象基本方法,然后给这个对象新建属性和方法。以及this的用法。
var box = new Object(); //创建对象
box.name = 'lee'; //添加属性
box.age=100;
box.run=function(){ //添加方法
return this.name+this.age+'运行中';
//this表示当前作用域下的对象 this表示new Objec()实例化出来的那个对象。
//this要放在一个作用域下,比如box.run(){}里面,这个是box作用域下的方法,方可用this来表示box本身
};
alert(box.run());
alert(this); //这里的this表示的是window 输出object
alert(this.name);//输出空 window下面没有定义name
var name='kkk';
alert(this.name);//输出kkk
2.工厂模式的方法创建对象
为了解决多个类似对象声明的问题,使用的方法。这种方法为了解决实例化对象产生大量重复的问题。
//工厂模式
function createObeject(name,age){ //里面可以传参
var obj = new Object(); //创建对象
obj.name=name; //添加属性
obj.age=age;
obj.run=function(){ //添加方法
return this.name+this.age+'运行中';
};
return obj; //返回对象引用 必须要返回obj 不然得不到一个对象
}
var box1 = createObeject('lee',100); // 创建第一个对象
var box2 = createObeject('jack',200); //创建第二个对象
alert(box1.run()); //打印第一个对象实例的run()方法 输出lee100运行中
alert(box2.run()); //打印第一个对象实例的run()方法 输出jack200运行中
//以上工厂模式实例解决了集中重复实例化的问题
工厂模式解决了重复实例化的问题,但还有一个问题,那就是识别问题。因为根本无法搞清楚他们到底是哪个对象的实例。
alert(typeof box1); //object
alert(typeof box2); //object
alert(box1 instanceof Object); //true
alert(box2 instanceof Object); //true
box1 和box2都是object 但是无法知道到底是哪个对象的实例。
3.构造函数创建对象
function Box(name,age){ //创建一个对象 所有构造函数的对象其实就是 Object
this.nam=name; //添加一个属性
this.age=age; //添加一个属性
this.run = function(){ //添加一个方法
return this.name+this.age+'运行中';
};
}
var box1= new Box('lee',100); //实例化
var box2= new Box('jack',200); //实例化
alert(box1.run()); //输出 lee100运行中
alert(box2.run()); //输出 jack200运行中
alert(box1 instenceof Box); //输出true 可以识别对象了,box1就是Box对象的引用
alert(this.name); //undefined 因为这里的this代表window
var this ='aaa';
alert(this.name); //输出 aaa
alert(Box('lee',100)); //不输出东西,构造函数,用普通函数调用一般是无效的,必须使用new运算符,若里面有return东西,则可以输出,但是又不符合一般的面向对象的写法,构造函数是需要封装起来的,里面东西是不能动的。
使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,但问题
是,这里并没有 new Object(),为什么可以实例化 Box(),这个是哪里来的呢?
使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
1.构造函数方法没有显示的创建对象(new Object());
构造函数没有new Object,但是它后台会自动 var obj = new Object();
2.直接将属性和方法赋值给 this 对象;
this就相当于obj
3.没有 renturn 语句。构造函数不需要返回对象引用,他是后台自动返回。工厂模式最后需要 return obj;
以上区别通俗来讲,构造函数跟工厂模式相比,就是少了 var obj = new Object(); return obj; 然后把obj改成this;工厂模式直接调用,构造函数需要new出来。构造函数实际上就是一个改良后的工厂方法。
构造函数的方法有一些规范:
1.构造函数也是函数,但函数名第一个字母必须大写。
函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和
普通函数);
2.必须new 构造函数名(),new Box(),而这个Box第一个字母也是大写
通过构造函数创建对象,必须使用 new 运算符
3.必须使用new运算符
//接着上面的例子 构造函数对象冒充
function Box(name,age){ //创建一个对象 所有构造函数的对象其实就是 Object
this.nam=name; //添加一个属性
this.age=age; //添加一个属性
this.run = function(){ //添加一个方法
return this.name+this.age+'运行中';
};
}
var o=new Object();
Box.call(o,'lee',100); //对象冒充 o冒充了Box对象,拥有了Box的所有功能
alert(o.run()); //输出lee100运行中
构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函
数,必须用 new 运算符来调用,否则就是普通函数。
var box = new Box('Lee', 100); //构造模式调用
alert(box.run());
Box('Lee', 20); //普通模式调用,无效
var o = new Object();
Box.call(o, 'Jack', 200) //对象冒充调用
alert(o.run());
接下来探讨构造函数内部的方法(或函数)的问题,
var box1 = new Box('Lee', 100); //传递一致 实例化后地址为1
var box2 = new Box('Lee', 100); //同上 实例化后地址为2
alert(box1.name == box2.name); //true,属性的值相等
alert(box1.run() == box2.run()); //true,构造函数体内的方法的值相等,因为传参一致
alert(box1.run); alert(box2.run); //输出的都是相同的函数
alert(box1.run == box2.run); //false,因为他们比较的是引用地址,他们的地址一个是1一个是2,因此不相等。方法其实也是一种引用地址。
把构造函数里的方法(或函数)用 new Function()方法来代替,得到一样的效果,更加
证明,他们最终判断的是引用地址,唯一性。
function Box(name, age) { //new Function()唯一性
this.name = name;
this.age = age;
this.run = new Function("return this.name + this.age + '运行中...'");
}
alert(box1.run == box2.run); //false,引用地址是绝对不可能相等的
我们可以通过构造函数外面绑定同一个函数的方法来保证引用地址的一致性,但这种做
法没什么必要,只是加深学习了解:
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',100); //实例化后地址为1
var box2=new Box('lee',100); //实例化后地址为2
alert(box1.run==box2.run);
alert(run()); //输出 NAN运行中 暴露出的问题是 run可能会被外面恶意调用 应该把它封装起来(到时候测试时把本文中的name换成user)
虽然使用了全局的函数 run()来解决了保证引用地址一致的问题,但这种方式又带来了
一个新的问题,全局中的 this 在对象调用的时候是 Box 本身,而当作普通函数调用的时候,
this 又代表 window。