精华内容
下载资源
问答
  •   作为一名前端工程师,必须搞懂JS中的prototype、__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞懂它们。这里说明一点,__...

    提示:不要排斥,静下心来,认真读完,你就搞懂了!(可以先看一下最后的总结部分再回过头来完整看完)

    1. 前言

      作为一名前端工程师,必须搞懂JS中的prototype__proto__constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞懂它们。这里说明一点,__proto__属性的两边是各由两个下划线构成(这里为了方便大家看清,在两下划线之间加入了一个空格:_ _proto_ _,读作“dunder proto”,“double underscore proto”的缩写),实际上,该属性在ES标准定义中的名字应该是[[Prototype]],具体实现是由浏览器代理自己实现,谷歌浏览器的实现就是将[[Prototype]]命名为__proto__,大家清楚这个标准定义与具体实现的区别即可(名字有所差异,功能是一样的),可以通过该方式检测引擎是否支持这个属性:Object.getPrototypeOf({__proto__: null}) === null。本文基于谷歌浏览器(版本 72.0.3626.121)的实验结果所得。
       现在正式开始! 让我们从如下一个简单的例子展开讨论,并配以相关的图帮助理解:

    function Foo() {...};
    let f1 = new Foo();
    

    以上代码表示创建一个构造函数Foo(),并用new关键字实例化该构造函数得到一个实例化对象f1。这里稍微补充一下new操作符将函数作为构造器进行调用时的过程:函数被调用,然后新创建一个对象,并且成了函数的上下文(也就是此时函数内部的this是指向该新创建的对象,这意味着我们可以在构造器函数内部通过this参数初始化值),最后返回该新对象的引用,详细请看:详解JavaScript中的new操作符。虽然是简简单单的两行代码,然而它们背后的关系却是错综复杂的,如下图所示:
    整体的联系看到这图别怕,让我们一步步剖析,彻底搞懂它们!
      图的说明:右下角为图例,红色箭头表示__proto__属性指向、绿色箭头表示prototype属性的指向、棕色实线箭头表示本身具有的constructor属性的指向,棕色虚线箭头表示继承而来的constructor属性的指向;蓝色方块表示对象,浅绿色方块表示函数(这里为了更好看清,Foo()仅代表是函数,并不是指执行函数Foo后得到的结果,图中的其他函数同理)。图的中间部分即为它们之间的联系,图的最左边即为例子代码。

    2. _ _ proto _ _ 属性

      首先,我们需要牢记两点:①__proto__constructor属性是对象所独有的;② prototype属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有__proto__constructor属性,这点是致使我们产生困惑的很大原因之一。上图有点复杂,我们把它按照属性分别拆开,然后进行分析:
    __proto__
      第一,这里我们仅留下 __proto__ 属性,它是对象所独有的,可以看到__proto__属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象),那么这个属性的作用是什么呢?它的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的__proto__属性所指向的那个对象(可以理解为爷爷对象)里找,如果还没找到,则继续往上找…直到原型链顶端null(可以理解为原始人。。。),再往上找就相当于在null上取值,会报错(可以理解为,再往上就已经不是“人”的范畴了,找不到了,到此结束,null为原型链的终点),由以上这种通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链
      其实我们平时调用的字符串方法、数组方法、对象方法、函数方法等都是靠__proto__继承而来的。

    3. prototype属性

      第二,接下来我们看 prototype 属性:
    prototype属性  prototype属性,别忘了一点,就是我们前面提到要牢记的两点中的第二点,它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象,由此可知:f1.__proto__ === Foo.prototype,它们两个完全一样。那prototype属性的作用又是什么呢?它的作用就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。

    4. constructor属性

      最后,我们来看一下 constructor 属性:
    constructor属性  constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数,每个对象都有构造函数(本身拥有或继承而来,继承而来的要结合__proto__属性查看会更清楚点,如下图所示),从上图中可以看出Function这个对象比较特殊,它的构造函数就是它自己(因为Function可以看成是一个函数,也可以是一个对象),所有函数和对象最终都是由Function构造函数得来,所以constructor属性的终点就是Function这个函数。
    constructor继承
      感谢网友的指出,这里解释一下上段中“每个对象都有构造函数”这句话。这里的意思是每个对象都可以找到其对应的constructor,因为创建对象的前提是需要有constructor,而这个constructor可能是对象自己本身显式定义的或者通过__proto__在原型链中找到的。而单从constructor这个属性来讲,只有prototype对象才有。每个函数在创建的时候,JS会同时创建一个该函数对应的prototype对象,而函数创建的对象.__proto__ === 该函数.prototype,该函数.prototype.constructor===该函数本身,故通过函数创建的对象即使自己没有constructor属性,它也能通过__proto__找到对应的constructor,所以任何对象最终都可以找到其构造函数(null如果当成对象的话,将null除外)。如下:
    constructor说明

    5. 总结

       总结一下:

    1. 我们需要牢记两点:①__proto__constructor属性是对象所独有的;② prototype属性是函数所独有的,因为函数也是一种对象,所以函数也拥有__proto__constructor属性。
    2. __proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链
    3. prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.__proto__ === Foo.prototype
    4. constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function

      本文就此结束了,希望对那些对JS中的prototype__proto__constructor属性有困惑的同学有所帮助。

    最后,感谢这两篇博文,本文中的部分内容参考自这两篇博文:

    小彩蛋:实现继承(相对完美、优雅)

    function inherit(Child, Parent) {
         // 继承原型上的属性 
        Child.prototype = Object.create(Parent.prototype)
         // 修复 constructor
        Child.prototype.constructor = Child
        // 存储超类
        Child.super = Parent
        // 静态属性继承
        if (Object.setPrototypeOf) {
            // setPrototypeOf es6
            Object.setPrototypeOf(Child, Parent)
        } else if (Child.__proto__) {
            // __proto__ es6 引入,但是部分浏览器早已支持
            Child.__proto__ = Parent
        } else {
            // 兼容 IE10 等陈旧浏览器
            // 将 Parent 上的静态属性和方法拷贝一份到 Child 上,不会覆盖 Child 上的方法
            for (var k in Parent) {
                if (Parent.hasOwnProperty(k) && !(k in Child)) {
                    Child[k] = Parent[k]
                }
            }
        }
    }
    

    若对你有帮助,可以支持一下作者创作更多好文章哦,一分钱也是爱~
    赞赏码

    展开全文
  • proto-源码

    2021-03-29 08:19:55
    proto
  • 原型 proto文件,包含生成http swagger文档的proto,以及生成grpc接口的proto make swagger_gen # 生成swagger.json make ui_run # 本地8080跑ui查看接口文档
  • C++的proto文件批处理转为python的proto。将文件拷贝到C++的proto文件下,直接运行即可生成python格式的proto文件
  • 多版本protobuf(protoc.exe),支持protoproto2、proto3
  • snsUnread.proto

    2021-05-10 17:31:11
    snsUnread.proto
  • proto 安装流程

    2018-11-21 19:11:23
    proto 安装流程
  • caffe.proto

    2018-08-23 12:16:33
    caffe.proto文件是一个消息格式文件,后缀名为proto. proto文件即消息协议原型定义文件,在该文件中可以通过使用描述性语言来定义程序中需要用到的数据格式
  • GameMsgProtocol.proto

    2021-07-18 11:21:06
    一个proto的实例,定义消息
  • proto2 proto3 变化

    千次阅读 2019-06-19 15:30:57
    总的来说,proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,建议使用 proto3 。 1、在第一行非空白非注释行,必须写: syntax = “proto3...

    总的来说,proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,建议使用 proto3 。

    1、在第一行非空白非注释行,必须写:

    syntax = “proto3”, 否则默认版本是proto2;

    2、字段规则移除了 “required”,并把 “optional” 改名为 “singular”;

    在 proto2 中 required 也是不推荐使用的。proto3 直接从语法层面上移除了 required 规则。

    3、“repeated”字段默认采用 packed 编码;

    在 proto2 中,需要明确使用 [packed=true] 来为字段指定比较紧凑的 packed 编码方式。

    4、语言增加 Go、Ruby、JavaNano 支持;

    5、移除了 default 选项;

    在 proto2 中,可以使用 default 选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。

    在字段被设置为默认值的时候,该字段不会被序列化。这样可以节省空间,提高效率。

    但这样就无法区分某字段是根本没赋值,还是赋值了默认值。这在 proto3 中问题不大,但在 proto2 中会有问题。

    比如,在更新协议的时候使用 default 选项为某个字段指定了一个与原来不同的默认值,旧代码获取到的该字段的值会与新代码不一样。

    • string, 默认值是空字符串(empty string)
    • bytes, 默认值是空bytes(empty bytes)
    • bool, 默认值是false
    • numeric, 默认值是0
    • enum, 默认值是第一个枚举值(value必须为0)
    • repeated,默认值为empty,通常是一个空list

    6、枚举类型的第一个字段必须为 0 ;

    这也是一个约定。

    7、移除了对分组的支持;

    分组的功能完全可以用消息嵌套的方式来实现,并且更清晰。在 proto2 中已经把分组语法标注为『过期』了。这次也算清理垃圾了。

    8、proto3代码在解析新增字段时,会把不认识的字段丢弃,再序列化后新增的字段就没了;

    在 proto2 中,旧代码虽然会忽视不认识的新增字段,但并不会将其丢弃,再序列化的时候那些字段会被原样保留。

    我觉得还是 proto2 的处理方式更好一些。能尽量保持兼容性和扩展能力,或许实现起来也更简单。proto3 现在的处理方式,没有带来明显的好处,但丢掉了部分兼容性和灵活性。

    [2017-06-15 更新]:经过漫长的讨论,官方终于同意在 proto3 中恢复 proto2 的处理方式了。

    9、移除了对扩展的支持,新增了 Any 类型;

    Any 类型是用来替代 proto2 中的扩展的。目前还在开发中。

    proto2 中的扩展特性很像 Swift 语言中的扩展。理解起来有点困难,使用起来更是会带来不少混乱。

    相比之下,proto3 中新增的 Any 类型有点像 C/C++ 中的 void* ,好理解,使用起来逻辑也更清晰。

    10、增加了 JSON 映射特性;

    展开全文
  • Proto2与Proto3区别

    2020-02-07 17:30:54
    使用 syntax = "proto3" 指定proto3,否则编译器会假定为proto2 proto3字段默认为singular,不需要显式添加 proto3移除required,proto2也不推荐使用required proto3 repeated默认设置[packed = true],proto2...
    • 使用 syntax = "proto3" 指定proto3,否则编译器会假定为proto2
    • proto3字段默认为singular,不需要显式添加
    • proto3移除required,proto2也不推荐使用required
    • proto3 repeated默认设置[packed = true],proto2需要显式设置
    • proto2可以使用default指定字段默认值,proto3移除default,strings默认是空字符,bool默认是false,数字类型默认是0等
      • 判断上要注意默认值,比如bool设置为false和默认值相同
      • 设为默认值,不会序列化这个字段,从而节省空间
      • 默认类型文档:https://developers.google.com/protocol-buffers/docs/proto3#default
    • proto3枚举类型第一个值必须为0,默认值为第一个值
    • proto3移除groups,proto2也废弃groups,可以用嵌套message代替
    • proto2和proto3 version 3.5及之后的版本 解析和序列化保留未知字段,proto3 version 3.5之前的版本丢弃未知字段
    • proto3移除extensions,增加Any,Any代替extensions
    • proto3增加json映射支持

     

    参考:

    https://blog.csdn.net/huanggang982/article/details/77944174

     

    展开全文
  • 原始数据 包含所有.proto文件
  • proto.zip

    2017-03-22 17:15:30
    lightcnn 训练的proto
  • Proto Thread库

    2018-12-10 08:08:50
    arduino里面的proto thread库,可以实现伪多线程操作。
  • timestamp.proto

    2019-04-09 09:57:04
    用于记录文件传输的时间戳,常常被包含在你自己写的proto文件下。
  • Unity Proto Demo

    2019-01-08 11:35:09
    博客地址:https://blog.csdn.net/qq_30259857/article/details/82858340 Proto解析demo
  • proto外部引入资源包

    2021-09-03 14:55:58
    proto外部引入包
  • proto-player-js
  • 一个protoc插件,它基于.proto文件中的字段选项在Go proto struct上生成Validate() error函数。 验证功能是代码生成的,因此不会因对嵌套消息的基于标签的反射而影响性能。 要求 目前已验证使用Protobuf验证程序可...
  • Protobuf 的 proto3 与 proto2 的区别

    千次阅读 2017-06-27 19:01:16
    本文转自:https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html总的来说,proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,...

    本文转自:https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html

    总的来说,proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,建议使用 proto3 。

    1、在第一行非空白非注释行,必须写:

    syntax = “proto3”;

    2、字段规则移除了 “required”,并把 “optional” 改名为 “singular”1;

    在 proto2 中 required 也是不推荐使用的。proto3 直接从语法层面上移除了 required 规则。其实可以做的更彻底,把所有字段规则描述都撤销,原来的 repeated 改为在类型或字段名后加一对中括号。这样是不是更简洁?

    3、“repeated”字段默认采用 packed 编码;

    在 proto2 中,需要明确使用 [packed=true] 来为字段指定比较紧凑的 packed 编码方式。

    4、语言增加 Go、Ruby、JavaNano 支持;

    5、移除了 default 选项;

    在 proto2 中,可以使用 default 选项为某一字段指定默认值。在 proto3 中,字段的默认值只能根据字段类型由系统决定。也就是说,默认值全部是约定好的,而不再提供指定默认值的语法。

    在字段被设置为默认值的时候,该字段不会被序列化。这样可以节省空间,提高效率。

    但这样就无法区分某字段是根本没赋值,还是赋值了默认值。这在 proto3 中问题不大,但在 proto2 中会有问题。

    比如,在更新协议的时候使用 default 选项为某个字段指定了一个与原来不同的默认值,旧代码获取到的该字段的值会与新代码不一样。

    另一个重约定而弱语法的例子是 Go 语言里的公共/私有对象。Go 语言约定,首字母大写的为公共对象,否则为私有对象。所以在 Go 语言中是没有 public、private 这样的语法的。

    6、枚举类型的第一个字段必须为 0 ;

    这也是一个约定。

    7、移除了对分组的支持;

    分组的功能完全可以用消息嵌套的方式来实现,并且更清晰。在 proto2 中已经把分组语法标注为『过期』了。这次也算清理垃圾了。

    8、旧代码在解析新增字段时,会把不认识的字段丢弃,再序列化后新增的字段就没了;

    在 proto2 中,旧代码虽然会忽视不认识的新增字段,但并不会将其丢弃,再序列化的时候那些字段会被原样保留。

    我觉得还是 proto2 的处理方式更好一些。能尽量保持兼容性和扩展能力,或许实现起来也更简单。proto3 现在的处理方式,没有带来明显的好处,但丢掉了部分兼容性和灵活性。

    [2017-06-15 更新]:经过漫长的讨论,官方终于同意在 proto3 中恢复 proto2 的处理方式了。

    9、移除了对扩展的支持,新增了 Any 类型;

    Any 类型是用来替代 proto2 中的扩展的。目前还在开发中。

    proto2 中的扩展特性很像 Swift 语言中的扩展。理解起来有点困难,使用起来更是会带来不少混乱。

    相比之下,proto3 中新增的 Any 类型有点像 C/C++ 中的 void* ,好理解,使用起来逻辑也更清晰。

    10、增加了 JSON 映射特性;

    语言的活力来自于与时俱进。当前,JSON 的流行有其充分的理由。很多『现代化』的语言都内置了对 JSON 的支持,比如 Go、PHP 等。而 C++ 这种看似保罗万象的学院派语言,因循守旧、故步自封,以致于现出了式微的苗头。

    展开全文
  • proto3文档介绍

    2018-03-29 14:51:46
    data, including .proto #le syntax and how to generate data access classes from your .proto #les. It covers the proto3 version of the protocol buffers language: for information on the older proto2 ...
  • proto编译

    2018-12-08 17:19:19
    .proto文件位置:.../protoFiles/music/songName.proto  .../protoFiles/music/artistName.proto  .../protoFiles/contact/friendName.proto  ...
  • 为__proto__提供一些限制 需要此polyfill的浏览器 在通常不提供__proto__ Object.defineProperty支持Object.defineProperty , Object.getPrototypeOf , Object.getOwnPropertyNames , Object....
  • proto3与proto2的区别

    千次阅读 2020-03-13 15:47:33
    总结:proto3比proto2支持的语言更多,语法更简洁。去掉了复杂的语法和特性,更强调约定而弱化语法。 1在第一回非空白非注释行,写明语法:syntax = “proto3”; 2 字段规则移除了"required",所有非repeated的字段...
  • proto命令

    2018-09-21 14:32:52
    生成proto的go文件 protoc --go_out ./ msg.proto //注意空格 生成grpc格式 protoc --go_out=plugins=grpc:. user.proto
  • proto-deps-源码

    2021-03-31 02:30:09
    proto-deps
  • kazen_proto-源码

    2021-03-22 07:36:15
    kazen_proto
  • kmp-proto-源码

    2021-03-21 03:38:37
    kmp-proto
  • Amzl_Proto-源码

    2021-03-14 13:59:29
    Amzl_Proto
  • blog_proto-源码

    2021-03-12 14:59:20
    blog_proto

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,354
精华内容 73,341
关键字:

proto