javascript 面向对象编程之创建对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangjun5159/article/details/80587612

创建对象

这部分属于JavaScript的面向对象编程,探讨如何更好的创建对象。在java中有类的概念,用new就可以创建对象, 但JavaScript没有类,所以也就无法创建某一类对象,但是可以利用一些技巧达到创建对象的目的。以下所说的各种模式是循序渐进的,如果理解了,记住各种方式也不是难事。


最原始的方式

var person = new Object();
person.name="jun";
person.age=12;
person.sayName=function (){
    console.log(this.name);
}

以上是最原始、最简单的创建对象的方法,但是它有一个缺点,就是代码重复,如果再创建一个person,就需要再次敲上述语句,这就是典型的代码重复,那直接的解决方案就是将上述语句放在一个方法中,这就是工厂模式了。


工厂模式

//工厂模式,缺点无法判断类型
function createPerson(name,age){
    var a = new Object();
    a.name=name;
    a.age=age;
    a.sayName=function  (){
        console.log(this.name);
    }
    return a; 
}
var p1 = createPerson("jun",20);
var p2 = createPerson("chun",18);
console.log(p1 instanceof Object);//true
console.log(p2 instanceof Object);//true

工厂模式实现了代码封装,它的缺点是不能判断对象类型,创建的对象都是Object类型,为了解决这个问题,就需要构造函数模式了。


构造函数模式

//构造函数模式
function Person(name,age){
    this.name=name;
    this.age=age;
    this.sayName=function(){
        console.log(this.name);
    }
}


var p3 = new Person("jack",40);
var p4 = new Person("jordan",50);
console.log(p3 instanceof Person);//true
console.log(p4 instanceof Person);//true
console.log(p3.sayName==p4.sayName);//false

构造函数模式创建的对象可以判断出类型,它的缺点是每个实例都要创建一个新的function。我们都知道在js中函数也是对象,上述代码中this.sayName=function(){} 就等同于this.sayName=new Function("") 所以每个实例都会创建一个新的函数,这就造成了实例之间的函数不相等。为了fix这个问题,自然而然的想到将函数拿到构造函数之外。

function Person(name,age){
    this.name=name;
    this.age=age;
    this.sayName=sayName;
}

function sayName(){
        console.log(this.name);
}

var p3 = new Person("jack",40);
var p4 = new Person("jordan",50);
console.log(p3.sayName==p4.sayName);//true

这样函数相等的目的达到了,但是可访问性增大,污染了全局环境,破坏了封装性,为了修正这个问题就想到将函数放在原型上,所有的实例就可以共享了。


原型模式

我们知道函数都有一个prototype属性指向它的原型,所有的实例都可以共享原型的属性、方法。将方法定义在函数的原型上,就能避免函数的重复创建。

function Person(){

}

Person.prototype.sayName=function (){
        console.log(this.name);
}
Person.prototype.name="jun";

var p3 = new Person();
var p4 = new Person();
console.log(p3.name);//jun
console.log(p4.name);//jun
console.log(p3.sayName==p4.sayName);//true

函数共享了,但是实例属性也共享了。到这里读者可以思考了,构造函数模式分离了属性、函数,原型模式共享了属性、函数,如果能结合一下构造函数分离属性,原型模式共享函数该多好,这就是原型+构造函数模式。


原型+构造函数混合模式

function Person(name,age){
    this.name=name;
    this.age=age;
}

Person.prototype.sayName=function (){
        console.log(this.name);
}


var p3 = new Person("jack",40);
var p4 = new Person("jordan",50);
console.log(p3.name);//jack
console.log(p4.name);//jordan
console.log(p3.sayName==p4.sayName);//true

这个模式还是有个缺点!^_^ 函数放在外边破坏了封装性,所以就有了

function Person(name,age){
    this.name=name;
    this.age=age;
    if(typeof this.sayName!="function"){
        Person.prototype.sayName=function (){
                console.log(this.name);
        }
    }
}

这种事业界内最推崇、最成熟的创建对象方式了。

寄生构造函数模式

修改原型以扩展方法虽然方便但也带来了缺点,比如String没有startsWith方法,我们会通过扩展原型来实现

String.prototype.startsWith=function(){
    //do something
}

但是你有没有想到,未来的js版本可能会实现这个方法,到那时js版本带的方法就跟扩展的方法冲突了,为了解决这个问题,就产生了寄生构造函数模式。
比如我们想创建一个新的Array,它有原生Array没有的方法

function SpecialArray(){
    var x = new Array();
    x.push.apply(x,arguments);
    x.pipedStr=function(){
        console.log(x.join("|"));
    }
    return x;
}

var xx = new SpecialArray("a","b","c");
xx.pipedStr();

我们可以看到寄生构造函数模式跟工厂模式基本一样,为了使用起来像创建新类型一样,用new创建对象

稳妥构造函数模式

有时我们不像让外界修改对象的值,怎么实现呢?只提供访问的方法,不提供修改的方法就可以了!因为值不能改变,是稳定的、可靠的,所以就叫稳妥方式。

function Person(name){
    var x = new Object();
    x.sayName=function(){
        console.log(name);
    }
    return x;
}

var y = Person("jun");
y.sayName();

注意,这里并没有使用new。

总结

以上所有的模式除了最后两种,都可以一步步推倒出来,循序渐进的演变过来的,所以,不用死记硬背。

参考

JavaScript高级程序设计(第2版)

猜你喜欢

转载自blog.csdn.net/wangjun5159/article/details/80587612