美文网首页javascript
Javascript 基础之原型和原型链

Javascript 基础之原型和原型链

作者: 编程之上 | 来源:发表于2019-04-29 13:22 被阅读0次

    原型

    原型
    • 每个 函数 都有 prototype 对象属性,除了 Function.prototype.bind(),它指向原型。
    • 每个 对象 都有 __proto__ 对象,它指向创建这个对象的构造函数的原型。其实这个属性指向了 [[prototype]],但是 [[prototype]] 是内部属性,我们访问不到,所以用 __proto__ 来访问。
    • 对象可以通过 __proto__ 来寻找部署改对象的属性,__proto__ 将对象连接起来组成 原型链

    小结:从上图可看出,一切皆对象,对象都有 __proto__ 属性

    1.通过 new 出来的对象,其 __proto__(这个对象的属性)指向创建这个对象的构造函数的原型;而这个构造函数的原型也是对象,它的 __proto__ 指向 Object 的原型;

    function Foo(){}
    const f1 = new Foo(); 
    f1.__proto__ => Foo.prototype;
    Foo.prototype.__proto__ => Object.prototype;
    Object.prototype.__proto__ => null; // 到头了
    

    2.那我们平常用的字面量对象呢?

    const obj = {};
    obj.__proto__ => Object.prototype;
    Object.prototype.__proto__ => null; // 到头了
    
    const arr = [];
    arr.__proto__ => Array.prototype;
    Array.prototype.__proto__ => Object.prototype;
    Object.prototype.__proto__ => null; // 到头了
    

    3.既然一切皆对象,那函数的 __proto__ 是怎样的呢?它指向构造函数 Function 的原型:

    function fn(){}
    fn.__proto__ => Function.prototype;
    Function.prototype.__proto__ => Object.prototype;
    Object.prototype.__proto__ => null; // 到头了
    

    4. 函数都有 prototype 属性,它的 constructor 又指回函数自己

    fn.prototype.constructor => fn;
    

    new

    • 新生成一个对象 let obj = new Object();
    • 获得构造函数 let Con = [].shift.call(arguments);
    • 链接到原型 obj.__proto__ = Con.prototype;
    • 绑定 this let result = Con.apply(obj, arguments);
    • 返回新对象 return typeof result === 'object' ? result : obj;

    在调用new的过程中会发生以上4件事:

    function create(){
      // 创建一个空的对象
      let obj = new Object();
      // 获得构造函数
      let Con = [].shift.call(arguments);
      // 链接到原型
      obj.__proto__ = Con.prototype;
      // 绑定 this,执行构造函数
      let result = Con.apply(obj, arguments);
      // 确保 new 出来的是个对象
      return typeof result === 'object' ? result : obj;
    }
    

    对于实例化对象来说,都是通过 new 产生的,无论是 function Foo() 还是 let x = { y: 1 }

    对于创建一个对象来说,推荐使用字面量的方式创建对象(无论性能还是可读性)。因为你使用 new Object() 的方式创建对象需要通过作用域链一层层找到Object,但是你使用字面量的方式就没这个问题了。

    function Foo();
    // function 就是个语法糖,内部等同与 new Function()
    
    let x = { y: 1 };
    // 这个字面量内部也是使用了new Object();
    

    对于new来说,还需注意下运算符优先级

    function Foo(){
      return this;
    }
    Foo.getName = function(){
      console.log('name');
    }
    Foo.prototype.getName = function(){
      console.log('prototypeName');
    }
    
    new Foo.getName();   // name
    new Foo().getName(); // prototypeName
    

    new Foo()的优先级高于new Foo,所以上面最后2行代码可划分执行顺序

    new (Foo.getName());
    
    (new Foo()).getName();
    

    instanceof

    instanceof 可正确判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。下面自我实现一个 instanceof 函数

    function inof(left, right) {
      // 获得类型的原型
      right = right.prototype;
      // 获得对象的原型
      left = left.__proto__;
      // 判断对象的类型是否等于类型的原型
      while (true) {
        if (left === null) {
            return false
        }
        if (right === left) {
            return true
        }
        left = left.__proto__;
      }
    }
    

    测试一下

    function fn(){}
    inof(fn, Function); // true
    inof(fn, Object); // true
    

    this

    它是一个会让很多人混淆的概念,让我们用几个场景规则来记住它。

    // 场景一
    function fn(){
      console.log(this.a);
    }
    var a = 1;
    fn(); // 1
    
    // 场景二
    var obj = {
      a: 2,
      fn: fn
    };
    obj.fn(); // 2
    
    // 以上两种场景 `this` 依赖于调用函数前的对象
    
    // 场景三 - 优先级最高的, `this` 只会绑定在 `obj1` 上,不会被任何方式修改 `this` 指向
    var obj1 = new fn();
    obj1.a = 3;
    console.log(obj1.a); // 3
    
    // 场景四 - 利用 call、apply、bind 改变 this,这个优先级仅次于 new
    fn.call(obj);  // 2
    

    以上 4 种场景弄清楚了,很多代码中的 this 就不是问题了。

    function fn() {
      return () => {
        return () => {
          console.log(this);
        }
      }
    }
    console.log(fn()()()); // window
    

    箭头函数中其实是没有 this 的,这个函数中的 this 只取决于它外面的第一个不是箭头函数的函数this。在这个例子中,因为调用 fn 符合前面代码中的第一个场景,所以 thiswindow。并且 this 一旦绑定了上下文,就不会被任何代码改变。

    上一篇: Javascript 基础之类型

    相关文章

      网友评论

        本文标题:Javascript 基础之原型和原型链

        本文链接:https://www.haomeiwen.com/subject/pzlynqtx.html