zoukankan      html  css  js  c++  java
  • 2020年了,别再重复学习原型了

    前置

    原型是 JavaScript 巧妙的设计,它非常容易理解。都 2020 年了,看完这篇希望你以后不需要再重复学习 JavaScript 原型了。如有不当之处,恳请指点一二!

    单词

    下面是相关单词及其翻译,牢牢记住它们就成功一半了。

    • constructor 构造器
    • proto & prototype 原型;雏形;最初形态

    constructor

    function Drink() {}
    
    const a = new Drink()
    console.log(a.constructor) // ƒ Drink() {}
    

    a 是由函数 Drink 构造而来的。

    prototype

    简单写点代码,后面全是 console.log

    function f() {
      this.a = 1
      this.b = 2
    }
    
    const o = new f()
    f.prototype.b = 3
    f.prototype.c = 4
    

    o 是 new f() 返回的结果,不妨回顾一下当执行 new f() 时, new 操作符对函数 f 做了些什么事。

    1. 创建一个空对象(即{}): var obj = Object.create(null)
    2. 链接该对象(即设置该对象的构造函数)到另一个对象(本函数), 这个空对象继承其原型: obj.__proto__ = f.prototype
    3. 使用指定的参数调用函数 f,new Foo 等同于 new Foo(),也就是 f 不带任何参数调用的情况; 将步骤 1 创建的对象作为 this 的上下文(将 this 绑定到新创建的对象 | f 函数中的 this 的指针替换成 obj) ,f.call(obj)
    4. 如果该函数没有显式地在函数中写 return,则返回 this。

    对于一个函数,如果不使用 new 操作它,它只是一个正常的函数;使用 new 操作符仅仅改变了它的 this 指向且在函数内部隐式地创建了一个对象,然后再称之为 “构造函数”。仅此而已。

    如果你对第三步中的操作有困惑,看几个简单的例子:

    设置构造函数
    function f() {
      this.a = 1
      this.b = 2
    }
    f()
    console.log(f.constructor) //ƒ Function() { [native code] }
    
    function f() {
      this.a = 1
      this.b = 2
    }
    
    const o = new f()
    console.log(o.constructor)
    // ƒ f() {
    //   this.a = 1
    //   this.b = 2
    // }
    
    this指针替换
    function f() {
      console.log(this) // window
      this.a = 1
      this.b = 2
    }
    
    f()
    
    function f() {
      console.log(this) // f {}
      this.a = 1
      this.b = 2
      console.log(this) // f {a: 1, b: 2}
    }
    
    new f()
    
    什么是call?
    const drink = {
      name: 'Coca Cola',
      color: 'black',
      price: '3.5',
      intro: function () {
        console.log(`名称:${this.name},颜色:${this.color},价格:${this.price}`)
      },
    }
    
    const computer = {
      name: 'Orange Juice',
      color: 'orange',
      price: '4',
    }
    
    drink.intro.call(computer) //名称:Orange Juice,颜色:orange,价格:4
    

    确保上面的内容你能十分清晰,否则不要进行下面的内容。

    console.log(o.b) // 2
    

    o 的值是通过 new f() 得到的对象,this 指向这个对象,函数中给 this 添加了属性 b 为其赋值为 2,并将他返回。所以 这里打印出 2。f.prototype 是无法被访问到的,这种情况还被称之为 property shadowing ---属性遮蔽

    console.log(o.c) // 4
    console.log(o.__proto__.c) // 4
    console.log(o.__proto__ === f.prototype) // true
    

    函数中并没有给 this 添加 c 属性并为其赋值 4,但是打印 o.c 返回 4。通过上文你已经知道 constructor 是干什么的了:

    console.log(o.constructor.prototype.b) // 3
    

    o 是由函数 f 构造的,o.constructor 返回函数 f,所以o.constructor.prototype === f.prototype, f.prototype 返回什么呢?上面初始代码中直接写好的,现在可以翻上去看看 f.prototype,所以 o.constructor.prototype.b 返回 3。查找对象上的属性就是先找自身再通过 __proto__ 一层一层往上找的:

    • 如果自身有该属性直接获取它的值;
    • 如果自身有且其构造器的 prototype 上也有,属性遮蔽不会忘了吧;
    • 如果一直沿着 __proto__ 找但没找到,会返回 undefined;为什么呢?
    console.log({}.constructor) // ƒ Object() { [native code] }
    console.log({}.__proto__ === Object.prototype) // true
    console.log(Object.prototype.__proto__) // null
    

    看到这里,应该十分清晰了。这就是最终为什么会返回 undefind 的原因:Object.prototype.__proto__ 指向 null。

    小练习

    做一个简单又不给你解释的小练习吧!

    console.log(o.b)
    console.log(o.__proto__.b)
    console.log(o.d)
    
    答案
    // 2
    // 3
    // undefined
    

    重要提示

    对于 Object.prototype.__proto__

    测试代码

    如果看完还是不太明白,动手试一试吧!我把本文用到的代码片段放到此处供你快速拷贝。

    function f() {
      this.a = 1
      this.b = 2
    }
    
    const o = new f()
    f.prototype.b = 3
    f.prototype.c = 4
    
    console.log(o.b) // 2
    
    console.log(o.c) // 4
    console.log(o.__proto__.c) // 4
    console.log(o.__proto__ === f.prototype) // true
    
    console.log(o.constructor.prototype.b) // 3
    
    console.log(o.b) // 2
    console.log(o.__proto__.b) // 3
    console.log(o.d) // undefined
    
    console.log({}.constructor) // ƒ Object() { [native code] }
    console.log({}.__proto__ === Object.prototype) // true
    console.log(Object.prototype.__proto__) // null
    
    // --------- other --------
    console.log(o.__proto__) // {b: 3, c: 4, constructor: ƒ}
    console.log(o.__proto__.__proto__ === Object.prototype) // true
    console.log(Object.prototype.__proto__) // null
    console.log(o.__proto__.__proto__.__proto__) // null
    console.log(f.prototype.__proto__ === Object.prototype) // true
    
  • 相关阅读:
    Spring AOP 实现原理
    Spring Aop实现方式总结
    Spring Aop重要概念介绍及应用实例结合分析
    Spring Aop
    常见的排序算法
    MINA2.0原理
    Java和Tomcat类加载机制
    Java 8 新特性概述
    Java类加载机制深度分析
    jetty之建立多Connector
  • 原文地址:https://www.cnblogs.com/guangzan/p/12886111.html
Copyright © 2011-2022 走看看