用对象图学习JavaScript(2)

本文介绍JavaScript中构造对象的三种方法:经典构造器、纯原型对象和对象工厂,并对比了各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址 http://howtonode.org/object-graphs-2

第一篇文章用对象图描述JavaScript的语义,很受欢迎。我将继续用对象图描述一些高级的主题。这篇文章主要解释三种构造对象的方法,即原型,纯原型和对象工厂。

我的目标是帮助大家理解每个方法的优劣和真正的机制。

经典JavaScript构造器

首先我们创建一个简单的原型构造器。这个构造器和类比较相似。它是很强大和高效的,但是它和其他由类构造对象的语言完全不同。

function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.getArea = function getArea() {
  return this.width * this.height;
};
Rectangle.prototype.getPerimeter = function getPerimeter() {
  return 2 * (this.width + this.height);
};
Rectangle.prototype.toString = function toString() {
  return this.constructor.name + " a=" + this.getArea() + " p=" + this.getPerimeter();
};
现在我们定义一个新的Squares对象继承Rectangles,为了实现继承,构造器prototype必须从父构造器的prototype继承。这里我们覆盖了getPerimeter函数。

function Square(side) {
  this.width = side;
  this.height = side;
}
// Make Square inherit from Rectangle
Square.prototype = Object.create(Rectangle.prototype, { constructor: { value: Square } });
// Override a method
Square.prototype.getPerimeter = function getPerimeter() {
  return this.width * 4;
};
使用很简单。常见对象实例并调用每个函数。

var rect = new Rectangle(6, 4);
var sqr = new Square(5);
console.log(rect.toString())
console.log(sqr.toString())
输出Rectangle a=24 p=20Square a=25 p=20

下图是数据结构图。虚线表示对象继承。

classical

请注意rect实例和Square.prototype有些许不同。他们都是从Rectangle.prototype派生的简单对象。JavaScript仅仅是一系列链接的对象。唯一特殊的对象是带参数并拥有执行代码的函数对象。

纯原型对象

下面我们给出一些不带构造函数的例子。我们将使用纯原型继承。

定义一个Rectangle原型。

var Rectangle = {
  name: "Rectangle",
  getArea: function getArea() {
    return this.width * this.height;
  },
  getPerimeter: function getPerimeter() {
    return 2 * (this.width + this.height);
  },
  toString: function toString() {
    return this.name + " a=" + this.getArea() + " p=" + this.getPerimeter();
  }
};
接下来定义一个Square子对象覆盖一些属性来改变行为。

var Square = Object.create(Rectangle);
Square.name = "Square";
Square.getArea = function getArea() {
  return this.width * this.width;
};
Square.getPerimeter = function getPerimeter() {
  return this.width * 4;
};
创建其对象很简单,只需要手动设置一些局部状态。

var rect = Object.create(Rectangle);
rect.width = 6;
rect.height = 4;
var square = Object.create(Square);
square.width = 5;
console.log(rect.toString());
console.log(square.toString());

输出Rectangle a=24 p=20Square a=25 p=20

这是对象图。

classical

这种方法通常不如第一个构造器+原型的方法强大,但是它因为指向比较少而很容易理解。而且如果你刚从原型继承的语言转换过来,你会发现JavaScript也可以实现。

对象工厂

创建对象最受欢迎的方法之一是使用工厂函数。区别在于以前使用共享函数产生原型对象再创建这些对象的实例,现在是调用一个函数来返回对象实例。

下面的例子是一个最简单的MVC系统,控制器函数接受model和view对象为参数并产生一个新的控制器对象。所有状态都通过作用域保存在闭包中。

function Controller(model, view) {
  view.update(model.value);
  return {
    up: function onUp(evt) {
      model.value++;
      view.update(model.value);
    },
    down: function onDown(evt) {
      model.value--;
      view.update(model.value);
    },
    save: function onSave(evt) {
      model.save();
      view.close();
    }
  };
}
使用这个控制器,只需要简单传递参数并调用。注意我们可以直接使用它们作为事件处理器(setTimeout)而不需要绑定函数到对象上。

var on = Controller(
  // Inline a mock model
  {
    value: 5,
    save: function save() {
      console.log("Saving value " + this.value + " somewhere");
    }
  },
  // Inline a mock view
  {
    update: function update(newValue) {
      console.log("View now has " + newValue);
    },
    close: function close() {
      console.log("Now hiding view");
    }
  }
);
setTimeout(on.up, 100);
setTimeout(on.down, 200);
setTimeout(on.save, 300);
输出为

// Output
View now has 5
View now has 6
View now has 5
Saving value 5 somewhere
Now hiding view

下面是上面代码的对象图。注意我们从工厂函数产生的闭包中访问到model和view。

factory

结论

我想写很多东西,但是我更想保持这系列文章的短小,如果有需要,我想写写ruby风格的模块和其他高级主题。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值