惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
Scott Helme
Scott Helme
NISL@THU
NISL@THU
T
Tor Project blog
T
Tenable Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Privacy International News Feed
Cyberwarzone
Cyberwarzone
Project Zero
Project Zero
S
Schneier on Security
C
Cybersecurity and Infrastructure Security Agency CISA
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
O
OpenAI News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
V2EX - 技术
V2EX - 技术
H
Help Net Security
C
Check Point Blog
T
The Exploit Database - CXSecurity.com
Forbes - Security
Forbes - Security
人人都是产品经理
人人都是产品经理
U
Unit 42
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
I
InfoQ
Schneier on Security
Schneier on Security
K
Kaspersky official blog
罗磊的独立博客
Cisco Talos Blog
Cisco Talos Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
雷峰网
雷峰网
G
GRAHAM CLULEY
Cloudbric
Cloudbric
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
AI
AI
L
LINUX DO - 热门话题
云风的 BLOG
云风的 BLOG
博客园_首页
T
Threat Research - Cisco Blogs
S
Secure Thoughts
有赞技术团队
有赞技术团队

f2h2h1's blog

使用yii3实现一个微框架 claw养殖技术 计算机网络基础知识 定时任务 ACME的使用经验 magento2加上varnish缓存 开发Magento2的模块 在magento2中使用persisted-query socket编程 一些开发笔记 一段CSDN文章主要内容的油猴脚本 电子邮件的不完整总结 git的笔记 在Windows下配置PHP服务器 终端,控制台和外壳 PHP各种运行方式的不完整总结 把网页导出成PDF 和颜色相关的笔记 HTTP认证方式的不完整总结 SEO的经验 密码学入门简明指南 文件的上传和下载 用纯CSS3实现的滑动按钮 在VSCode里调试PHP Linux的GUI 关于字符编码的一些坑 nc的使用和原理 在Windows下安装Magento2 使用docker-compose部署magento2 浏览器和服务器通讯方式的不完整总结 观察网站性能 一些关于Linux的笔记 telnet的不完整总结 在Windows下安装pear MySQL的时间类型和时间相关的函数 Windows下通过PEB读取进程的环境变量 关于 在VSCode里使用Xdebug远程调试PHP 在Windows下搭建git服务 关于环境变量的不完整总结 使用shell实现的kv数据库 如何完成以xx管理系统为选题的毕业设计 数字号码资源 各种标记语言 使用PowerShell实现的http服务器 kind相关经验 DNSSEC简介 nginx+ffmpeg+websocket实现的直播例子 使用Tesseract识别字符验证码 使用docker部署nuxt FirstData后台的设置 paypal,firtdata,支付宝的不完整接入指南 微信支付的不完整接入指南 用docker-compose部署lnmp环境 mongodb分片 练习
对JS原型链的理解
2025-02-27 · via f2h2h1's blog

JS 的类型

js 里有七种原始类型和 Object

  • undefined
  • boolean
  • number
  • string
  • bigint
  • symbol
  • null

原始类型

number 是基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(253 -1) 到 253 -1)。 它并没有为整数给出一种特定的类型。 除了能够表示浮点数外,还有一些带符号的值:+Infinity,-Infinity 和 NaN (非数值,Not-a-Number)。

bigint 可以用任意精度表示整数。 在将 bigint 转换为 boolean 时,它的行为类似于一个 number 。 bigint 不能与 number 互换操作。否则,将抛出 TypeError 。

bigint 和 symbol 都是 es2015 新增的,平时接触得比较少。 symbol 可以简单但不严谨地类比成 C 里面的枚举类型。

基本字符串和字符串对象的区别

请注意区分 JavaScript 字符串对象和基本字符串值。( 对于 Boolean 和Numbers 也同样如此。)

字符串字面量 (通过单引号或双引号定义) 和 直接调用 String 方法(没有通过 new 生成字符串对象实例)的字符串都是基本字符串。

JavaScript 会自动将基本字符串转换为字符串对象,只有将基本字符串转化为字符串对象之后才可以使用字符串对象的方法。

当基本字符串需要调用一个字符串对象才有的方法或者查询值的时候(基本字符串是没有这些方法的), JavaScript 会自动将基本字符串转化为字符串对象并且调用相应的方法或者执行查询。

参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String

Object

Object 是引用类型。 大多数情况下引用类型的赋值都是浅拷贝,例如这样。要完整地复制一个对象,需要深拷贝(这是一个可以单独写一篇文章的主题)。

// 引用数据类型赋值
var a = {name: '张三'};
var b = a;
console.log(a); // {name: "张三"}
console.log(b); // {name: "张三"}

函数是 Object , 数组是 Object , 可以简单但不严谨地理解为,除了原始类型之外都是 Object 。

null 和 undefined

  • 一个变量已声明未赋值是 undefined
  • 直接使用未声明的变量会抛错误
  • 也可以直接给变量赋值 undefined
  • null 一般是需要特意赋值或者是原型链的尽头
  • null 和 undefined 转换为布尔值时都是 false
  • null 转换数据类型 number 时会转换为 0
  • undefined 转换数据类型 number 时会转换为 NaN
  • 试图访问对象不存在的属性时会返回 undefined

NaN 是一个特殊的值,但在 es2015 里, NaN 是 Number 的一个属性。 NaN 最好只用来判断一个变量是不是数字。

类型检测

typeof 只能检测原始数据类型。 数组,对象这类的全都是返回 object 。 但 null 也是返回 object 。 但函数返回的是 function 。

笔者认为的检测类型最安全的方法是 Object.prototype.toString.call(variable)

对象和函数

对象

对象分类:

  1. 内置对象
    • 由 es 标准中定义的对象,在任何的 es 的环境中都可以使用,例如:Object Function Array Math Date 等
  2. 宿主对象
    • 由 js 的运行环境提供的对象,例如由浏览器提供的对象:BOM(浏览器对象模型) DOM(文档对象模型)
  3. 自定义对象
    • 由开发者创建的对象

在 js 里每一个对象都有一个原型。 对象的原型也是一个对象。 对象会继承原型的属性和方法。 对象会覆盖原型里同名的属性和方法。 所有对象的原型最终都会指向 Object.prototype 。 Object.prototype 的原型是 null 。 可以通过 __proto__ 属性或 Object.getPrototypeOf() 来访问原型。

函数

函数可以理解成一个变量。 函数的类型是 Object 。 函数名和变量名相同时会提示语法错误。 Function 是一种对象。 function 是一个用于声明对象的关键字。

// 一个函数的声明
function a(){};
// 也可以写成这样
var a = function(){};

函数都有一个名为 prototype 的属性,这个属性的值是一个对象。 这个对象会被称为函数的原型对象。 原型对象会有一个名为 constructor 的属性,这个属性会指向函数本身。

prototype 和 __proto__ 是不一样的。 prototype 只有函数才有, __proto__ 所有对象都有。 函数也有 __proto__ 属性。

所有函数的原型最终都会指向 Function.prototype 。 Function.prototype 的原型是 Object.prototype 。 Object.prototype 的原型是 null 。

Function 的 prototype 和 __proto__ 是相等的

console.log(Object.is(Object.getPrototypeOf(Function), Function.prototype)); // true

new 运算符

new 关键字会进行如下的操作:

  1. 创建一个空的简单 JavaScript 对象(即{});
  2. 为步骤1新创建的对象添加属性 __proto__ ,将该属性链接至构造函数的原型对象 ;
  3. 将步骤1新创建的对象作为 this 的上下文 ;
  4. 如果该函数没有返回对象,则返回 this 。

例子

(function(){
    let a = function(){};
    let b = new a();
    console.log(Object.is(b.__proto__, a.prototype)); // true;
    console.log(Object.is(a, a.prototype.constructor)); // true;
    console.log(Object.is(a.__proto__, Function.prototype)); // true;
    console.log(Object.is(Function.prototype.__proto__, Object.prototype)); // true;
})();

根据上面的例子, a 会被称为构造函数, b 会被称为 a 的实例。 a 本质上只是一个普通的函数,但使用 new 运算符创建新的对象 b 时, a 就可以被称为构造函数。 在一些语境下 a 也会被称为类。

参考

原型链

需要关注这三个属性

  • prototype
    • 这个属性只有函数才有
    • 指向函数的原型对象
  • constructor
    • 这个属性只有函数的原型对象才有
    • 指向函数本身
  • __proto__
    • 这个属性只要是对象都有
    • 指向对象的原型

在访问对象的属性时,会先查找自身的属性,如果没有找一级一级地向上查找原型的属性。 试图访问对象不存在的属性时会遍历整个原型链。

@startuml
(null)
(Object.prototype)
(Function.prototype)
(Array.prototype)
(function Function) as funFunction
(function Object) as funObject
(function Array)as funArray
(function Example)as funExample
(Example.prototype)
(exampleObj)
(exampleArr)
(var obj = new Object<U+0028><U+0029>) as obj1
(var fun = new Function<U+0028><U+0029>) as fun1

Object.prototype --> null : "<U+005F>_proto__"
Function.prototype --> Object.prototype : "<U+005F>_proto__"
Example.prototype --> Object.prototype : "<U+005F>_proto__"
Array.prototype --> Object.prototype : "<U+005F>_proto__"
funFunction --> Function.prototype : "<U+005F>_proto__"
funObject --> funFunction : "<U+005F>_proto__"
funArray --> funFunction : "<U+005F>_proto__"
funExample --> funFunction : "<U+005F>_proto__"
exampleObj --> Example.prototype : "<U+005F>_proto__"
exampleArr --> Array.prototype : "<U+005F>_proto__"
obj1 --> Object.prototype : "<U+005F>_proto__"
fun1 --> Function.prototype : "<U+005F>_proto__"

funArray --> Array.prototype : "prototype"
funExample --> Example.prototype : "prototype"
funFunction --> Function.prototype : "prototype"
funObject --> Object.prototype : "prototype"

Array.prototype --> funArray : "constructor"
Example.prototype --> funExample : "constructor"
Function.prototype --> funFunction : "constructor"
Object.prototype --> funObject : "constructor"
@enduml

js 的原型链

这个图里, function Excemple 是自定义的函数。 function Array 是 js 的内置函数。

in 和 hasOwnProperty 的区别

  • 都是用来判断对象是否存在某个属性
  • hasOwnProperty 只能判断是否是属于自身的属性,不会查找原型链上的属性
  • in 能查找原型链上的属性

例子

(function(){
    let Person = function() {};
    Person.prototype.lastName = "Deng";
    let person = new Person();
    person.age = 12;
    console.log(person.hasOwnProperty('lastName')); // false
    console.log(person.hasOwnProperty('age')); // true
    console.log('lastName' in person); // true
    console.log('age' in person); // true
})()

getPrototypeOf 和 __proto__

__proto__ 是已经废弃了的属性 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

标准是使用 Object.getPrototypeOf() 方法替代 __proto__

其它

原生原型不应该被扩展,除非它是为了与新的 JavaScript 特性兼容。

不建议重新定义原型,不要重新定义函数的 prototype 属性。

直接通过 console.log 输出的对象数据时,总是和预期的有一点不一样。 可能大概是因为这样,所以 es2015 才会要求使用 Object.getPrototypeOf() 方法获取对象原型而不是通过 __proto__ 属性获取对象原型。

js 是一种函数优先的编程语言,函数可以作为变量、参数、返回值。 js 也是一种面向对象的编程语言,但和 Java C++ 不同的是, js 并没有区分 类 和 对象。 js 只有对象,并使用原型链的方式来实现对象的继承。

class 只是原型链的语法糖。

除了原型链之外 js 还有很多语法细节上的坑,例如 this 闭包 事件循环 IIFE

参考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

https://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

https://www.liaoxuefeng.com/wiki/1022910821149312/1023021997355072

https://zh.javascript.info/prototype-inheritance