• 理解prototype(原型)


    版权归作者所有,任何形式转载请联系作者。
    作者:U_U(来自豆瓣)
    来源:https://www.douban.com/note/293217333/

    要理解JS中的prototype, 首先必须弄清楚以下几个概念
    1. JS中所有的东西都是对象

    2. JS中所有的东西都由Object衍生而来, 即所有东西原型链的终点指向Object.prototype
         // ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf",
         // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__",
         // "__lookupSetter__"]
         console.log(Object.getOwnPropertyNames(Object.prototype));

    3. JS中构造函数和实例(对象)之间的微妙关系
       构造函数通过定义prototype来约定其实例的规格, 再通过 new 来构造出实例, 他们的作用就是生产对象.
       而构造函数(方法)本身又是方法(Function)的实例, 因此也可以查到它的__proto__(原型链)

       Object / function F() {} 这样子的就是构造函数啦, 一个是JS原生API提供的, 一个是自定义的
       new Object() / new F() 这样子的就是实例啦
       实例就"只能"查看__proto__来得知自己是基于什么prototype被制造出来的,
       而"不能"再重新定义实例的prototype妄想创造出实例的实例了.

       实践出真知, 只有自己动手观察/思考才能真正领悟:
       // 先来看看构造函数到底是什么
       // function Empty() {} function Empty() {}
       console.log(Function.prototype, Function.__proto__);
       // Object {} function Empty() {}
       console.log(Object.prototype, Object.__proto__);
       function F() {}
       // F {} function Empty() {}
       console.log(F.prototype, F.__proto__);

       你可能已经晕了, 我们来分解一下
       prototype输出的格式为: 构造函数名 原型
       首先看下Object.prototype输出了什么?
       Object {} -> 前面的Object为构造函数的名称, 后面的那个表示原型, 这里是一个{}, 即一个Object对象的实例(空对象)
       那么 F {} 我们就明白是什么意思了, F 就是构造函数的名称, 原型也是一个空对象

       // 再来看看由构造函数构造出来的实例
       var o = new Object(); // var o = {};
       // undefined Object {}
       console.log(o.prototype, o.__proto__);
       function F() {}
       var i = new F();
       // undefined F {} 创建的对象中的__proto__可以看见他的构造函数是啥   对象当中没有prototype 只有构造函数才有

       console.log(i.prototype, i.__proto__);

       我们再深入一点, 定义下 F 的原型看看到底会发生些什么?
       function F() {}
       F.prototype.a = function() {};
       var i = new F();
       // undefined F {a: function}
       console.log(i.prototype, i.__proto__);

       这样我们就清楚的看到 i 是由 F 构造出来的, 原型是 {a: function}, 就是原本的空对象原型新增了一个 a 方法

       我们再换一种情况, 完全覆盖 F 的原型会怎么样?
       function F() {}
       F.prototype = {
           a: function() {}
       };
       var i = new F();
       // undefined Object {a: function}
       console.log(i.prototype, i.__proto__);
       
       咦~ 为什么这里表明 i 是由 Object 构造出来的? 不对吧!
       因为我们完全将 F 的prototype覆盖, 其实也就是将原型指定为对象{a: function}, 但这会造成原本的constructor信息丢失, 变成了对象{a: function}指定的constructor.
       那么对象{a: function}的constructor是什么呢?
       因为对象{a: function}其实就相对于
       var o = {a: function() {}} // new了一个Object
       那么o的constructor当然是 Object 啦

       我们来纠正下这个错误
       function F() {}
       F.prototype = {
           a: function() {}
       }
       // 重新指定正确的构造函数
       F.prototype.constructor = F;
       var i = new F();
       // undefined F {a: function, constructor: function}
       console.log(i.prototype, i.__proto__);

       现在又能得到正确的原型信息了

       最后来看看什么原型链又是个什么东西?
       简单的来讲和OOP中的继承关系(链)是一样的, 一层一层往上找, 直至最终的 Object.prototype

    prototype chain


       最最关键的是要弄清楚JS中哪些东西是(实例)对象, 这个简单了, JS中所有东西都是对象!
       再要弄清楚就是任何一个对象都是有一个原型的!

       那么我们来证明一下:
       Object // 这是一个函数, 函数是 Function 的实例对象, 那么就是由 Function 构造出来的(其实转载别人的我自己都看晕了 。。。。)
       Object.__proto__ == Function.prototype // 那么Object的原型, true
       // 这个是一个普通对象了, 因此属于 Object 的实例
       Function.prototype.__proto__ == Object.prototype // true
       // 这已经是原型链的最顶层了, 因此最终的指向 null
       Object.prototype.__proto__ == null // true

       Function // 这也是一个函数, 没错吧!
       Function.__proto__ == Function.prototype // true
       
       function A() {} // 这是一个自定义的函数, 终归还是一个函数, 没错吧!
       A.__proto__ == Function.prototype // 任何函数都是 Function 的实例, 因此A的原型是?
       var a = new A()
       a.__proto__ == A.prototype // 实例a是由A构造函数构造出来的, 因此a的原型是由A的prototype属性定义的
       A.prototype.__proto__ == Object.prototype // 普通对象都是 Object 的示例
       

    个人总结一下:

    首先记住一句:js中一切皆为对象:

    例子:

    ಥ_ಥ:
    [图片]

    ಥ_ಥ:
    js中一切皆为对象
    function test(){}
    var t new test
    t. prototype为undefined
    t. __proto__保存的是构造该对象的函数的prototype该属性用于规定该函数构造实例的规格
    一切函数又是对象,函数中的__proto__又是一个对象该对象由Oject 构造函数构造得来,
    Function. prototype. __proto__也是一个对象一个Object的实例,完全等于Object. prototype

    Object. prototype. __proto__完全等于null
    这已经是原型链最顶层了

    说实话真得绕,函数也是对象,该函数的原型也是对象也就是构造该函数的Object函数的prototype属性!

  • 相关阅读:
    Spring Cloud
    Hibernate 缓存
    Spring 快速入门
    Junit 单元测试
    Spring Cloud 笔记
    Swagger SpringBoot 集成
    Apache Shiro 权限框架
    Spring Boot
    跨域问题
    BeX5 常见问题解决办法
  • 原文地址:https://www.cnblogs.com/webcyh/p/11313627.html
Copyright © 2020-2023  润新知