创建对象方式
第一种模式:工厂方式
// 对象方法。
//对象首个字母可以不大写也不会出错,但是大写就像不成文的规定一样,大家都是按照这种风格来书写的。
var obj = function() {
console.log( "工厂方式创建对象,将方法写在外面避免重复创建,消耗性能。" )
return 2
};
//创建对象
function Parent(){
var Child = new Object();
Child.name = "张三";
Child.age = "30";
//第一个obj指的是对象的属性。第二个obj指的上边定义的变量。
Child.obj = obj;
//必须返回
return Child;
};
var x = Parent();
console.log( x.name );
// 调用对象方法直接打点调用即可。x.obj()。
// 下边会在控制台输出。不写return 2会显示一个undefined,原因是方法没有返回值。
console.log( x.obj() );
console.log( x.age );
一些细节:
1.对象内定义各种属性,属性可以为方法,建议将属性为方法的属性定义到函数之外,这样可以避免重复创建该方法,消耗性能。
2.工厂方式解决了创建多个相似对象的问题,但是没解决对象识别问题(即怎样知道一个对象的类型)。
3.不推荐使用这种方式创建对象。
第二种模式:构造函数方式
var obj = function() {
console.log( "构造函数方式创建对象,this指当前对象(是p也就是Parent)。" );
return 2;
};
function Parent(){
this.name = "张三";
this.age = "30";
this.obj = obj;
};
var p = new Parent();
console.log( p.name );
console.log( p.age );
console.log( p.obj() );
一些细节:
1.使用构造函数方式创建对象,无需再函数内部重建创建对象,而使用this指代,并且函数无需明确return。
2.不推荐使用这种方式创建对象。
第三种模式:原型模式
什么是原型?
我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含有特定类型的所有实例共享的属性和方法。只要创建了一个新函数,就会为该函数创建一个prototype 属性。在默认情况下,所有prototype属性都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。这样,函数及函数原型之间形成了循环指向。
每当调用构造函数创建一个新实例后(即”new constructor()”这样的形式),该实例的内部将包含一个指针(一般名为proto),指向构造函数的原型属性。(console.dir( obj )即可查看)
var obj = function() {
console.log( "原型方式创建对象。" );
return 2;
};
function Parent(){};
Parent.prototype.name = "张三";
Parent.prototype.age = "30";
Parent.prototype.obj = obj;
var p = new Parent();
console.log( p.name );
console.log( p.age );
console.log( p.obj() );
一些细节:
1.函数中不对属性进行定义。
2.利用prototype属性对属性进行定义。
3.不推荐使用这样方式创建对象。
第四种模式:混合的构造函数,原型方式(推荐)
var obj = function() {
// 这里的this指的是p也就是Parent对象,因为obj是Parent的原型方法。
console.log( this.name + "是" + this.age + "岁" );
console.log( "混合构造函数和原型方式创建对象。" );
return 2;
};
function Parent(){
this.name = "张三";
this.age = "30";
};
Parent.prototype.obj = obj;
var p = new Parent();
console.log( p.name );
console.log( p.age );
console.log( p.obj() );
一些细节:
1.该模式是指混合搭配使用构造函数方式和原型方式。
2.将所有不是方法的属性定义在函数中(构造函数方式),将所有属性值为方法的属性利用prototype在函数之外定义(原型方式)
3.推荐使用这样方式创建对象。
4.:好处:通过这种方式,不仅每个实例都有自己的一份实例属性的副本,而且同时又共享着对方法的引用,最大限度的节省了内存。而且这种混合模式还支持向构造函数传递参数,可谓是集两种模式之长。
5.关于基本类型(string,number,boolean,null,undefined)和引用类型(object),或许有助于你理解第4点的好处。
1、复制基本类型:
2、复制引用类型:
一个引用的例子。
即使在函数内部修改了参数的值,但是原始引用不变,实际上。当函数内部重写obj时,这个变量引用就是一个局部对象了。局部对象会在函数执行完毕后销毁。
function setName( obj ) {
obj.name = "liu"
obj = new Object()
obj.name = "yong"
}
var person = new Object()
setName( person )
console.log( person.name )
// liu
第五种模式:动态原型方式
function Parent(){
this.name = "张三";
this.age = "30";
// this.obj = function() {
// return 1;
// }
if( typeof this.obj != "function" ) {
Parent.prototype.obj = function() {
console.log( this.name + "是" + this.age + "岁" );
return 2;
};
};
};
// Parent.prototype.obj = function() {
// return 3;
// }
var p = new Parent();
console.log( p.name );
console.log( p.age );
console.log( p.obj() );
一些细节:
1.动态原型方式可以理解为混合构造函数,原型方式的一个特例。
2.该模式中,为方法的属性直接在函数中进行了定义,但是因为
Parent.prototype.obj = function() {
console.log( this.name + "是" + this.age + "岁" );
return 2;
};
从而保证创建该对象的实例时,属性的方法不会被重复创建。
3.
第六种模式:字面量方式
// 1.字面量方式创建对象。
var Parent = {
// 属性之间用逗号分开。
name: "张三",
age: "30",
show: function () {
console.log( "字面量方式创建" )
return 3;
}
}
console.log(Parent.show())
对象方法
//基类(父类)
function Base( name, age ) {
this.name = name,
this.age = age,
// showInfo()基类对象方法。
this.showInfo = function(){
console.log('姓名:' + this.name + ',年龄' + this.age);
}
}
// showInfos()基类的类方法。(类的静态方法)
Base.showInfos = function() {
console.log('类方法,姓名:' + this.name);
}
// showAge()基类原型方法。(类的实例方法)
Base.prototype.showAge = function() {
console.log('原型方法,年领:' + this.age);
}
一些细节:
1.静态方法不可以被继承,也不能被重写,类加载时便加载了;而实例方法,则在实例化后加载。如果一个方法经常被调用,并且与自身的对象没有什么关系,就用静态方法;如果一个方法在必然使用它的情况下才需要调用,就用实例方法。
2.对象方法包括构造函数中的方法以及构造函数原型上面的方法,如果类生成一个实例,那么该实例就能使用该方法。
3.类方法,不需要通过生成实例就可以使用的方法,其实这里的类就是一个函数,在js中由于函数也是一个对象,所以可以为函数添加属性以及方法,这种方法在node中用的比较多。
4.原型方法一般用于对象实例共享,比如Person.prototype.sayName=function(){console.log(this.name);};在原型上面添加该方法,就能实现共享。这样就不用每一次初始化一个实例的时候,为其分配相应的内存了。