一,创建对象
var box = new Object();
box.name = 'lee';
box.age = 23;
box.run = function () {
return this.name + this.age + " run....";
}
alert(box.run());
上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box 对象本身。这种是JavaScript 创建对象最基本的方法,但有个缺点,想创建一个类似的对象,就会产生大量的代码。
var box1 = new Object();
box1.name = 'jack';
box1.age = 24;
box1.run = function () {
return this.name + this.age + " run....";
}
alert(box1.run());
为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。
1.工厂模式
function createObject(name, age)
{
var obj = new Object(); //创建对象
obj.name = name; //添加属性
obj.age = age;
obj.run = function () { //添加方法
return this.name + this.age + " runing...";
};
return obj; //返回对象
};
var box2 = createObject('hg', 100); //创建第一个对象
var box3 = createObject('wj', 200); //创建第二个对象
alert(box2.run()); //打印run方法
alert(box3.run());
工厂模式:就解决了实例化对象,产生大量重复的问题.但是又引出了一个新的问题,声明出来的对象都是object的类型,无法区分它们.
2.构造函数方法的方式创建对象
function Box(name, age) //创建对象
{
this.name = name; //添加属性
this.age = age;
this.run = function ()
{
return this.name + this.age + " runing...";
};
};
var box1 = new Box('lee', 100); //实力化
var box2 = new Box('wenjing', 200);
alert(box1.run());
alert(box2.run());
alert(box1 instanceof Box); //true
构造函数方式:(改良后的工厂方法)
(1)构造函数没有使用new object,但是系统会自动调用var obj=new object().
(2)this 相当于 obj.
(3)构造函数方式没有像工厂一样return obj; 后台自动返回对象.
构造函数的方法有一些规范:
(1)函数名和实例化构造名相同且大写.(非强制,但是有助于区分与普通函数之间的区别).
(2)通过构造函数创建对象,一定要用new
(3)解决了对象识别问题box1 instanceof Box 返回ture
注意:
A;this的使用
this如果在全局,就是代表windows对象,在构造函数内,代表构造函数所声明的对象.构造函数用普通函数调用,一般是无效的,必须使用new运算符.
B:对象冒充调用:
var o = new Object();
Box.call(o, 'Jack', 200) //对象冒充调用
alert(o.run()); //正确
C:探讨一下构造函数体内构造方法
function Box(name, age) //创建对象
{
this.name = name; //添加属性
this.age = age;
this.run = function ()
{
return this.name + this.age + " runing...";
};
};
var box1 = new Box('hg', 123);
var box2 = new Box('wj', 321);
alert(box1.run == box2.run); //false
两个对象使用的run函数不相同.解决引用地址不同,可以通过对象外面引用同一个函数,来解决.
function Box(name, age) //创建对象
{
this.name = name; //添加属性,实例属性
this.age = age;
this.run = run; //实例方法
};
function run()
{
return this.name + this.age + " runing...";
}
var box1 = new Box();
var box2 = new Box();
alert(box1.run());
alert(box1.run == box2.run); //true
用全局的run来解决唯一性,但是又带来了新的问题.run暴露在外边.对象调用this代表box,被当作普通函数的时候,this代表window.
3.原型
每一个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含特定类型的所有实例共享的属性和方法.
function Box() {}; //原型
Box.prototype.name = 'hg'; //原型属性
Box.prototype.age = 23;
Box.prototype.run = function () //原型方法
{
return this.name + this.age + " runing...";
}
var box1 = new Box();
var box2 = new Box();
alert(box1.run());
alert(box1.run == box2.run); //true
如果是实例方法,不同的实例化,他们的方法地址是不同的地址. 而原型方法,他们的地址是共享的,大家都是一样的.
构造函数方式
原型模式方式
__proto__ 是一个指针,指向prototype的原型对象.
在声明原型的时候,多了2个属性,这2个属性都是创建对象自动生成的, __proto__属性是实例指向原型对象的一个指针.他的作用就是指向构造函数的原型属性constructor.
PS:IE 浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。
alert(box1.__proto__); //[object Object]
alert(box1.constructor); //可以获取构造函数本身.
判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。
alert(Box.prototype.isPrototypeOf(box1)); //true
原型的执行过程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
这说明原型是原型,对象是对象.通过原型创建的对象依旧可以添加自己的属性和方法,但是这个属性和方法不影响原型.说明我们可以通过对象访问原型的值,但是不可以改写原型的值.
Box.prototype.name = 'hg'; //原型属性
Box.prototype.age = 23;
Box.prototype.run = function () //原型方法
{
return this.name + this.age + " runing...";
}
var box1 = new Box();
var box2 = new Box();
alert(box2.name); //hg
box2.name = 'wj'; //重写name的属性
alert(box2.name); //wj
delete box2.name; //删除box2的对象name属性
alert(box2.name); //hg
//可以通过prototype来重写原型中的属性.
Box.prototype.name = 'kkk'; //可以重写原型的属性
可以使用hasOwnProperty()函数来验证:构造函数的实例里是否有属性.
alert(box.hasOwnProperty('name')); //实例里有返回true,否则返回false
in操作符判断属性是否在对象中,无论属性存在于实例或者原型中都返回true.
alert('name' in box1); //true
alert('name' in box2); //true
判断是否属性只存在于原型,而实例中没有.
function isProperty(object, property) { //判断原型中是否存在属性
return (!object.hasOwnProperty(property)) && (property in object);
}
var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有
注意:
var box = new Box();
alert(box.prototype); //错
alert(box.__proto__); //可以,但是IE本身是无法反问的.
alert(Box.prototype); //可以
如果想访问prototype,用Box.prototype可以.
使用字面量的方式创建原型对象.
function Box() {}
Box.prototype = {
name:'hg',
age:23,
run:function () {
return this.age + this.name + " runing...";
}
};
var box = new Box();
alert(box.run()); //正常打印
注意:Box.prototype = {};创建了一个新的对象,不再指向Box了.
可以用constructor:Box进行强制转换.
function Box() {}
Box.prototype = {
name:'hg',
age:23,
run:function () {
return this.age + this.name + " runing...";
}
};
//这里就切断了之前的原型与对象的链接.不会保存以前的原型中的属性
Box.prototype = {
age:100,
};
var box = new Box();
alert(box.run()); //run is undefined
原型的缺点:第一:省略了传参的过程,所有的实例,初始化都是一样的.无法保持独立性.第二个缺点也是它最大的优点就是,所以的都是共享的.
//原型的缺点
function Box() {}
Box.prototype = {
constructor:Box,
name:'hg',
age:100,
family:['gege', 'jiejie', 'didi'],
run:function () {
return this.name + this.family;
}
};
var box1 = new Box();
alert(box1.family);
box1.family.push('meimei'); //更改了原型
alert(box1.family);
var box2 = new Box();
alert(box2.family); //受box1的操作影响
//组合构造函数+原型模式
function Box(name, age)
{
this.name = name;
this.age = age;
this.family = ['gg','jj','mm'];
};
Box.prototype = {
constructor:Box,
run:function () {
return this.name + ' ' + this.family;
},
};
var box = new Box();
alert(box.family);
box.family.push('dd'); //添加新的数据
alert(box.family);
var box1 = new Box();
alert(box1.family); //没有改变
这样family并没有被共享.
//动态原型模式
//将原型封装到构造函数里面
function Box(name, age)
{
this.name = name;
this.age = age;
this.family = ['gg','jj','mm'];
//原型初始化开始
Box.prototype.run = function () {
return this.name + ' ' + this.family;
};
//原型初始化结束
};
事实上原型只初始化一次就可以了,所以想办法第一次初始化调用一次就好了.
function Box(name, age)
{
this.name = name;
this.age = age;
this.family = ['gg','jj','mm'];
//这样就只初始化一次,判断run函数是否存在.
if (typeof this.run != 'function'){
Box.prototype.run = function () {
return this.name + ' ' + this.family;
};
}
};
Var box = new Box(‘hg’, 123);
Alert(box.run());
使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。重写原型prototype就将之前的原型给替换了.
//寄生构造模式 = 工厂模式 + 构造函数
function Box(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}
var box = new Box('hg', 123);
alert(box.run());
//稳妥构造函数 不允许使用this和new
在一些安全的环境中,比如禁止使用this 和new,这里的this 是构造函数里不使用this,这里的new 是在外部实例化构造函数时不使用new。这种创建方式叫做稳妥构造函数。
function Box(name , age) {
var obj = new Object();
obj.run = function () {
return name + age + '运行中...'; //直接打印参数即可
};
return obj;
}
var box = Box('Lee', 100); //直接调用函数
alert(box.run());
稳妥构造函数和寄生构造函数很类似.