Implementando herencia en JavaScript ES5

1 Prototipos de objetos y funciones.

2 nuevos constructores

3. Orden de búsqueda de la cadena de prototipos.

4 Herencia implementada por cadena prototipo

5 Herencia del constructor prestado

6 La combinación parasitaria implementa la herencia.

Si el nombre creado por la función comienza con una letra mayúscula, entonces no es una función, sino una clase.

¡Presta atención a la distinción! Hay muchas clases de este tipo en este capítulo.

Las instancias tienen prototipos implícitos y las funciones u objetos declarados tienen prototipos explícitos e implícitos. Los prototipos explícitos incluyen constructores y prototipos implícitos. La relación entre cada objeto se muestra a continuación.

Prototipos de objetos comunes.

El prototipo del objeto es el Prototipo de la imagen siguiente, que normalmente está oculto.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    var obj = {
      name: "why",
      age: 18
    }
    console.log(obj)

    var info = {}

    // 获取对象的原型
    console.log(obj.name, obj.age)
    console.log(obj.__proto__)
    console.log(Object.getPrototypeOf(obj))
    console.log(obj.__proto__ === Object.getPrototypeOf(obj)) // true

    // 疑问: 这个原型有什么用呢?
    // 当我们通过[[get]]方式获取一个属性对应的value时
    // 1> 它会优先在自己的对象中查找, 如果找到直接返回
    // 2> 如果没有找到, 那么会在原型对象中查找
    console.log(obj.name)

    // 在原型中添加一个参数,开发时候不建议这样子用
    obj.__proto__.message = "Hello World"
    console.log(obj.message)

  </script>

</body>
</html>

 el prototipo del objeto de función

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    var obj = {}
    function foo() {}

    // 1.将函数看成是一个普通的对象时, 它是具备__proto__(隐式原型)
    // 作用: 查找key对应的value时, 会找到原型身上
    // console.log(obj.__proto__)
    // console.log(foo.__proto__)


    // 2.将函数看成是一个函数时, 它是具备prototype(显式原型)
    // 作用: 用来构建对象时, 给对象设置隐式原型的
    console.log(foo.prototype)
    // console.log(obj.prototype) 对象是没有prototype

  </script>

</body>
</html>

nueva asignación de prototipo de operación

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function Foo() {
      // 1.创建空的对象
      // 2.将Foo的prototype原型(显式隐式)赋值给空的对象的__proto__(隐式原型)
    }

    console.log(Foo.prototype)

    var f1 = new Foo()
    var f2 = new Foo()
    var f3 = new Foo()
    var f4 = new Foo()
    var f5 = new Foo()
    console.log(f1.__proto__)
    console.log(f1.__proto__ === Foo.prototype) // true
    console.log(f3.__proto__ === f5.__proto__) // true

  </script>

</body>
</html>

poner el método en el prototipo 

El papel de la nueva operación es muy importante. Nota: Si hay varias funciones en una función definida y la función se crea mediante nueva, se creará la cantidad de funciones creadas * la cantidad de funciones en la función definida. Muchas de estas funciones se repiten y desperdician espacio, por lo que se utiliza el método del prototipo como solución.

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    /*
    1.什么是函数的显式原型
      * 区分和对象原型区别
    2.函数的原型的作用
      * 在通过new操作创建对象时, 将这个显式原型赋值给创建出来对象的隐式原型
    3.案例Person, 将所有的函数定义放到了显式原型上
    */

    function Student(name, age, sno) {
      this.name = name
      this.age = age
      this.sno = sno

      // 1.方式一: 编写函数, 会创建很多个函数对象
      // this.running = function() {
      //   console.log(this.name + " running")
      // }
      // this.eating = function() {
      //   console.log(this.name + " eating")
      // }
      // this.studying = function() {
      //   console.log(this.name + " studying")
      // }
    }

    // 当我们多个对象拥有共同的值时, 我们可以将它放到构造函数对象的显式原型
    // 由构造函数创建出来的所有对象, 都会共享这些属性
    Student.prototype.running = function() {
      console.log(this.name + " running")
    }
    Student.prototype.eating = function() {
      console.log(this.name + " eating")
    }

    // 1.创建三个学生
    var stu1 = new Student("why", 18, 111)
    var stu2 = new Student("kobe", 30, 112)
    var stu3 = new Student("james", 18, 111)

    // 隐式原型的作用
    // 1> stu1的隐式原型是谁? Student.prototype对象
    // 2> stu1.running查找:
    //  * 先在自己身上查找, 没有找到
    //  * 去原型去查找
    stu1.running()
    stu2.eating()

  </script>

</body>
</html>

propiedades en prototipos explícitos

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 非常重要的属性: constructor, 指向Person函数对象
    function Person() {

    }

    // 1.对constructor在prototype上的验证
    var PersonPrototype = Person.prototype
    console.log(PersonPrototype)
    console.log(PersonPrototype.constructor)
    console.log(PersonPrototype.constructor === Person)

    console.log(Person.name)
    console.log(PersonPrototype.constructor.name)

    // 2.实例对象p
    var p = new Person()
    console.log(p.__proto__.constructor)
    console.log(p.__proto__.constructor.name)

  </script>

</body>
</html>

Cree memoria de proceso de objetos, consulte ppt para ver el diagrama de memoria específico

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function Person(name, age) {
      this.name = name
      this.age = age
    }

    Person.prototype.running = function() {
      console.log("running~")
    }

    var p1 = new Person("why", 18)
    var p2 = new Person("kobe", 30)

    // 进行操作
    console.log(p1.name)
    console.log(p2.name)

    p1.running()
    p2.running()

    // 新增属性
    Person.prototype.address = "中国"
    p1.__proto__.info = "中国很美丽!"

    p1.height = 1.88
    p2.isAdmin = true

    // 获取属性
    console.log(p1.address)
    console.log(p2.isAdmin)
    console.log(p1.isAdmin)
    console.log(p2.info)

    // 修改address
    p1.address = "广州市"
    console.log(p2.address)

  </script>

</body>
</html>

anular el objeto prototipo de función

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function Person() {

    }

    console.log(Person.prototype)
    
    // 在原有的原型对象上添加新的属性
    // Person.prototype.message = "Hello Person"
    // Person.prototype.info = { name: "哈哈哈", age: 30 }
    // Person.prototype.running = function() {}
    // Person.prototype.eating = function() {}

    // console.log(Person.prototype)
    // console.log(Object.keys(Person.prototype))

    // 直接赋值一个新的原型对象,把原来的替换掉
    Person.prototype = {
      message: "Hello Person",
      info: { name: "哈哈哈", age: 30 },
      running: function() {},
      eating: function() {},
      // 加上constructor就和原本的原型差不多一样了
      // 但是原来的constructor是不可枚举的Object.keys枚举不到,所以还得改不可枚举
      // constructor: Person
    }
    // 通过下面对象属性描述符来给原型添加对应的constructor
    Object.defineProperty(Person.prototype, "constructor", {
      enumerable: false,
      configurable: true,
      writable: true,
      value: Person
    })

    console.log(Object.keys(Person.prototype))

    // 新建实例对象
    var p1 = new Person()
    console.log(p1.message)

  </script>

</body>
</html>

IMPORTANTE: la cadena prototipo del objeto.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 1.{}的本质
    // var info = {}
    // 相当于
    // var info = new Object()
    // console.log(info.__proto__ === Object.prototype)

    // 2.原型链
    var obj = {
      name: "why",
      age: 18
    }

    // 查找顺序
    // 1.obj上面查找
    // 2.obj.__proto__上面查找
    // 3.obj.__proto__.__proto__ -> null 上面查找(undefined)
    // console.log(obj.message)


    // 3.对现有代码进行改造
    obj.__proto__ = {
      // message: "Hello aaa"
    }

    obj.__proto__.__proto__ = {
      message: "Hello bbbb"
    }

    obj.__proto__.__proto__.__proto__ = {
      message: "Hello ccc"
    }

    console.log(obj.message)

  </script>

</body>
</html>

Herencia de métodos de implementación de cadena de prototipos.

De lo que estoy hablando aquí es de cómo hacer que la función de estudiante no se encuentre en sus propias propiedades ni en el prototipo. Encuentre una manera de pedir a los estudiantes que encuentren los atributos requeridos en el prototipo de la función persona.

Método incorrecto uno: entregar el prototipo de la clase principal directamente a la clase secundaria (no hagas esto)

 Método 2: No recomendado, porque hay muchos problemas, depende de los atributos de la función principal y los atributos creados por varias instancias se compartirán.

 El método 3 toma prestada la herencia de atributos del constructor y analiza el código del siguiente título.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 定义Person构造函数(类)
    function Person(name, age, height, address) {
      this.name = name
      this.age = age
      this.height = height
      this.address = address
    }

    Person.prototype.running = function() {
      console.log("running~")
    }
    Person.prototype.eating = function() {
      console.log("eating~")
    }

    // 定义学生类
    function Student(name, age, height, address, sno, score) {
      this.name = name
      this.age = age
      this.height = height
      this.address = address

      this.sno = sno
      this.score = score
    }

    // 方式一: 父类的原型直接赋值给子类的原型
    // 缺点: 父类和子类共享通一个原型对象, 修改了任意一个, 另外一个也被修改
    // Student.prototype = Person.prototype

    // 方式二: 创建一个父类的实例对象(new Person()), 用这个实例对象来作为子类的原型对象
    var p = new Person("why", 18)
    Student.prototype = p

    // Student.prototype.running = function() {
    //   console.log("running~")
    // }
    // Student.prototype.eating = function() {
    //   console.log("eating~")
    // }
    Student.prototype.studying = function() {
      console.log("studying~")
    }

    // 创建学生
    var stu1 = new Student("kobe", 30, 111, 100)
    var stu2 = new Student("james", 25, 111, 100)
    stu1.running()
    stu1.studying()

    console.log(stu1.name, stu1.age)
    console.log(stu1)
    console.log(stu2.name, stu2.age)


  </script>

</body>
</html>

Herencia de propiedad del constructor prestado: importante

Todavía hay desventajas,

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 定义Person构造函数(类)
    function Person(name, age, height, address) {
      this.name = name
      this.age = age
      this.height = height
      this.address = address
    }

    Person.prototype.running = function() {
      console.log("running~")
    }
    Person.prototype.eating = function() {
      console.log("eating~")
    }

    // 定义学生类
    function Student(name, age, height, address, sno, score) {
      // 重点: 借用构造函数
      Person.call(this, name, age, height, address)
      // this.name = name
      // this.age = age
      // this.height = height
      // this.address = address

      this.sno = sno
      this.score = score
    }

    // 方式一: 父类的原型直接赋值给子类的原型
    // 缺点: 父类和子类共享通一个原型对象, 修改了任意一个, 另外一个也被修改
    // Student.prototype = Person.prototype

    // 方式二: 创建一个父类的实例对象(new Person()), 用这个实例对象来作为子类的原型对象
    var p = new Person("why", 18)
    Student.prototype = p

    // Student.prototype.running = function() {
    //   console.log("running~")
    // }
    // Student.prototype.eating = function() {
    //   console.log("eating~")
    // }
    Student.prototype.studying = function() {
      console.log("studying~")
    }

    // 创建学生
    var stu1 = new Student("kobe", 30, 111, 100)
    var stu2 = new Student("james", 25, 111, 100)
    stu1.running()
    stu1.studying()

    console.log(stu1.name, stu1.age)
    console.log(stu1)
    console.log(stu2.name, stu2.age)


  </script>

</body>
</html>

Cómo crear un objeto prototipo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 工具函数
    // 创建对象的过程
    function createObject(o) {
      function F() {}
      F.prototype = o
      return new F()
    }

    // 将Subtype和Supertype联系在一起
    // 寄生式函数
    function inherit(Subtype, Supertype) {
      Subtype.prototype = createObject(Supertype.prototype)
      Object.defineProperty(Subtype.prototype, "constructor", {
        enumerable: false,
        configurable: true,
        writable: true,
        value: Subtype
      })
    }

    /*
    满足什么条件:
      1.必须创建出来一个对象
      2.这个对象的隐式原型必须指向父类的显式原型
      3.将这个对象赋值给子类的显式原型
    */
    function Person(name, age, height) {}
    function Student() {}

    inherit(Student, Person)
    
    // 1.之前的做法: 但是不想要这种做法
    // var p = new Person()
    // Student.prototype = p

    // 2.方案一:
    var obj = {}
    // obj.__proto__ = Person.prototype
    Object.setPrototypeOf(obj, Person.prototype)
    Student.prototype = Person.prototype

    // 3.方案二:
    // function F() {}
    // F.prototype = Person.prototype
    // Student.prototype = new F()

    // 4.方案三:
    var obj = Object.create(Person.prototype)
    console.log(obj.__proto__ === Person.prototype)
    Student.prototype = obj

  </script>

</body>
</html>

Cómo redactar el plan de herencia final

Cree un archivo de herramienta hered_utils.js con el siguiente contenido:

// 创建对象的过程
function createObject(o) {
  function F() {}
  F.prototype = o
  return new F()
}

// 将Subtype和Supertype联系在一起
// 寄生式函数
function inherit(Subtype, Supertype) {
  // Subtype.prototype.__proto__ = Supertype.prototype
  // Object.setPrototypeOf(Subtype.prototype, Subtype.prototype)
  Subtype.prototype = createObject(Supertype.prototype)
  Object.defineProperty(Subtype.prototype, "constructor", {
    enumerable: false,
    configurable: true,
    writable: true,
    value: Subtype
  })
  Object.setPrototypeOf(Subtype, Supertype)
  // Subtype.__proto__ = Supertype
}

Introducir herramientas donde realmente se utilizan:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script src="./js/inherit_utils.js"></script>
  <script>
    // 寄生组合式继承
    // 原型链/借用/原型式(对象之间)/寄生式函数
    function Person(name, age, height) {
      this.name = name
      this.age = age
      this.height = height
    }

    Person.prototype.running = function() {
      console.log("running~")
    }
    Person.prototype.eating = function() {
      console.log("eating~")
    }


    function Student(name, age, height, sno, score) {
      Person.call(this, name, age, height)
      this.sno = sno
      this.score = score
    }

    inherit(Student, Person)
    Student.prototype.studying = function() {
      console.log("studying")
    }

    // 创建实例对象
    var stu1 = new Student("why", 18, 1.88, 111, 100)

  </script>

</body>
</html>

ES5-Prototipo-Esquema de herencia parasitaria

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 对象之间的继承
    // 默认的对象
    var obj = {
      name: "why",
      age: 18
    }

    // 原型式继承
    function createObject(o) {
      function F() {}
      F.prototype = o
      return new F()
    }

    // 寄生式函数
    function createInfo(o, name, age, height, address) {
      var newObj = createObject(o)
      newObj.name = name
      newObj.age = age
      newObj.height = height
      newObj.address = address
      
      return newObj
    }

    // 创建另外一个对象, 这个对象可以继承自obj
    // var info1 = createObject(obj)  
    // info1.height = 1.88
    // info1.address = "广州市"

    // var info2 = createObject(obj)  
    // info1.height = 1.88
    // info1.address = "广州市"

    // var info3 = createObject(obj)  
    // info1.height = 1.88
    // info1.address = "广州市"

    // 创建一系列对象
    var info1 = createInfo(obj, "why", 18, 1.88, "广州市")
    var info2 = createInfo(obj, "kobe", 30, 1.98, "洛杉矶市")

  </script>

</body>
</html>

 ES5-Object es la clase padre de otras clases

Es decir, siempre que sea de tipo objeto, puedes llamar a las funciones en Objeto.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script src="./js/inherit_utils.js"></script>
  <script>

    function Person() {}
    function Student() {}
    function Teacher() {}

    inherit(Student, Person)
    console.log(Person.prototype.__proto__ === Object.prototype)

    // 在Object的原型上添加属性
    Object.prototype.message = "coderwhy"
    var stu = new Student()
    console.log(stu.message)

    // Object原型上本来就已经存放一些方法
    console.log(Object.prototype)
    console.log(stu.toString())

    // 函数对象也是最终继承自Object
    function foo() {}
    console.log(foo.message)

  </script>

</body>
</html>

Suplemento del método de juicio de objetos ES5

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script src="./js/inherit_utils.js"></script>
  <script>

    var obj = {
      name: "why",
      age: 18
    }

    var info = createObject(obj)
    info.address = "中国"
    info.intro = "中国大好河山"

    console.log(info.name, info.address)
    console.log(info)

    // 1.hasOwnProperty
    // console.log(info.hasOwnProperty("name")) // false
    // console.log(info.hasOwnProperty("address")) // true

    // 2.in操作符
    console.log("name" in info)
    console.log("address" in info)
    // 注意: for in遍历不仅仅是自己对象上的内容, 也包括原型对象上的内容
    for (var key in info) {
      console.log(key)
    }

    // 3.instanceof
    // instanceof用于判断对象和类(构造函数)之间的关系
    function Person() {}
    function Student() {}
    inherit(Student, Person)

    // stu实例(instance)对象
    var stu = new Student()
    console.log(stu instanceof Student)
    console.log(stu instanceof Person)
    console.log(stu instanceof Object)
    console.log(stu instanceof Array)

    // 4.isPrototypeOf
    console.log(Student.prototype.isPrototypeOf(stu))
    console.log(Person.prototype.isPrototypeOf(stu))
    
    // 可以用于判断对象之间的继承
    console.log(obj.isPrototypeOf(info))

  </script>

</body>
</html>

ES5 - Método de clase para constructor 

Los métodos agregados al prototipo se denominan métodos de instancia y los métodos agregados a la clase se denominan métodos de clase.

Los métodos de instancia no se pueden usar sin crear una instancia, pero se pueden usar métodos de clase.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // var obj = {
    //   friend: {
    //     play: function() {
    //       console.log("play~")
    //     }
    //   }
    // }

    // obj.play()

    function Person(name, age) {
      this.name = name
      this.age = age
    }

    Person.totalCounter = "70亿"

    // 添加Person原型上的方法也成为 实例方法
    Person.prototype.running = function() {
      console.log(this.name + "running~")
    }
    Person.prototype.eating = function() {
      console.log("eating~")
    }

    // 添加Person对象本身的方法成为 类方法
    var names = ["abc", "cba", "nba", "mba"]
    Person.randomPerson = function() {
      var randomName = names[Math.floor(Math.random() * names.length)]
      return new Person(randomName, Math.floor(Math.random() * 100))
    }

    // 实例对象
    var p1 = new Person("why", 18)
    var p2 = new Person("kobe", 30)
    p1.running()

    // 没有实例对象的情况下, 能不能调用函数? 不可以调用
    var p = Person.randomPerson()
    console.log(p)

  </script>

</body>
</html>

 

 

 

 

 

 

 

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_56663198/article/details/131487782
Recomendado
Clasificación