目录

  • 一切皆是对象吗?
  • 对象
    • 原型与原型链
    • 构造函数
  • 参考

1.一切皆是对象吗?

首先,“在 JavaScript 中,一切皆是对象”这种表述是不完全正确的。

JavaScript 的数据类型分为两类:原始值类型和对象(Object类型)。

原始值类型(ES5):

  • undefined
  • null - typeof null 的值为"object",是因为 ES5 规范规定:对于 null 值的 typeof 字符串值返回"object"
  • true/false - 布尔值
  • number
  • string
var a = undefined
var b = null
var c = true
var d = 1
var e = "abc"

这些值是在底层上直接实现的,它们不是object,所以没有原型(__proto__),没有构造函数(constructor)。

但我们再实践过程中,会发现虽然字符串,布尔值和数字是原始值类型,但却表现得有点像对象。

以字符串为例:

在上图中,可以看到定义了一个值为"abc"的字符串变量 e,访问其 _proto_ 和 constructor 属性,发现其居然有值?不是说原始值类型没有原型和构造函数,这是怎么回事呢?

原来原始值类型(布尔值、数字、字符串)有其对应的包装器对象:Boolean(布尔对象)、Number(数字对象)、String(字符串对象),在这些原始值类型上尝试调用属性或方法(比如 constructor 等)时,JS会自动进行 Auto-Boxing(临时包装)的过程,首先将其转换为临时包装器对象,再访问其上的属性或方法,而不会影响原始值类型的属性。

这也能解释为什么我们直接对原始值类型变量(布尔值、数字、字符串)添加了一些属性,再次访问依旧为 undefined,因为我们访问属性操作的是临时包装器对象,不会影响基本原始值类型本身。如下图:

而原始值类型(null 与 undefined)没有对应的包装器对象,所以在其上尝试访问任何属性或方法都会报错。如下图:

2.对象

在JS中,Object 是一个属性的集合,并且拥有一个单独的原型对象 [prototype object] (其可以是一个 object 或 null 值)。

在浏览器或 Node.js 中,可以通过 _proto_ 属性访问这个原型对象, _proto_ 被称为该对象的原型,但为了和函数的原型属性(prototype)区分,一般称其为隐式原型。

var position = {
x: 10,
y: 20,
z: 30,
}

上面的代码中,对象与隐式原型的关系如下图:

(1)原型与原型链

在JS中,对象的继承关系是通过隐式原型(__proto__)来实现的。对象的隐式原型在对象创建时由对象的构造函数自动关联,也可以通过修改隐式原型,更改对象的继承关系。

由 Object 构造函数创建的对象,其隐式原型指向 Object.prototype。而 Object.prototype 对象的隐式原型的值默认为 nulll。

代码示例:

// x, y, z 的隐式原型 __proto__ 默认都指向 Object.prototype
var x = {
a: 10,
}
var y = {
a: 20,
b: 30,
}
var z = {
a: 40,
b: 50,
c: 60,
} // 设置 x 的隐式原型为 y
// 设置 y 的隐式原型为 z
x.__proto__ = y
y.__proto__ = z console.log(x.a) // 10 - 来自 x 自身的属性
console.log(x.b) // 30 - 来自 y 的属性
console.log(x.c) // 60 - 来自 z 的属性 // 修改 y 的属性 b 的值
y.b = 70 console.log(x.b) // 70 - 来自 y 的属性 // 移除 z 的属性 c
delete z.c console.log(x.c) // undefined - 沿着隐式原型一级一级往上找,没有找到该属性

从上述代码,我们可以看到,当访问一个对象的属性时,会优先在这个对象的属性中查找是否存在所要访问的属性,若存在,则获取成功,停止查找;若没有找到该属性,则会继续去查找该对象的隐式原型中是否存在,若存在,则获取成功,停止查找;若还是没有查找到,将继续再往上一级的隐式原型中查找,直到找到则返回找到的属性值 或 直到遇到隐式原型值为 null 则返回 undefined。

这种由原型相互关联(指向)的关系就形成了所谓的原型链,而对象的属性或方法的查找就是沿着原型链顺序进行查找的。

上述代码示例中的原型链关系如下图:

(2)构造函数

首先要明白,函数也是一个特殊的对象,除了和其他对象一样有 _proto_ 属性外,还有自己特有的属性——显示原型(prototype),这个属性指向一个对象,其用途就是包含所有实例共享的属性和方法。显示原型对象也有一个 constructor 属性,这个属性指向原构造函数。

而所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。而JS中所有函数(除了箭头函数)都可以当做构造函数。

一个对象由构造函数创建时,其隐式原型(__proto__)指向构造该对象的构造函数(constructor)的显示原型(prototype),这保证了实例能够访问在构造函数原型中定义的属性和方法。

代码示例:

// 构造函数 C
function C(x) {
this.x = x
} // 继承属性 y
C.prototype.y = 30 // new 两个对象实例a、b
var a = new C(10)
var b = new C(20) console.log(a.x) // 10
console.log(a.y) // 30
console.log(b.x) // 20
console.log(b.y) // 30 // 对象实例 a、b 的隐式原型(__proto__)指向构造该对象的构造函数 C 的显示原型(prototype)
console.log(a.__proto__ === C.prototype) // true
console.log(b.__proto__ === C.prototype) // true // 构造函数的显示原型(prototype)的 constructor 属性指向原构造函数
console.log(C === C.prototype.constructor) // true // 构造函数 C、Function 与 Object 的隐式原型(__proto__)指向构造该对象的构造函数 Function 的显示原型(prototype)
console.log(C.__proto__ === Function.prototype) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true // C.prototype 与 Function.prototype 的隐式原型(__proto__)指向构造该对象的构造函数 Object 的显示原型(prototype)
console.log(C.prototype.__proto__ === Object.prototype) // true
console.log(Function.prototype.__proto__ === Object.prototype) // true // Object.prototype 的隐式原型(__proto__)等于 null
console.log(Object.prototype.__proto__ === null) // true

上述代码示例中的完整原型链关系如下图:

从上图我们可以总结:

  1. 所有的(隐式)原型链的最末端最终都会指向 null(JS不允许有循环原型链,避免死循环)

  2. 所有(非继承的)函数默认都是由 Function 构造函数创建,即所有(非继承的)函数的隐式原型(__proto__)都指向 Function.prototype。

  3. 所有对象默认都继承自Object对象,即默认情况下,所有对象的(隐式)原型链的末端都指向 Object.prototype。

注:所谓默认情况,即没有手动修改原型链关系。

3.参考

JS中一切都是对象吗?看这一篇就知道了

js中__proto__和prototype的区别和关系?

深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)

深入理解JavaScript系列(18):面向对象编程之ECMAScript实现(推荐)

深入理解JS中的对象(一)的更多相关文章

  1. 深入理解JS中的对象(二):new 的工作原理

    目录 序言 不同返回值的构造函数 深入 new 调用函数原理 总结 参考 1.序言 在 深入理解JS中的对象(一):原型.原型链和构造函数 中,我们分析了JS中是否一切皆对象以及对象的原型.原型链和构 ...

  2. 深入理解JS中的对象(三):class 的工作原理

    目录 序言 class 是一个特殊的函数 class 的工作原理 class 继承的原型链关系 参考 1.序言 ECMAScript 2015(ES6) 中引入的 JavaScript 类实质上是 J ...

  3. 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承

    ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...

  4. 和我一起理解js中的事件对象

    我们知道在JS中常用的事件有: 页面事件:load: 焦点事件:focus,blur: 鼠标事件:click,mouseout,mouseover,mousemove等: 键盘事件:keydown,k ...

  5. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

  6. 浅解析js中的对象

    浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...

  7. JS中的对象和方法简单剖析

    众所周知,在js中对象就是精髓,不理解对象就是不理解js. 那么什么事js中的对象呢? 在js中,几乎一切皆对象: Boolean ,String,Number可以是对象(或者说原生数据被认作对象): ...

  8. 如何更好的理解js中的this,分享2段有意思的代码

    关于js中this的浅析,大家可以点击[彻底理解js中this的指向,不必硬背]这篇博客了解. 今天遇到2段比较有意思的代码. ----------------第一段----------------- ...

  9. 图文结合深入理解 JS 中的 this 值

    图文结合深入理解 JS 中的 this 值 在 JS 中最常见的莫过于函数了,在函数(方法)中 this 的出现频率特别高,那么 this 到底是什么呢,今天就和大家一起学习总结一下 JS 中的 th ...

随机推荐

  1. 用three.js开发三维地图实例

    公司要做智慧消防楼层可视化,需要用到web3d,开源的引擎中先研究了cesium三维地球,但cesium做楼层感觉是大材小用,而且体验也不好,最终选用的是功能强大.更适合小型场景的three. thr ...

  2. go开发包下载,IDE工具下载,基础配置命令

    目录 go语言介绍 go开发包下载 命令介绍 配置 修改配置 golandIDE工具下载 编译并执行命令 命令 go语言介绍 # 1 诞生于 2009年,10年的时间,非常新的语言,天然支持并发,很新 ...

  3. C. Standard Free2play --div

    https://codeforces.com/contest/1238/problem/C 题意:下台阶的时候只有一种方式,拉动当前台阶x的 level,然后当前的台阶关闭,调到下边的台阶x-1,如果 ...

  4. 深入浅出node.js游戏服务器开发1——基础架构与框架介绍

    2013年04月19日 14:09:37 MJiao 阅读数:4614   深入浅出node.js游戏服务器开发1——基础架构与框架介绍   游戏服务器概述 没开发过游戏的人会觉得游戏服务器是很神秘的 ...

  5. 浅析CAS与AtomicInteger原子类

    一:CAS简介 CAS:Compare And Swap(字面意思是比较与交换),JUC包中大量使用到了CAS,比如我们的atomic包下的原子类就是基于CAS来实现.区别于悲观锁synchroniz ...

  6. linux常用命令--文件的权限

    ls -lh 显示权限 ls /tmp | pr -T5 -W$COLUMNS 将终端划分成5栏显示 chmod ugo+rwx directory1 设置目录的所有人(u).群组(g)以及其他人(o ...

  7. [护网杯2018] easy_laravel

    前言 题目环境 buuoj 上的复现,和原版的题目不是完全一样.原题使用的是 nginx + mysql 而 buuoj 上的是 apache + sqlite composer 这是在 PHP5.3 ...

  8. [PHP]PHP设计模式:单例模式

    单例模式(职责模式): 简单的说,一个对象(在学习设计模式之前,需要比较了解面向对象思想)只负责一个特定的任务: 单例类: 1.构造函数需要标记为private(访问控制:防止外部代码使用new操作符 ...

  9. layui table渲染和数据处理

    最近在用layui开发管理系统,果然是"累"ui 实现功能:将之前选择的选项勾选,渲染备注信息(原数据为空的列) <table class="layui-hide& ...

  10. ASP.NET母版页

    ASP.NET母版页:主要是设置一致界面的页面,在固定的页中进行更新. 如图1-1所示 页头 页中(页内容) 页尾 图1-1  母版页 一般网页是固定页头和页尾,只更新页内容,来实现网页的跳转或内容的 ...