JavaScript中Object和Function及其prototype之间的关系

引子

在nodejs中执行如下代码

> Object instanceof Function
true

> Function.prototype instanceof Object
true

> Function instanceof Function
true

是不是有点迷惑?

instanceof的真实含义

在js中判断某个实例是否某个类的实例,我们可以是用如下代码:

function Test() {}
var t = new Test();
t instanceof Test;  // true

从字面上看,要表达的意思很直接。然而让我们hack一下代码,看看会发生什么:

var testPrototype = Test.prototype;
Test.prototype = {};
t instanceof Test;  // false

当Test类的原型更新为另一个对象时,之前用Test创建的实例其原型不变,依旧是Test上原先的prototype。从这个例子可以看出,我们可以大致这么理解instanceof这个语法:

t inheritsFrom Test.prototype

为了获得或判断t的真实原型,ES5提供了Object.getPrototypeOf()和Object.prototype.isPrototypeOf()方法:

Object.getPrototypeOf(t) === testPrototype;  // true
testPrototype.isPrototypeOf(t);  // true

构造函数只是实例和原型的连接器

当使用构造函数创建对象后,对象与其原型已经联系起来,之后构造函数对于这两者已经没有什么存在的意义了。我们用猎头撮合人才与公司签订劳动协议来举例子:

          劳动协议签订完毕
人才 --------------------------> 公司

       猎头:没我什么事儿了……

这个法则也适用于js对象的原型继承:

            继承关系建立
实例 --------------------------> 原型

       构造函数:没我什么事儿了……

构造函数就像中介,用来联系实例和原型。构造函数和原型虽然有prototype属性联系,但他们真的没什么大关系。

整理混乱的关系

在js中不污染prototype时具有以下规则:
– 所有function都继承自Function.prototype
– Object构造函数也是function,因此也继承自Function.prototype
– Function构造函数也是function,因此也继承自Function.prototype
– Function.prototype继承自Object.prototype,但增加了callable的支持,即可以在标识符后边使用()来触发调用

继承关系图

Object.prototype
        ^
        |
Function.prototype
    ^        ^
    |        |
 Object   Function

验证代码:

> Object.getPrototypeOf(Object.prototype) === null
true

> Object.getPrototypeOf(Function.prototype) === Object.prototype
true

> Object.getPrototypeOf(Object) === Function.prototype
true

> Object.getPrototypeOf(Function) === Function.prototype
true

在有CSS transform属性的元素内position fixed定位错误的解释

当容器元素具有CSS transform定义时,会隐式地生成定位容器,transform容器及其子元素都会相对于该隐式容器做transform变换,即便内部元素具有position:fixed也无法逃脱,其行为就好像设置了position:absolute,详见参考资料。

参考资料

https://stackoverflow.com/questions/9115880/css-transform-translate-moves-postionfixed-inner-div

https://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/

更改systemd服务同时打开的文件数

更改ulimit配置文件是不起作用的,需要修改service单元文件:

[Service]
LimitNOFILE=8192

有效的Limit选项可以运行man 5 systemd.exec查看。

  LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=,
       LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=,
       LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=,
       LimitRTTIME=
           These settings control various resource limits for executed
           processes. See setrlimit(2) for details. Use the string infinity to
           configure no limit on a specific resource.

参考资料:

https://serverfault.com/questions/649577/how-can-i-permanently-set-ulimit-n-8192-in-centos-7#answer-720596

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-unit_files#sect-Managing_Services_with_systemd-Unit_File_Create

https://access.redhat.com/solutions/1257953

Win10虚拟机初始化配置一般流程

  • 禁用自动更新(gpedit.msc->计算机配置->管理模板->Windows组件->Windows更新,配置自动更新,已禁用)
  • 禁用Microsoft Defender防病毒(gpedit.msc->计算机配置->管理模板->Windows组件->Microsoft Defender防病毒程序,关闭Microsoft Defender防病毒程序,已启用)(较旧版本系统替换上述名称:s/Microsoft/Windows/g)
  • 禁用Windows Defener实时保护
  • 禁用Cortana(gpedit.msc->计算机配置->管理模板->Windows组件->搜索,允许使用Cortana,已禁用)
  • 禁用云搜索(gpedit.msc->计算机配置->管理模板->Windows组件->搜索,允许云搜索,已禁用)
  • 禁用遥测(gpedit.msc->计算机配置->管理模板->Windows组件->数据收集和预览版本,允许遥测,已禁用)
  • 禁用OneDrive(gpedit.msc->计算机配置->管理模板->Windows组件->OneDrive,禁止使用OneDrive进行文件存储,已启用)
  • 禁用电源计划,从不关闭屏幕,从不睡眠
  • 禁用休眠,管理员方式运行powercfg -h off
  • 禁用磁盘碎片整理任务计划
  • 禁用系统保护
  • 禁用任务计划
    • Library->Microsoft->Windows->Application Experience->Microsoft Compatibility Appraiser
    • Library->Microsoft->Windows->MemoryDiagnostic->RunFullMemoryDiagnostic
  • 卸载OneDrive
  • 卸载Cortana
  • 浏览器默认首页为新建标签页
  • 停用不必要的服务
    • Connected User Experiences and Telemetry
    • Diagnostic Execution Service
    • Diagnostic Policy Service
    • Diagnostic Service Host
    • Diagnostic System Host
    • Superfetch(SysMain)
    • Windows Search
      $services=Get-Service -Name   DiagTrack,diagsvc,DPS,WdiServiceHost,WdiSystemHost,SysMain,WSearch
      $services | Stop-Service
      $services | Set-Service -StartupType Disabled
      
  • 禁用传递优化(设置->更新和安全->传递优化->允许从其他电脑下载->关)
  • 启用桌面图标(可选),运行RUNDLL32 SHELL32.DLL,Control_RunDLL DESK.CPL,,0
  • 打开照片app,在设置中取消“关联各个复本”
  • 打开应用商店app,在设置中取消“自动更新应用”
  • 输入法默认输入状态为英文,禁用表情(可选)
  • 锁屏界面使用图片(可选)
  • 禁用隐私追踪(设置->隐私->常规)

Win 11
管理员运行oobe\ByPassNRO.cmd

OpenSSL自签名证书

本文只讨论使用RSA算法的x509证书。本文在撰写时使用特定版本的openssl,但大部分情况下也应该适用于其它版本。

$ openssl version
OpenSSL 1.1.0f  25 May 2017

1 生成

生成自签名证书可分为使用基本步骤和快捷步骤。快捷步骤只是通过特殊选项合并基本步骤中的一步或两步。通过openssl生成的文件默认都是PEM格式,可直接用于apache或nginx。如使用IIS需要在生成后转换为pfx格式。

1.1 基本步骤

生成自签名证书的基本步骤如下:
– 生成私钥(Private Key)文件
– 生成证书(签名)请求文件CSR,需要使用私钥
– 生成自签名证书(Certificate)文件,需要使用证书请求文件

1.1.1 步骤1 生成RSA私钥(Private Key)

RSA私钥中也包含公钥。命令为openssl genrsa,格式:

openssl genrsa [<options>] <bit-length>
    [-des3 | -aes128 | ...]     #指定用于保护私钥的对称加密算法
        [-passout pass:<password> | -passout file:<path-name> | -passout env:<variable> | -passout fd:<file-descriptor> | -passout stdin]   #指定输出私钥的加密密码来源
    -out <private-key-file>     #输出私钥到文件,不指定则输出到stdout

举例,生成一个长度为2048位的RSA私钥(含公钥):

openssl genrsa -out ca.key 2048

举例,生成一个长度为2048位,并用aes128加密的私钥,密码为1234:

openssl genrsa -aes128 -passout pass:1234 -out ca-pass.key

1.1.2 步骤2 用私钥生成证书签名请求(Certificate Signing Request, CSR)

命令为openssl req,格式:

openssl req
    -new    #生成新的证书签名请求
    -key <private-key>  #在步骤1中生成的私钥
    [-passin pass:<password> | -passin file:<path-name> | -passin env:<variable> | -passin fd:<file-descriptor> | -passin stdin]    #指定所用私钥的密码
    -subj '/C=<country>/ST=<province>/L=<locality>/O=<organiation>/OU=<organiation-unit>/CN=<common-name>/emailAddress=<email>'
    -out <csr-file>     #输出证书请求到文件,不指定则输出到stdout

选项-subj指定证书所有人主体信息,如果证书用于网站,则其中的CN域必须指定为网站域名,其他域不是必填项。
举例,为www.mysite.com生成证书签名请求:

openssl req -new -key ca.key -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=CompanyName/OU=DepartmentName/CN=www.mysite.com' -out mysite.csr

举例,为www.mysite.com生成证书签名请求,同时指定之前生成私钥时所用密码:

openssl req -new -key ca-pass.key -passin pass:1234 -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=CompanyName/OU=DepartmentName/CN=www.mysite.com' -out mysite.csr

1.1.3 步骤3 生成自签名证书

步骤3有两种命令可以实现,分别是openssl req -x509和openssl x509 -req。有一点小区别是前者使用-key指定私钥,后者用-signkey指定私钥。

步骤3方法1 openssl req -x509

命令openssl req格式

openssl req
    -x509   #生成自签名证书,而不是证书请求
    -days <days>    #指定证书有效期天数
    -md2 | -md5 | -sha1 | -sha256 | -sha512     #签名所用哈希算法
    -key <private-key-file>
    -in <csr-file>
    -out <certificate-file>

举例,为证书请求文件签名并生成证书:

openssl req -x509 -days 365 -sha256 -key ca.key -in mysite.csr -out mysite.crt

步骤3方法2 openssl x509 -req

命令openssl x509格式:

openssl x509
    -req    #输入内容为证书请求,而不是证书
    -days <days>    #指定证书有效期天数
    -md2 | -md5 | -sha1 | -sha256 | -sha512     #签名所用哈希算法
    -signkey <private-key-file>
    -in <csr-file>
    -out <certificate-file>     #输出证书到文件,不指定则输出到stdout

举例,为证书请求文件签名并生成证书:

openssl x509 -req -days 365 -sha256 -signkey ca.key -in mysite.csr -out mysite.crt

此方法似乎不会读取/etc下的openssl.cnf的设置(不同发行版路径不同,使用find /etc/ -name openssl.cnf查找),如果在其中有设置subjectAltName不会起作用。

1.2 快捷步骤

可以合并基本步骤中的一步或两步,来减少命令输入量。快捷步骤总是以基本步骤2(openssl req)为基础,通过增加额外的选项来合并其它步骤。

1.2.1 基本步骤1,2一起做

如果还未生成私钥,可以在基本步骤2的命令openssl req的基础上,用-newkey代替-key,来指明生成证书请求的同时生成私钥。与私钥有关的基本步骤1中的选项便可以同时出现。

    -newkey <type:length>   #指定私钥类型及长度,如rsa:2048
    -keyout <private-key-file>
    -nodes  #不要为私钥使用对称密钥加密,相当于基本步骤1中不指定加密算法

举例,使用一条命令生成私钥和证书签名请求:

openssl req -new -newkey rsa:2048 -keyout ca.key -passout pass:1234 -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=CompanyName/OU=DepartmentName/CN=www.mysite.com' -out mysite.csr

其中-passout来自于基本步骤1中的选项。

1.2.1 基本步骤2,3一起做

如果已经有了私钥,也可以合并基本步骤2,3,来直接生成证书,而跳过证书请求。在基本步骤2的命令openssl req的基础上,用-x509代替-new:

    -x509   #生成自签名证书,而不是证书请求

相当于把基本步骤2(openssl req)和基本步骤3方法1(openssl req -x509)合并起来。
举例,利用已有私钥,通过一条命令来生成自签名证书:

openssl req -new -x509 -key ca.key -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=CompanyName/OU=DepartmentName/CN=www.mysite.com' -days 365 -sha256 -out mysite.crt

1.2.2 基本步骤1,2,3一起做

如果要同时生成私钥和自签名证书,也可以用一条命令完成,只要把合并步骤1,2及合并步骤2,3的选项放在一起便可。
举例,通过一条命令生成私钥和自签名证书

openssl req -x509 -newkey rsa:2048 -keyout ca.key -nodes -subj '/C=CN/ST=ZheJiang/L=HangZhou/O=CompanyName/OU=DepartmentName/CN=www.mysite.com' -days 365 -sha256 -out mysite.crt

2. 利用私钥和现有证书重新生成证书签名请求

可以通过基本步骤1产生的私钥和基本步骤3产生的证书来重新生成证书请求文件,而无须重新指明主体信息。
在使用自签名证书的情形下作用不大,但如果曾经把证书请求提供给第三方进行过签名,那么通过此方法可以快速重新生成证书请求文件,从而再次申请签名。

命令为openssl x509 -x509toreq,格式:

    -x509toreq  #将x509证书转换为证书请求
    -signkey <private-key-file>
    -in <certificate-file>
    -out <csr-file>     #输出证书请求到文件,不指定则输出到stdout

举例,通过私钥和证书,生成证书请求文件:

openssl x509 -x509toreq -signkey ca.key -in mysite.crt -out mysite.csr

3 查看信息

查看信息的共有选项如下,不再单独列出:

    -text   #解析原始内容,以可理解的方式输出信息
    -noout  #不输出原始内容
    [-passin pass:<password> | -passin file:<path-name> | -passin env:<variable> | -passin fd:<file-descriptor> | -passin stdin]
    -in <input-file>    #指定输入内容的来源
    -out <output-file>  #指定输出到文件,不指定则输出到stdout

3.1 查看私钥信息

使用openssl rsa命令,举例:

openssl rsa -text -noout -in ca.key

3.2 查看证书签名请求信息

使用openssl req命令,举例:

openssl req -text -noout -in mysite.csr

3.3 查看证书信息

使用openssl x509命令,举例:

openssl x509 -text -noout -in mysite.crt

4 MinGW/MSYS/git-bash for Windows下生成证书时报错:Subject does not start with ‘/’

解决方案与原因详见:https://stackoverflow.com/questions/31506158/running-openssl-from-a-bash-script-on-windows-subject-does-not-start-with