JS中 prototype 和 __proto__ 的区别

523 阅读3分钟

前言

  • JavaScript中的 Object 是构造函数(创建对象的包装器)
  • 构造函数,通过prototype来存储要共享的属性和方法,也可以设置prototype指向现存的对象来继承该对象。
  • Object.getPrototypeOf(Object)Object.prototype 不一样
  • Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)
  • Object.getPrototypeOf(Object) 等同于 Object.__proto__[[prototype]] === __proto__

内容

Object, Function, 和 new Object()

测试

console.log(Object)                                 // ƒ Object() { [native code] }
console.log(Object.prototype)                       // {constructor: ƒ, __defineGetter__: ƒ,  …}
console.log(Object.prototype.constructor === Object)// true
console.log(typeof Object.prototype)                // "object"
console.log(Object.getPrototypeOf(Object))          // ƒ () { [native code] }
console.log(Object.__proto__)                       // ƒ () { [native code] }
console.log(Object.getPrototypeOf(Object.prototype))// null

console.log(Function)                               // ƒ Function() { [native code] }
console.log(Function.prototype)                     // ƒ () { [native code] }
console.log(Object.getPrototypeOf(Function))        // ƒ () { [native code] }
console.log(typeof Function)                        // function
console.log(typeof Function.prototype)              // function
console.log(Object.getPrototypeOf(Function) === Function.prototype)             // true
console.log(Object.getPrototypeOf(Function) === Object.getPrototypeOf(Object))  // true
console.log(Function == Object)                                                 // false

let obj = new Object();                              // 等同于 let obj = {}
console.log(obj)                                     // {} 展开后有 [[Prototype]]: Object
console.log(typeof obj)                              // "object"
console.log(obj.prototype)                           // undefined
console.log(Object.getPrototypeOf(obj))              // {constructor: ƒ, __defineGetter__: ƒ, …}
console.log(typeof(Object.getPrototypeOf(obj)))      // "object"

console.log(Object.getPrototypeOf(Function.prototype))    //{constructor: ƒ, …}

解析

  1. 单独的 Object 是一个Object类型的构造函数,它有一个与之关联的 Object.prototype 对象 可以通过调用 Object.prototype 来访问
  2. Object.prototype 对象中存储着所有共享的方法和属性,并且还有一个 constructor 属性等于 Object 构造函数
  3. Object.prototype 对象的原型对象 [[prototype]] (也称__proto__,但不推荐使用) 是原型链的终点,值为 null
  4. Object的原型对象 [[prototype]] (也称__proto__) 等于 Function 构造函数的原型对象[[prototype]] 也等于 Function 构造函数的 protytype
  5. 单独的 Function 是一个 Function 类型的构造函数
  6. FunctionFunction.protytype 和原型对象 [[protytype]] 是相等的,他们也都等于 Object 的原型对象 [[prototype]] (也称__proto__)

总结

Object.prototype.constructor === Object
Object.prototype.__proto__ === null
Object.__proto__ === Function.__proto__ == Function.prototype

实例,原型,和构造函数

测试

function fn() {
    let x = 1;
    this.y = 2;
    console.log("In fn: ", this)
}
fn.prototype.z = 3;

console.log(fn)                                      // f fn() {let x = 1; this.y = 2;}
console.log(fn.prototype)                            // {z: 3, constructor: ƒ} 展开后有 [[Prototype]]: Object
console.log(Object.getPrototypeOf(fn))               // ƒ () { [native code] }


let instance = new fn();
console.log(instance)                                // In fn:  fn {y: 2} // fn {y: 2} 展开后有 [[Prototype]]: Object
console.log(instance.prototype)                      // undefined
console.log(Object.getPrototypeOf(instance))         // {z: 3, constructor: ƒ fn()} 展开后有 [[Prototype]]: Object

解析

在一般看来,当我们自定义一个函数fn后,如果直接用()调用这个函数,那么这个函数就作为一个普通函数; 如果用 new 操作符调用这个函数并赋值给一个变量,那么这个函数就是fn类型的构造函数,变量就是实例。

作为一个普通函数 fn :

  1. 它的第一层执行环境是包含他的对象,也就是this是包含他的对象,如果这个函数是在全局中,那么就是 window 对象
  2. 它也有一个与之关联的 fn.prototype 对象,通过 fn.prototype 访问,
  3. fn.prototype 对象可以加自定义方法和属性,它内部属性 constructor 等于 fn 构造函数。
  4. fn.prototype 对象的原型对象 [[prototype]] 就是 Object
  5. 它的原型对象 [[prototype]] 等于 Object 的原型对象 [[prototype]]

作为一个用 new 操作符调用的构造函数 fn ,对于它的实例 instance :

  1. 这个实例 instance 的第一层执行环境就是当前构造函数本身, 也就是内部的 this 指向自己的构造函数内部
  2. 它也有一个与之关联的 fn.prototype 对象,通过 fn.prototype 访问,
  3. fn.prototype 对象可以加自定义方法和属性,它内部属性 constructor 等于 fn 构造函数。
  4. fn.prototype 对象的原型对象 [[prototype]] 就是 Object
  5. 它的原型对象 [[prototype]] 等于 Object 的原型对象 [[prototype]]
  6. instance 实例的原型对象 [[protytype]] 等于 fn.prototype 对象
  7. instance 实例的 prototypeundefined

当用 new 操作符创建一个 Object 这个构造函数的实例的时候,这个实例的原型对象 [[prototype]] 等于 Object.prototype 对象。 这个实例没有自己的 protytype 属性

小结

fn.prototype.constructor === fn
fn.prototype.__proto__ = Object.prototype
fn.__proto__ === Object.__proto__

instance.__proto__ === fn.prototype
instance.__proto__.constructor === fn
instance.__proto__.__proto__ === Object.prototype
instance.__proto__.__proto__.__proto__ === null