深入学习js之——创建对象的各种方式以及优缺点 #12

栏目: JavaScript · 发布时间: 6年前

内容简介:深入学习js系列是自己阶段性成长的见证,希望通过文章的形式更加严谨、客观地梳理js的相关知识,也希望能够帮助更多的前端开发的朋友解决问题,期待我们的共同进步。如果觉得本系列不错,欢迎点赞、评论、转发,您的支持就是我坚持的最大动力。这篇文章将的是创建对象的优缺点以及各种方式。

深入学习js系列是自己阶段性成长的见证,希望通过文章的形式更加严谨、客观地梳理js的相关知识,也希望能够帮助更多的前端开发的朋友解决问题,期待我们的共同进步。

如果觉得本系列不错,欢迎点赞、评论、转发,您的支持就是我坚持的最大动力。

写在前面

这篇文章将的是创建对象的优缺点以及各种方式。

但是注意:

这篇文章更像是笔记,因为《JavaScript 高级程序设计》写的真是太好了!

1、工厂模式

function createPerson(name) {
  var o = new Object();
  o.name = name;
  o.getName = function() {
    console.log(this.name);
  };

  return o;
}

var person1 = createPerson('kevin');
复制代码

缺点:对象无法识别,因为所有的实例都指向一个原型

2、构造函数模式

function Person(name){
    this.name = name;
    this.getName = function(){
      console.log(this.name);
    }
  }
  var person1 = new Person('kevin')
复制代码

优点: 实例可以识别一个特定的类型 缺点:每次创建实例的时候,每个方法都要被创建一次

2.1 构造函数模式优化

function Person(name){
    this.name = name;
    this.getName = getName;
  }

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

  var person1 = new Person('kevin');
复制代码

优点:解决了每个方法都要被重新创建的问题 缺点:这叫啥封装?

3.原型模式

function Person(name) {

  }

  Person.prototype.name = 'kevin';
  Person.prototype.getName = function() {
    console.log(this.name);
  }

  var person1 = new Person();
复制代码

优点: 方法不会被重新创建 缺点: 1、所有的属性和方法都共享,2、不能初始化参数

3.1 原型模式优化

function Person(name){

  }
  Person.prototype = {
    name:'kevin',
    getName:function(){
      console.log(this.name);
    }
  }
  var person1 = new Person();
复制代码

优点: 封装性好了一些 缺点: 重写了原型,丢失了contructor 属性

3.2 原型模式优化

function Person(name){

  }
  Person.prototype = {
    constructor : Person,
    name: 'kevin',
    getName: function(){
      console.log(this.name)
    }
  }
  var person1 = new Preson();
复制代码

优点:实例可以通过contructor属性找到所属于的构造函数 缺点:原型模式该有的全缺点还是有。

4.组合模式

构造函数模式和 原型模式的双剑合璧。

function Person(name){
    this.name = name;
  }
  Person.prototype = {
    constructor: Person,
    getName: function(){
      console.log(this.name)
    }
  }

  var person1 = new Person();
复制代码

优点:应该共享的共享,该私有的私有,使用最广泛的方式 缺点:有的人就是希望全部写在一起,即拥有更好的封装性

4.1 动态原型模式

function Perosn(name) {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype.getName = function() {
      console.log(this.name);
    };
  }
}

var person1 = new Person();
复制代码

注意: 使用动态原型模式时,不能用对象字面量重写原型

解释下为什么:

function Person() {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype = {
      constructor: Person,
      getName: function() {
        console.log(this.name);
      }
    };
  }
}

var person1 = new Person("kevin");
var person2 = new Person("daisy");

// 报错 并没有该方法
person1.getName();
// 注释掉上面的代码。这句是可以执行的。
person2.getName();
复制代码

为了解释这个问题,假设开始执行 var person1 = new Person('kevin') . 如果对 new 和 apply 的底层执行不是很熟悉,可以阅读关于系列的相关的文章。

我们回顾一下 new 的操作步骤:

1、首先创建一个对象
2、然后将对象的原型指向 Person.prototype
3、然后 Person.apply(obj)
4、返回这个对象
复制代码

注意这个时候,回顾下 apply 的实现步骤,会执行 obj.Person 方法 ,这个时候就会执行 if 语句里面的 内容,注意构造函数的 prototype 属性指向了实例的原型,使用字面量方式直接覆盖 Person.prototype, 并不会更改实例的原型的值,person1 仍然是指向了以前的原型,而不是 Person.prototype,而之前原型是没有 getName 方法的,所以就报错了。

如果你就是想用字面量方式写代码,可以尝试使用这种方法:

function Person() {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype = {
      constructor: Person,
      getName: function() {
        console.log(this.name);
      }
    };
    return Person(name);
  }
}

var person1 = new Person("kevin");
var person2 = new Person("dsisy");

person1.getName(); // kevin
person2.getName(); // daisy
复制代码

5.1 寄生构造函数模式

function Person(name) {
  var o = new Object();
  o.name = name;
  o.getName = function() {
    console.log(this.name);
  };
  return o;
}

var person1 = new Person("kevin");

console.log(person1 instanceof Person); // false
console.log(person2 instanceof Object); // true
复制代码

寄生构造函数模式,我个人认为应该这样读:

寄生—构造函数-模式,也就是说寄生发生在构造函数的一种方法。

也就是说打着构造函数的幌子挂羊头卖狗肉,你看创建实例使用的是 instanceof 都无法指向构造函数!

这样的方法可以自特殊的情况下使用,比如我们想创建一个具有额外方法的特殊数组,但是又不想直接修改 Array 的构造函数,我们可以这样写:

function SpeciaArray(){
    var values = new Array();

    for(var i = 0;len = arguments.length;i<len;i++){
      values.push(arguments[i])
    }

    values.toPipString = function(){
      return this.join('|');
    };
    return values;
  }
  var colors = new SpecialArray('red', 'blue', 'green');
  var colors2 = SpecialArray('red2', 'blue2', 'green2');

  console.log(colors);
  console.log(colors.toPipedString()); // red|blue|green

  console.log(colors2);
  console.log(colors2.toPipedString()); // red2|blue2|green2
复制代码

你会发现,其实所谓的寄生构造函数模式就是比工厂模式在创建对象的时候,多使用了一个 new,实际上两者的结果是一样的。

但是作者可能是希望能像使用普通 Array 一样使用 SpecialArray,虽然把 SpecialArray 当成函数也一样能用,但是这并不是作者的本意,也变得不优雅。

在可以使用其他模式的情况下,不要使用这种模式。

但是值得一提的是,上面例子中的循环:

for (var i = 0, len = arguments.length; i < len; i++) {
  values.push(arguments[i]);
}
复制代码

可以替换成:

values.push.apply(values, arguments);
复制代码

5.2 稳妥构造函数模式

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

var person1 = person("kevin");

person1.sayName(); // kevin

person1.name = "daisy";

person1.sayName(); // kevin

console.log(person1.name); // daisy
复制代码

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用 this 的对象。

与寄生构造函数模式有两点不同:

新创建的实例方法不引用 this 不使用 new 操作符调用构造函数 稳妥对象最适合在一些安全的环境中。

稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型。

欢迎关注我的个人微信公众号——指尖的宇宙,更多优质思考干货


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Computer Science Using Python

Introduction to Computer Science Using Python

Dierbach, Charles / 2012-12 / $ 133.62

Introduction to Computer Science Using Python: A Computational Problem-Solving Focus introduces students to programming and computational problem-solving via a back-to-basics, step-by-step, objects-la......一起来看看 《Introduction to Computer Science Using Python》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具