深入理解对象和对象的创建

前面所说,简单的创建对象就是字面量创建和new Object()创建,一个代码的麻烦冗余,一个不像一个整体。所以可以推荐几种方式创建!

1.工厂模式

工厂模式,听起来就是一个工厂加工成自己需要的东西。将创建的对象封装在一个函数中(工厂函数),然后创建一个实例传递参数,就像工厂成批出产一样。

//将创建对象的代码封装在一个函数中
function createPerson(name, age, gender) {
  var person = new Object();
  person.name = name;
  person.age = age;
  person.gender = gender;
  person.sayName = function () {
    console.log(this.name);
  }
  return person;
}
//利用工厂函数来创建对象
var person1 = createPerson("zhangsan", 18, 'male');
var person2 = createPerson("lisa", 20, 'female');

这个缺点也很明显, 工厂函数中直接用person.构造属性,导致了对象类型的单一化。就是说,实例对象时,只能用preson(人)类型的,如果我想用dog(狗)、apple(苹果)等就不适用了。

2.构造函数模式

为了解决工厂模式的缺点,我们研究了一个构造函数模式,自定义构造函数。

// 自定义构造函数
function Person(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayName = function () {
    console.log(this.name);
  }
}

var person1 = new Person('zhangsan', 29, 'male');
var person2 = new Person('lisa', 19, 'female');

person1.sayName(); // zhangsan
person2.sayName(); // lisa

工厂函数的preson.创建属性变成了this.(指向新对象),也没有了return。这时候要用new操作符来创建实例对象了,形成了一个新的对象,也就是this的指向了,解决了工厂模式对象类型单一化缺点。

温馨提醒:任何函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数 如:

Person("lisa", 27, "female"); 
window.sayName(); // lisa

 这个构造函数也存在一定的缺点。如果想要访问sayname属性,多个实例创建后:一、如果在构造函数内部,每个实例都要再次创建sayname属性函数,没有必要;二、如果在构造函数外部,有很多个类型的像sayname的属性函数,容易造成全局混乱和全局污染。

3.原型模式

每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。

function Person() { }
Person.prototype.name = "zhangsan";
Person.prototype.age = 29;
Person.prototype.gender = "male";
Person.prototype.sayName = function () {
  console.log(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "lisa";
console.log(person1.name); // lisa,来自实例
console.log(person2.name); // zhangsan,来自原型

 person1 的 name 属性遮蔽了原型对象上的同名属性,不会修改属性只是在上面盖了一层,覆盖住了。JavaScript 引擎会问:“person2 实例有 sayName 属性吗?”答案是没有。然后,继续搜索并问:“person2 的原型有 sayName 属性吗?”答案是有。于是就返回了保存在原型上的这个函数。 一层层往上找。

原型函数也有一定的缺点,弱化了向构造函数传递初始化参数的能力,会导致所有实例默认都取得相同的属性值 。最大的缺点就是,原型上的所有属性是在实例间共享的,意味着多个实例情况下,只要有一个属性改变了,那其他实例的属性也跟着改变了。

4.组合模式

这个时候啊,人们就会发现,能不能把构造函数和原型函数组合在一起,让代码冗余减少,不造成全局混乱,结构形成一个整体,而且属性共享的同时修改自身属性不影响其他实例,于是就形成了组合模式。

function Person(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.firends = ['zhangsan', 'lisa'];
}
Person.prototype = {
  constructor: Person,
  sayName: function () {
    console.log(this.name);
  }
};
var p1 = new Person('shen', 22, 'male');
var p2 = new Person('kun', 23, 'male');

p1.firends.push('robin');
console.log(p1.firends); // [ 'zhangsan', 'lisa', 'robin' ]
console.log(p2.firends); // [ 'zhangsan', 'lisa' ]
console.log(p1.firends === p2.firends); // false
console.log(p1.sayName === p2.sayName); // true

 构造函数用于定义实例属性,原型模式用于定义方法和共享属性。 就是分工明确,构造函数实例分开,原型创造共享属性,确实不错!!!

总结:虽然组合模式是最好的,但是也不是一定要使用它。在实际情况中,我们可以根据情况使用适合的方法创建对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值