javascript——百变创建对象

首先一看到创建对象,马上想到的就是对象字面量创建对象 var obj = {}; 或者使用Object构造函数创建对象,var obj = new Object();  没错。但是为什么还要讲创建对象呢?因为这个两种方式虽然能够创建对象,但是,当我们创建对象很多地方相同怎么办,这会产生很多重复代码,一想到重复代码,脑子就应该浮现的解决办法:函数!

这里一共有7中创建对象的模式:

  • 工程模式
  • 构造函数模式
  • 原型模式
  • 组合使用构造函数模式和原型模式
  • 动态原型模式
  • 寄生构造函数模式
  • 稳妥构造函数模式

这么多,到底怎么个表现形式,下面来一一举例说明:

工厂模式:

其实工厂模式,就是利用函数来进行代码的封装

function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        console.log(this.name);
     };
     return o;
 }

var person1 = createPerson('Jack', 27, 'doctor');

很明显,这样也就创建了一个对象,而且我们可以多次创建,使用不同的参数。这样也就解决了我们想多次相似对象的问题。但是问题来了,这样的方式,创建的对象多了,我们怎么知道哪个对象是由哪个构造函数创建的呢?也就是我们说的怎么知道一个对象的类型。构造函数模式来了~

构造函数模式:

这个我们都好理解,也见过,构造函数,原生的构造函数就有Object,对吧就像祖宗,还有Array等。那创建自定义构造函数呢

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    };
}
var person2 = new Person('Pibi', 22, 'student');

这里与上面不同的是:1、没有显示的创建对象,2、直接将属性和方法赋值给this对象,3、没有return语句。而且我们最后创建对象使用的是new关键字,这个过程发生了什么呢?按照惯例也为了区分,构造函数首字母都用大写。

通过new关键字调用Person函数,实际上经历了以下四个步骤:

  1. 创建新对象; var obj = {};  形象一点
  2. 将构造函数的作用域赋给新对象(也就是this指向obj)
  3. 执行构造函数代码,也就是obj添加了name,age,job属性和sayName方法
  4. 最后返回新对象,也就是说,上面person2保存了这个返回对象的引用

我们检测对象的类型,person2是Person的实例,当然也是Object的实例,毕竟祖宗嘛。

当然我们的构造函数也可以当做普通函数调用,也就是不用new关键字,不过这个时候this对象,在浏览器中的话就是window对象了。

var person = Person('Jack', 22, 'student'); //普通函数调用

Person函数没有返回值,当然person也就是undefined,this对象指向window,所以window对象可以调用

关于不使用new关键字调用函数,this指向window问题。我们来想想解决办法,创建作用域安全的构造函数:

function Person(name, age, job) {
    if (this instanceof Person) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function () {
            console.log(this.name);
        };
    } else {
        return new Person(name, age, job);
    }
    
}

通过一个判断,来判断this是否是Person的实例来实现。无论是否使用new关键字,这样我们都能够得到一个Person新实例这样也就避免了在全局对象上意外设置属性。

有利有弊,构造函数的缺点就是,对于像上面同样的方法sayName,多个对象我们得创建多次,每次还不是一样。怎么办呢?可以单独抽出来。

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

最后上面的this.sayName = sayName; 这样就可以了。多个对象就是同一个函数了。新问题出现,这样得定义多少个全局函数呀~,而且这个全局函数仅仅是被指定的对象调用。

原型模式:

function PersonThird() {
    
}
PersonThird.prototype.name = 'Jony';
PersonThird.prototype.age = 23;
PersonThird.prototype.job = 'doctor';
PersonThird.prototype.sayName = function () {
    console.log(this.name);
};

var person3 = new PersonThird();
console.log(person3.sayName());

这样就完美了,直接在原型对象上面创建对象实例姚公用的方法属性。原型不理解的可以看看在下这篇文章。

但是虽然对象实例可以访问原型的东西,但是却不能重写,毕竟作用域链的访问就是,如果对象实例定义了name。那么访问的就是自己的name。其它对象没定义,仍然是原型对象的name。hasOwnProperty()判断是否是自己的属性,而不是原型的。for in 单独使用就是 'name' in person2 返回true 意思就是只要能够访问到,就为true。

这个原型对象的创建方式就很神奇了,不仅我们可以自定义这样创建,其实就连所有原生的引用类型,都是采用这种模式创建的。比如Object、Array、String 等 。

虽然可以修改原生对象的原型,但是这样做不好,导致冲突等等。

这个方式的缺点:好的一面可能带来坏的一面。正因为共享,对于包含引用类型的属性,就会发生问题。实例对象都会受到音音响,因为都是一样的。

组合使用构造函数模式和原型模式:

function ComplexPerson(name, age, job) {
    this.name = name;
    this.age = name;
    this.job = job;
}
ComplexPerson.prototype = {
    constructor: ComplexPerson,
    sayName: function () {
        console.log(this.name);
    }
}
var person4 = new ComplexPerson('Cassie', 12, 'student');
console.log(person4);

集构造函数模式和原型模式为一体,公认比较好的模式。

动态原型模式:

function DynamicPerson(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    if (typeof this.sayName !== 'function') {
        DynamicPerson.prototype.sayName = function () {
            console.log(this.name);
        };
    }
}
var person5 = new DynamicPerson('personFive', 33, 'free');

也就是判断一下。

寄生构造函数模式

返回的对象和构造函数或者构造函数的原型属性没关系,不能依赖instanceof来检测,不建议使用

稳妥构造函数模式

不用new,不用this保证封闭。

终于写完了,也方便日后自己的复习和理解,希望能有一点点的帮助吧。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值