前端修仙之路-五、JavaScript原型初学者指南(1)

在JavaScript的世界中,万物皆对象。如果不处理对象,您将无法在JavaScript中走得很远。

它们是JavaScript编程语言几乎所有方面的基础。实际上,学习如何创建对象可能是您刚开始学习时首先学习的内容之一。

话虽如此,为了最有效地了解JavaScript原型,我们从基础知识开始。

对象的表现形式是键/值对。创建对象的最常见方法是使用花括号{},然后使用点表示法将属性和方法添加到对象。

let animal = {}
animal.name = 'Leo'
animal.energy = 10

animal.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

animal.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

animal.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

一个简单animal对象就创建完成了,当然还可以继续给它添加属性和方法。

简单来说,现在在我们的程序中,我们将需要创造不止一种动物,猫、狗、大象……。自然,下一步是将该逻辑封装在一个函数中,我们可以在需要创建新动物时调用该逻辑。我们将其称为“功能实例化”  Functional Instantiation,并将函数本身称为“构造函数”,因为它负责“构造”新对象。

功能实例化

function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy

  animal.eat = function (amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  }

  animal.sleep = function (length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  }

  animal.play = function (length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }

  return animal
}

const cat = Animal('Cat', 7)
const dog = Animal('Dog', 10)

现在,每当我们要创建一个新的动物(或者更广泛地说一个新的“实例”),我们所要做的就是调用我们的Animal函数,给它添加名字和能量。

上面的方法简单明了,这很好用,而且非常简单。

但是,您可以发现这种模式有什么缺点吗?

动物都有三种方法- eat(吃饭)sleep(睡觉)play(玩)这些方法中的每一个不仅是动态的,而且是完全通用的。

这意味着没有必要重新创建这些方法,就像我们在创建新动物时所做的那样。我们只是在浪费内存,使每个动物对象都超出其需要。

您能想到解决方案吗?

如果不是每次创建新动物时都重新创建这些方法,而是将它们移到它们自己的对象上,然后让每个动物都引用该对象怎么办?

我们可以称这种模式为共享方法的功能实例化。

共享方法的功能实例化

const animalMethods = {
  eat(amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  },
  sleep(length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  },
  play(length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
}

function Animal (name, energy) {
  let animal = {}
  animal.name = name
  animal.energy = energy
  animal.eat = animalMethods.eat
  animal.sleep = animalMethods.sleep
  animal.play = animalMethods.play

  return animal
}

const cat = Animal('Cat', 7)
const dog = Animal('Dog', 10)

通过将共享方法移动到它们自己的对象并在我们的Animal函数内部引用该对象,我们现在解决了内存浪费和过大的Animal对象的问题。

对象创建

让我们通过使用Object.create再次完善示例。

简而言之,Object.create允许您创建一个对象,该对象将在失败的查找时委派给另一个对象

换句话说,Object.create允许您创建一个对象,并且只要对该对象的属性查找失败,它就可以查询另一个对象以查看该另一个对象是否具有该属性。

话有点多,让我们看一些代码。

const parent = {
  name: 'Stacey',
  age: 35,
  heritage: '一千万'
}

const child = Object.create(parent)
child.name = 'Ryan'
child.age = 7

console.log(child.name) // Ryan
console.log(child.age) // 7
console.log(child.heritage) // 一千万

因此,在上面的示例中,由于child是使用创建的Object.create(parent),因此每当对属性进行失败的查找时child,JavaScript都会将查找委托给该parent对象(找到它的父类)。

这意味着即使child没有heritage财产,就会往上查找parent(父类)child.heritage您将获得parent的遗产“一千万”

现在,Object.create在我们的工具类中,我们如何使用它来简化Animal以前代码?

好吧,与其像现在那样将所有共享方法一一添加到Animal,不如使用Object.create委托给animalMethods对象。

听起来真的很聪明,我们称之为一个共享方法和Object.create的功能实例化。

共享方法和Object.create的功能实例化

const animalMethods = {
  eat(amount) {
    console.log(`${this.name} is eating.`)
    this.energy += amount
  },
  sleep(length) {
    console.log(`${this.name} is sleeping.`)
    this.energy += length
  },
  play(length) {
    console.log(`${this.name} is playing.`)
    this.energy -= length
  }
}

function Animal (name, energy) {
  let animal = Object.create(animalMethods)
  animal.name = name
  animal.energy = energy

  return animal
}

const cat = Animal('Cat', 7)
const dog = Animal('Dog', 10)

cat.eat(10)
dog.play(5)

因此,现在当我们调用时cat.eat,JavaScript将eat在cat对象寻找方法该查找将失败,然后由于Object.create,它将委派给将animalMethods在其中找到对象eat

到现在为止还挺好。我们仍然可以做一些改进。似乎必须要管理一个单独的对象(animalMethods)才能在实例之间共享方法,这只是一点点笨拙 

这似乎是您希望在语言本身中实现的一项常用功能。

事实证明,这就是您在这里的全部原因- prototype(原型)

那么prototype在JavaScript中到底是什么呢?

简而言之,JavaScript中的每个函数都有一个prototype引用对象属性。不相信,对吗?自己测试一下。

function doThing () {}
console.log(doThing.prototype) // {}

如果不是将单独的animalMethods每个对象放在Animal函数的原型上,而不是创建一个单独的对象来管理我们的方法(就像我们正在使用),该怎么办?

然后,我们要做的就是代替使用Object.create委托给animalMethods,而可以使用它委托给Animal.prototype我们称这种模式Prototypal Instantiation(原型实例化)

原型实例化

function Animal (name, energy) {
  let animal = Object.create(Animal.prototype)
  animal.name = name
  animal.energy = energy

  return animal
}

Animal.prototype.eat = function (amount) {
  console.log(`${this.name} is eating.`)
  this.energy += amount
}

Animal.prototype.sleep = function (length) {
  console.log(`${this.name} is sleeping.`)
  this.energy += length
}

Animal.prototype.play = function (length) {
  console.log(`${this.name} is playing.`)
  this.energy -= length
}

const cat = Animal('Cat', 7)
const dog = Animal('dog', 10)

leo.eat(10)
snoop.play(5)

同样,prototype它只是JavaScript中每个函数都具有的属性,并且如我们上面所见,它允许我们在函数的所有实例之间共享方法。我们所有的功能仍然相同,但是现在不必为所有方法管理单独的对象,我们只需使用Animal函数本身内置的另一个对象即可Animal.prototype

这篇就先讲这么多!

原文地址:https://www.cnblogs.com/liao123/p/14269863.html