黑马程序员技术交流社区

标题: [上海前端]JavaScript中的原型和继承(下) [打印本页]

作者: sh_mwx    时间: 2017-8-25 19:08
标题: [上海前端]JavaScript中的原型和继承(下)
有关函数
  JavaScript 中的函数也是对象。这样的表述带来了几个重要的结果,而我们并不会在本文中涉及所有的事项。这其中,能将一个函数赋值给一个变量,并且将一个函数作为参数传递给另一个函数的能力构成了现代 JavaScript 编程表达的基本范式。
  我们需要关注的是,函数本身就是对象,因此函数可以有自身的方法,属性,并且引用一个原型对象。让我们来讨论下面的代码的含义。
// 这将返回 true:typeof (Array) === "function"// 这样的表达式也是:Object.getPrototypeOf(Array) === Object.getPrototypeOf(function () { })// 这样的表达式同样:Array.prototype != null
  代码中的第一行证明, JavaScript 中的数组是函数。稍后我们将看到如何调用 Array 函数创建一个新的数组对象。下一行代码,证明了 Array 对象使用与任何其他函数对象相同的原型,就像我们看到数组对象间共享相同的原型一样。最后一行代码证明了 Array 函数都有一个 prototype 属性,而这个 prototype 属性指向一个有效的对象。这个 prototype 属性十分重要。
  JavaScript 中的每一个函数对象都有 prototype 属性。千万不要混淆这个 prototype 属性的 __proto__ 属性。他们用途并不相同,也不是指向同一个对象。
// 返回 trueObject.getPrototypeOf(Array) != Array.prototype
  Array.__proto__ 提供的是 数组原型 – 请把它当作 Array 函数所继承的对象。
  而 Array.protoype,提供的的是 所有数组的原型对象。也就是说,它提供的是像 myArray 这样数组对象的原型对象,也包含了所有数组将会继承的方法。我们可以写一些代码来证明这个事实。
// trueArray.prototype == Object.getPrototypeOf(myArray)// 也是 trueArray.prototype == Object.getPrototypeOf(yourArray);
  我们也可以使用这项新知识重绘之前的示意图。
5
  基于所知道的知识,请想象创建一个新的对象,并让新对象表现地像数组的过程。一种方法是使用下面的代码。
// 创建一个新的空对象var o = {};// 继承自同一个原型,一个数组对象o.__proto__ = Array.prototype;// 现在我们可以调用数组的任何方法...o.push(3);
  虽然这段代码很有趣,也能工作,可问题在于,并不是每一个 JavaScript 环境都支持可写的 __proto__ 对象属性。幸运的是,JavaScript 确实有一个创建对象内建的标准机制,只需要一个操作符,就可以创建新对象,并且设置新对象的 __proto__ 引用 – 那就是“new”操作符。
var o = new Array();o.push(3);
  JavaScript 中的 new 操作符有三个基本任务。首先,它创建新的空对象。接下来,它将设置新对象的 __proto__ 属性,以匹配所调用函数的原型属性。最后,操作符调用函数,将新对象作为“this”引用传递。如果要扩展最后两行代码,就会变成如下情况:
var o = {};o.__proto__ = Array.prototype;Array.call(o);o.push(3);
  函数的 call 方法允许你在调用函数的情况下在函数内部指定“this”所引用的对象。当然,函数的作者在这种情况下需要实现这样的函数。一旦作者创建了这样的函数,就可以将其称之为构造函数。
  构造函数
  构造函数和普通的函数一样,但是具有以下两个特殊性质。
  Array 就是一个构造函数的例子。Array 函数需要和 new 操作符一起使用,而且 Array 的首字母是大写的。JavaScript 将 Array 作为内置函数包括在内,而任何人都可以写出自己的构造函数。事实上,我们最后可以为先前创建的点对象编写出构造函数。
var Point = function (x, y) {    this.x = x;    this.y = y;    this.add = function (otherPoint) {        this.x += otherPoint.x;        this.y += otherPoint.y;    }}var p1 = new Point(3, 4);var p2 = new Point(8, 6);p1.add(p2);
  在上面的代码中,我们使用了 new 操作符和 Point 函数来构造点对象,这个对象带有 x 属性和 y 属性和一个 add 方法。你可以将最后的结果想象成图 6 的样子。
6
  现在的问题是我们的每个点对象中仍然有单独的 add 方法。使用我们学到的原型和继承的知识,我们更希望将点对象的 add 方法从每个点实例中转移到 Point.prototype 中。要达到继承 add 方法的效果,我们所需要做的,就是修改 Point.prototype 对象。
var Point = function (x, y) {    this.x = x;    this.y = y;}Point.prototype.add = function (otherPoint) {    this.x += otherPoint.x;    this.y += otherPoint.y;}var p1 = new Point(3, 4);var p2 = new Point(8, 6);p1.add(p2);
  大功告成!我们刚刚在 JavaScript 中完成原型式的继承模式!
7
  总结
  我希望这篇文章能够帮助你揭开 JavaScript 原型概念的神秘面纱。开始看到的是原型怎样让一个对象从其他对象中继承功能,然后看到怎样结合 new 操作符和构造函数来构建对象。这里所提到的,只是开启对象原型力量和灵活性的第一步。本文鼓励你自己发现学习有关原型和 JavaScript 语言的新信息。
  同时,请小心驾驶。你永远不会知道这些行驶在路上的车辆会从他们的原型继承到什么(有缺陷)的技术。

~~~~黑马出品,必属精品~~~






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2