Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js —— js数据类型:Object 基础介绍(内部方法和内置插槽等) #53

Open
lizhongzhen11 opened this issue Nov 8, 2019 · 0 comments
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Nov 8, 2019

Object 基础介绍

这里不涉及具体某个api,因为实在太多了。

对象的字符串属性键名 整数索引 在 0 ~ 253 - 1间(源于string的长度限制)。

数组也是对象。但是数组的索引范围是 0 ~ 232 - 1。因为数组长度内部用了 ToUint32 转换的,相关算法在规范中多处都有提到,例如 Array 的 [[DefineOwnProperty]](P, Desc)

属性有两种访问方式:getset,分别对应取值和赋值。通过getset可以访问对象自身属性和继承属性。

JavaScript 中的对象分类

来源于规范中定义的对象以及winter《重学前端》——JavaScript对象:你知道全部的对象分类吗?。

  • host Objects(宿主对象):由 JavaScript 宿主环境提供的对象,它们的行为完全由宿主环境决定。
  • Built-in Objects(内置对象):由 JavaScript 语言提供的对象。
    • Ordinary objects(普通对象):最常见的对象形式,并具有默认的对象语义。(由{}语法、Object 构造器或者 class 关键字定义类创建的对象,它能够被原型继承。)
    • Intrinsic Objects(固有对象):由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。
    • Native Objects(原生对象):可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象。PS:规范中并没有找到相应的分类,单纯的 Array 属于固有对象,但是其生成的数组对象被winter划分到这里。

PS:任何不是 Ordinary objects 的对象都是 exotic object (奇异/怪异对象)。

属性描述符

注意:js对象其实是key-value集合,每个key都有相应的属性描述符!根据属性描述符的不同可以分为 数据属性访问器属性

数据属性的属性描述符见下表:

属性名 值域 描述
[[Value]] 符合ECMAScript语言类型的值 通过属性的get访问获取的值。
[[Writable]] Boolean 如果为false,通过ECMAScript代码试图使用[[Set]]改变该属性[[Value]]特性不会成功
[[Enumerable]] Boolean 如果为true,该属性能被for-in枚举(见13.7.5)。否则,该属性不可枚举。
[[Configurable]] Boolean 如果为false,尝试删除该属性,将该属性转换为访问器属性或者改变它的特性([[Value]]以外的其他值,或将[[Writable]]更改为false)等操作都会失败。[[Value]]依然可以改。

js代码示例:

let obj = {};
Object.defineProperty(obj, 'a', {
  value: 'test',
  writable: true,
  enumerable: true,
  configurable: true
})

访问器属性的属性描述符见下表:

属性名 值域 描述
[[Get]] Object / Undefined 如果值为对象,那么必须是函数对象。使用空参数列表调用函数的[[Call]]内置方法(见),每次执行属性的get访问时检索属性值。
[[Set]] Object / Undefined 如果值为对象,那么必须是函数对象。每次执行属性的set访问时会使用包含 赋值作为其唯一参数的 参数列表调用函数的[[Call]]内置方法(见)。属性的[[Set]]内部方法的效果可能(但不是必需)对后续调用该属性的[[Get]]内部方法所返回的值产生影响。
[[Enumerable]] Boolean 如果为true,该属性能被for-in枚举(见13.7.5)。否则,该属性不可枚举。
[[Configurable]] Boolean 如果为false,尝试删除该属性,将该属性转换为数据属性或改变该属性的特性(描述符)都会失败。

js代码示例:

let val;
Object.defineProperty(obj, 'b', {
  get () {
    console.log('get...');
    return val;
  },
  set (newVal) {
    val = newVal;
    console.log('set...');
  },
  enumerable: true,
  configurable: true
})
obj.b = 1; // set...
obj.b; // get...  // 1

对象的内部方法和内部插槽

ECMAScript中对象的实际语义是通过称为 内部方法 的算法指定的。ECMAScript引擎中的每个对象都与一组内部方法相关联,这些内部方法定义了其运行时行为。这些内部方法不是ECMAScript语言的一部分。由规范定义,仅出于说明目的。

内部插槽对应于与对象关联并由各种ECMAScript规范算法使用的 内部状态。内部插槽不是对象属性,也不会继承。根据特定的内部插槽规范,这种状态可以由任何 ECMAScript语言类型的值特定的ECMAScript规范类型的值 组成。除非另有明确说明,否则内部插槽将作为创建对象过程的一部分进行分配,并且可能不会动态添加到对象中。除非另有说明,否则内部插槽的初始值为 undefined。规范中的各种算法都会创建具有内部插槽的对象。但是,ECMAScript语言没有提供将内部插槽与对象关联的直接方法。

在规范中,内部方法和内部插槽使用 [[内部方法名 或者 内部插槽名]] 表示(符合Record类型)。下表总结了规范使用的 基本内部方法,这些方法适用于由ECMAScript代码创建或操作的所有对象。每个对象都必须具有用于所有基本内部方法的算法。但是,对于这些方法,所有对象不一定都使用相同的算法。

内部方法 签名 描述
[[GetPrototypeOf]] ( ) → Object / Null 确定为该对象提供继承属性的对象。null表示没有继承属性。Object.getPrototypeOf()
[[SetPrototypeOf]] (Object / Null) → Boolean 将此对象与提供继承属性的另一个对象相关联。传null表示没有继承属性。返回true表示操作成功,返回false表示操作失败。(Object.setPrototypeOf()
[[IsExtensible]] ( ) → Boolean 确定是否允许向该对象添加其他属性。(对应Object.isExtensible()
[[PreventExtensions]] ( ) → Boolean 控制新属性是否能被加入对象内。返回true表示操作成功,返回false表示操作失败。(PS:如果为false,即使[[IsExtensible]]true,添加新属性操作也会失败。Object.preventExtensions()
[[GetOwnProperty]] (propertyKey) → Undefined / Property Descriptor 返回此对象自身属性的属性描述符,如果没有对应的属性,返回undefinedObject.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptors()
[[DefineOwnProperty]] (propertyKey, PropertyDescriptor) → Boolean 创建或更改自己的属性,该属性对应传入的propertyKey,属性描述符对应传入的PropertyDescriptor。如果操作成功返回true,否则返回false。(对应Object.defineProperty()Object.defineProperties()
[[HasProperty]] (propertyKey) → Boolean 返回一个布尔值,该值指示此对象是否其自身已具有或继承的键为传入的propertyKey的属性。(对应Object.prototype.hasOwnProperty()
[[Get]] (propertyKey, Receiver) → any 返回对象中属性名为参数propertyKey的值。如果必须执行ECMAScript代码来找到属性值,参数Receiver会被当作this来用。
[[Set]] (propertyKey, value, Receiver) → Boolean 将参数value设置为对象中属性名为参数propertyKey的值。参数Receiver会被当作this来用。如果操作成功返回true,否则返回false
[[Delete]] (propertyKey) → Boolean 删除对象中属性名为参数propertyKey的属性。删除成功返回true,否则返回false。(类似js中的delete关键字)
[[OwnPropertyKeys]] ( ) → List of propertyKey 返回一个列表,其元素都是对象自己的所有属性键。(Object.getOwnPropertyNames()Object.getOwnPropertySymbols()

下表总结了函数对象所支持的其他基本内部方法:

内部方法 签名 描述
[[Call]] (any, a List of any) → any 执行与此对象关联的代码。通过函数调用表达式调用。第一个参数any表示thisa List of any表示传入的参数列表。实现此内部方法的对象是可调用的。
[[Construct]] (a List of any, Object) → Object 创建一个对象。通过newsuper操作调用。a List of any表示包含运算符参数的列表。第二个参数Object表示new操作的初始应用对象。实现该内部方法的对象称为constructors。函数对象不一定要有constructor并且非构造函数对象没有[[Construct]]内部方法。

基本内部方法的不变量

定义:

  • 内部方法被调用的对象就是其目标target
  • 如果目标对象的[[IsExtensible]]内部方法返回false或者其[[PreventExtensions]]返回true,则该对象是不可扩展的。
  • 不存在的属性是指 不可扩展的对象自身没有该属性。
  • SameValue的所有引用均根据SameValue算法的定义。

返回值:

任何内部方法的返回值必须是具有以下任一内容的完成记录

  • [[Type]] = normal, [[Target]] = empty, 并且 [[Value]] = normal类型返回的值, 或
  • [[Type]] = throw, [[Target]] = empty, 并且 [[Value]] = 任何ECMAScript语言类型值。

注意:内部方法不会返回[[Type]]为continue, break, 或 return的completion。

2020-07-27 补充

var a = {n: 1};
var b = a; // 指向 {n: 1} 这个对象
a.x = a = {n: 2}; // 此时 a 指向 {n: 2} 这个对象
console.log(a.x); // undefined
console.log(b); // {n: 1, x: {n: 2}}
console.log(b.x); // {n: 2}

这里问题关键在于 a.x = a = {n: 2} 这一段,其实 a.x 此时应该是 {n: 1} 这个对象添加了个新属性 xa = {n: 2} 则是将 a 变量指向新对象!然后 {n: 1} 这个对象的 x 属性指向 {n: 2} 这个对象。

@lizhongzhen11 lizhongzhen11 added the js基础 Good for newcomers label Nov 8, 2019
@lizhongzhen11 lizhongzhen11 changed the title 重学js——Object 基础介绍 重学js——Object 基础介绍(内部方法和内置插槽等) Nov 8, 2019
@lizhongzhen11 lizhongzhen11 changed the title 重学js——Object 基础介绍(内部方法和内置插槽等) js数据类型(四):Object 基础介绍(内部方法和内置插槽等) Nov 9, 2019
@lizhongzhen11 lizhongzhen11 changed the title js数据类型(四):Object 基础介绍(内部方法和内置插槽等) 重学js —— js数据类型(四):Object 基础介绍(内部方法和内置插槽等) Nov 9, 2019
@lizhongzhen11 lizhongzhen11 added the 重学js 重学js系列 规范+MDN label Jan 6, 2020
@lizhongzhen11 lizhongzhen11 changed the title 重学js —— js数据类型(四):Object 基础介绍(内部方法和内置插槽等) 重学js —— js数据类型(五):Object 基础介绍(内部方法和内置插槽等) Apr 6, 2020
@lizhongzhen11 lizhongzhen11 changed the title 重学js —— js数据类型(五):Object 基础介绍(内部方法和内置插槽等) 重学js —— js数据类型(六):Object 基础介绍(内部方法和内置插槽等) Apr 12, 2020
@lizhongzhen11 lizhongzhen11 changed the title 重学js —— js数据类型(六):Object 基础介绍(内部方法和内置插槽等) 重学js —— js数据类型:Object 基础介绍(内部方法和内置插槽等) Jun 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant