javascript 面向对象编程之创建对象详解编程语言

创建对象

这部分属于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版)

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/20293.html

(0)
上一篇 2021年7月19日 23:19
下一篇 2021年7月19日 23:19

相关推荐

发表回复

登录后才能评论