[TOC] #### 构造函数 --- 在介绍原型和原型链之前,我们需要先了解一些知识点 任何函数都可以作为 **构造函数**。当该函数通过 `new` 关键字创建对象的时候,我们就称之为 **构造函数** ```javascript // 定义一个函数,那它只是一个普通的函数,不能称它为构造函数 function User() { } // 这时 User 就不是普通的函数了,它现在是一个构造函数,因为通过 new 关键字调用了它 // 创建一个 User 构造函数的实例 instance let instance = new User() ``` #### prototype 属性 --- prototype 属性是`函数`特有的属性。 你可能会有疑问,函数为什么会有属性?这是因为在 JavaScript 中,函数也是一个对象,对象有自己的属性很正常 这个属性设计之初的目的,就是为了继承。作用:让某一个构造函数实例化的 `所有对象` 可以找到公共的方法和属性 ```javascript function User() { } User.prototype.name = '所有 User 的实例都可以读取到我' let u1 = new User() let u2 = new User() console.log(u1.name); // 所有 User 的实例都可以读取到我 console.log(u2.name); // 所有 User 的实例都可以读取到我 ``` 在学习原型链之前,你可能会有疑问,我们并没有像下面这样手动设置 `u1.name` 和 `u2.name` 的值 但是,它们的输出结果为什么是有值的,它们的值又是从哪里找到的呢?这里我们就引出了 `__proto__` 属性 ```javascript u1.name = '所有 User 的实例都可以读取到我' u2.name = '所有 User 的实例都可以读取到我' ``` #### \_\_proto\_\_ 属性 --- \_\_proto\_\_ 属性是 `对象` 特有的属性,它表示当前对象的原型是谁 对象的 \_\_proto\_\_ 属性就是它的构造函数的 prototype 属性,通过以下代码可证明这句话 ```javascript function User() { } let instance = new User() console.log(instance.__proto__ === User.prototype) // true ``` 现在我们可以解答上面的疑问了,为什么我们可以调用对象上没有定义的方法和属性呢? ```javascript function User() { } User.prototype.name = '所有 User 的实例都可以读取到我' let u1 = new User() let u2 = new User() // 当我们调用对象上的属性 u1.name 时 // 第一步: 首先,会在 u1 这个对象上查找 name 属性,找到就返回,没有找到进行下一步 // 第二步: 查找 u1.__proto__ 属性上有没有 name 属性,找到就返回,没有找到进行下一步 // 第三步: 查找 Object.prototype 属性上有没有 name 属性,找到就返回,没有找到返回 undefined // 以此类推,直到 Object.prototype.__proto__ === null console.log(u1.name); // 所有 User 的实例都可以读取到我 console.log(u2.name); // 所有 User 的实例都可以读取到我 // 第二步找 u1.__proto__,实际找的是 User.prototype console.log(u1.__proto__ === User.prototype); // true // 第三步找 Object.prototype,实际找的是 Object.prototype console.log(User.prototype.__proto__ === Object.prototype); // true // 直到 Object.prototype.__proto__ 为 null,停止继续查找 console.log(Object.prototype.__proto__); // null // 为什么第三步从 Object.prototype 上找 ? 因为 User.prototype 是通过 Object 实例化得到的 console.log(User.prototype.__proto__ === Object.prototype); // true ``` #### 原型链的概念 --- 每个对象都有一个原型(prototype),并从原型上继承属性和方法。 原型本身也是一个对象,它也有自己的原型,形成一个链式结构,这种链式结构就被称为原型链。 ```plaintext 对象本身 -> User.prototype -> Object.prototype ``` #### constructor 属性 --- constructor 属性是 `对象` 特有的属性,它表示当前对象的构造函数 ```javascript function User() { } let instance = new User() console.log(instance.constructor); // ƒ User() { } ``` 我们知道在 JavaScript 中,函数也是对象,那么函数是否也有 `constructor` 属性呢 ? ```javascript function User() { } // 可以发现,函数也有 constructor 属性 console.log(User.constructor); // ƒ Function() { [native code] } ``` 如果继续追问,`Function()` 是否也有 `constructor` 属性 ? ```javascript // 可以发现 Function 函数的构造函数就是本身了 console.log(Function.constructor); // ƒ Function() { [native code] } ```