Skip to content
On this page

vue 源码使用到的原型

使用 new 创建实例 。执行 init 方法,_init 方法构造函数没有此方法,往原型对象上找 此处使用 new 创建出来的 this,必定指向 VUE。

  • new 干了什么?
  • instanceof 判断逻辑?
var app = new Vue({
    data:{},
    watch:{}
})
function Vue(options) {
  if (process.env.NODE_ENV !== "production" && !(this instanceof Vue)) {
    warn("Vue is a constructor and should be called with the `new` keyword");
  }
  this._init(options);
}
initMixin(Vue);

Vue源码使用到的原型

    if (Array.isArray(value)) {
      // 通过能力检测的结果选择不同方式进行数组劫持
      if (hasProto) {
        protoAugment(value, arrayMethods); //如果浏览器支持隐式原型
      } else {
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value);
    } else {
      this.walk(value);
    }

// can we use __proto__?
export const hasProto = '__proto__' in {}
function protoAugment(target, src: Object) {
  /* eslint-disable no-proto */
  target.__proto__ = src;
  /* eslint-enable no-proto */
}

MDN:通常,应该使用 Object.setPrototypeOf() 方法来设置对象的原型

源码中为什么使用_proto_ 而没有使用 setPrototypeOf

地址

为什么要使用原型

      function Foo(name) {
        this.name = name;
        this.showName = function () {
          console.log("I'm " + this.name);
        };
      }

图上通过 Foo 创建出来的每一个对象,里面都有 showName 这样就会占用很多的资源。

     function Foo(name) {
        this.name = name;
      }
      Foo.prototype.showName = function () {
        console.log("I'm " + this.name);
      };

  • 而通过原型来实现的话,只需要在构造函数里面给属性赋值,而把方法写在 Foo.prototype 属性 这样每个对象都可以使用 prototype 属性里面的方法,节省了不少的资源。
  • 使用原型链解决继承问题

原型链笔记

  • 每个对象都有一个_proto_属性,并且指向它的 prototype 原型对象
  • 每个构造函数都有一个 prototype 原型对象-
    • prototype 原型对象里的 constructor 指向构造函数本身 Person.prototype.constructor === Person
  • 当试图得到一个对象的属性时,如果这个对象本身不存在这个属性就会根据proto去 prototype 找。因为还是一个对象继续找 Object

Object.create(null)

Object.create(null) 新建的对象是没有__proto__属性的

hasOwnProperty

在原型链上查询属性比较耗时,对性能有影响,试图访问不存在的属性时会遍历整个原型链。遍历对象属性时,每个可枚举的属性都会被枚举出来。 要检查是否具有自己定义的属性,而不是原型链上的属性,必须使用 hasOwnProperty 方法。hasOwnProperty 是 JavaScript 中唯一处理属性并且不会遍历原型链的方法

new 干了什么?

   function myNew(Con, ...args) {
        //1创建一个空对象
        let obj = {};
        //2将这个空对象的__proto__指向构造函数的原型
        Object.setPrototypeOf(obj, Con.prototype);
        //3改变this指向,讲空对象作为构造函数的上下文
        var result = Con.apply(obj, args);
        //4对构造函数有返回值的处理判断
        // 当 构造函数有返回值时 则需要做判断再返回对应的值,是 对象类型则返回该对象,是 原始类型则返回第一步创建的空对象。
        return result instanceof Object ? result : obj;
      }

      function Foo2() {
        this.name = "aaa";
        return 111;
      }
      console.log(new Foo2()); //这个返回值是基本类型,被忽略不影响结果

4 默认 如果返回的是基本类型return 111 则忽略返回结果 如果返回的是引用类型,则返回引用类型

instanceof 判断逻辑?

instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype

   function new_instance_of(leftVaule, rightVaule) {
        let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
        leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值

        if(typeof leftVaule !== 'object' || leftVaule === null) {
              return false
          }

        while (true) {
          //最顶层的object的__proto__是null
          if (leftVaule === null) {
            return false;
          }
          if (leftVaule === rightProto) {
            return true;
          }
          // 当原型对象不相同时, 沿着原型链继续向上查找
          leftVaule = leftVaule.__proto__;
        }
      function Fun() {
        // this.run = a;//2
      }
      // Fun.prototype.run = b;//4
      var f1 = new Fun();
      // f1.run = c; //1
      // f1.__proto__.run = d;//3
      // Object.prototype.run = e;//5
      Function.prototype.run = f; //不会找
      console.log(f1.run);

为什么使用 Object.prototype.toString.call()

Released under the MIT License.