zoukankan      html  css  js  c++  java
  • 彻底搞懂js原型与原型链

    原生的原型链

    function fn(){},fn 为 Function的一个实例,原型链为 null -> Object -> Function -> fn:

     fn.__proto__ === Function.prototype

    Function.prototype.__proto === Object.prototype

    Object.prototype.__proto__ === null

    原型链通过原型(prototype)链接,prototype 就是一个 只有(构造)函数才有的特殊的实例,包含了constructor指针(和__proto__,所有实例都有

    之后new出来的普通实例(非prototype)都包含这个prototype(引用名为__proto__):console.log(sonA)   //  {/* 其他属性 */ __proto__: Son.prototype}

    举例来说,对于函数实例,所有函数实例.__proto__ === Function.prototype (通过这个能拿到Function上的通用属性,如bind函数)

    甚至Function.__proto__ === Function.prototype, Object.__proto__ === Function.prototype 

    Function instanceof Object // true  Function.__proto__.__proto__ === Object.prototype (优先是更具体的函数,然后才作为更抽象的对象,对象永远在原型链较上层)

    Object instanceof Function // true  Object.__proto__ = Function.prototype

    原型链继承: 

    未继承时

    console.log(Son.prototype) // {  constructor: Son, __proto__: Object.prototype }

    原型链继承了Father时,

    console.log(Son.prototype)  // { __proto__: Father.prototype }父类的一个实例, 通过new Father 或者 Object.create(Father.prototype)生成

    需要手动赋予constructor:

    Object.defineProperty(Son.prototype, "constructor", {

      value: Son,

      writable: false

    });

    console.log(Object.prototype)

    __proto__: null }

    原型链继承,本质就是修改函数的prototype,使其从指向Function变为指向父类;父类的对象刚好符合这个特性

    巩固一下上面的知识点,请判断以下比较是否为真:

    Object.prototype.__proto__ === null

    Object.__proto__ === Function.prototype

    Function.__proto__ === Function.prototype 

    fn.__proto___ === Function.prototype

    Object.prototype === Function.prototype.__proto__

    Object.prototype === fn.prototype.__proto__ 

    Object.prototype.isPrototypeOf(fn) 

    Object.prototype.isPrototypeOf(fn.prototype)

    Function.prototype === fn.__proto__; 

    Function.prototype.isPrototypeOf(fn) 

    Function.prototype.isPrototypeOf(fn.prototype) // false

    答案:以上判断若未特殊说明,结果都为真

    谈一下new

    var foo = new Foo();
    实际是这样调用的
     
        var this = new Object(); //Note: this no longer point to global variable if called with new
        this.__proto__ = Foo.prototype;
        Foo.call(this);
        return this;
      或者
     var this = Object.create(Foo.prototype);
       Foo.call(this);
     return this;
     
    其中object.create(p)的polyfill如下:
         function f(){}
         f.prototype = p;
         return new f();

    自定义原型链:基于原型链的继承

    Father() {} -> Son() {]

    继承的本质是,如何使Son的实例能访问到Father定义的属性

    通过原型链,我们将Son的原型指向Father

    Son原型链现在是指向的Function,Son.__proto__ === Function.prototype

    我们希望Son.__proto__ === Father.prototype

    按es5之前的规范,我们不能直接访问__proto__,那么只能修改prototype (ES5中用Object.getPrototypeOf函数获得一个对象的[[prototype]]。ES6中,使用Object.setPrototypeOf可以直接修改一个对象的[[prototype]])

    我们知道 Father的实例的__proto__指向Father.prototype,那么Son.prototype等于Father的实例就可以

    Son.prototype = new Father()  或者

    Son.prototype = Object.create(Father.prototype)

    这里有一个问题,prototype的constructor属性应该指向构造函数,而这种写法的constructor通过原型链会找到Father,所以需要定义一下constructor

    Object.defineProperty(Son.prototype, "constructor", {

      value: Son,

      writable: false

    });

    顺便了解一下原型链查找顺序

    优先查找对象的,对象上没有则通过__proto__找prototype,还没找到,就找prototype.__proto__, 也就是父类的prototype

    比如

    对象objA查找hasOwnProperty 

    objA -> Son.prototype -> Object.prototype -> Object.prototype.hasOwnProperty

    函数funcA查找bind

    funcA -> Function.prototype -> Function.prototype.bind

    PS:对于 const fn = () => {} 这样的箭头函数,不属于原型链的范畴 可以参考 http://www.cnblogs.com/mengff/p/9656486.html

  • 相关阅读:
    springMVC(注解版笔记)
    关于在Eclipse里面启动了服务,但是localhost:8080无法访问的问题:
    springmvc基础知识
    private
    hashtable,hashMap,vector和ArrayList
    使用IDEA创建java项目(hello word)
    设计模式
    设计模式(总纲)
    spring-boot集成PageHelper和通用Mapper
    spring-boot集成mybatis
  • 原文地址:https://www.cnblogs.com/huashiyiqike/p/10542585.html
Copyright © 2011-2022 走看看