当前的位置: 首页 >> 金融 > 内容

《JavaScript面向对象精要》阅读记录

发布时间:2023-05-02 16:57:15 来源:哔哩哔哩

1. 原始类型、引用类型

原始类型(boolean、string、number、null、undefined)的变量直接保存原始值;

引用类型的变量不在变量中直接保存对象,而是保存指向内存中实际对象所在位置的指针/引用;引用值(对象)是引用类型的实例;


(相关资料图)

把一个对象赋值给变量时,实际是赋值给这个变量一个指针。

null空类型只有一个值:null;

undefined未定义类型只有一个值:undefined

typeof null == 'object' :可以认为 null是一个空的对象指针,所以结果为"object";

判断一个值是否为空类型(null)的最佳方式是直接和 null比较(val===null)

对象是属性的无序列表。属性包含键(始终是字符串)和值。如果一个属性的值是函数,它就被称为方法;

对象引用解除: obj=null;  // 赋值为null即可

内建类型:Function、Object、Array、Date、RegExp、Error

可使用 new来实例化每一个内建引用类型

字面量形式虽然没有用new 实例化,但是js引擎背后做的事情确是一样的

typeof能返回的类型:boolean、string、number、undefined、object、function

instanceof能鉴别继承类型:obj instanceof Object

原始封装类型:Boolean、String、Number;(为了让原始类型看上去更像引用类型)

读取原始封装类型变量值时,原始封装类型在背后自动创建并随后销毁:

虽然原始封装类型会被自动创建,在这些值上进行 instanceof检查对应类型的返回值却是 false。 这是因为临时对象仅在值被读取时创建instanceof操作符并没有真的读取任何东西,也就没有临时对象的创建。

也可以手动创建原始封装类型。

注意:手动创建原始封装类型和使用原始值是有区别的。所以尽量避免手动创建原始封装类型。

2. 函数

函数也是对象,使函数不同于其它对象的决定性特点是函数存在一个被称为 [[Call]]的内部属性。内部属性无法通过代码访问而是定义了代码执行时的行为。ECMAScript为JavaScript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注。

[[Call]] 属性是函数独有的,表明该对象可以被执行。由于仅函数拥有该属性,ECMAScript 定义 typeof 操作符对任何具有 [[Call]] 属性的对象返回 "function"。过去因某些浏览器曾在正则表达式中包含 [[Call]]属性,导致正则表达式被错误鉴别为函数。

函数声明和函数表达式的一个重要区别是:函数声明会被提升至上下文(要么是该函数被声明时所在的函数范围,要么是全局范围)的顶部。

函数参数保存在类数组对象 argumentsArray.isArray(arguments)返回 false)中。可以接收任意数量的参数。 函数的 length属性表明其期望的参数个数。

可以像使用对象一样使用函数(因为函数本来就是对象,Function 构造函数更加容易说明)。[page]

定义多个同名的函数时,只有最后的定义有效,之前的函数声明被完全删除(函数也是对象,变量只是存指针)。

对象某个属性的值是函数,该函数就称为方法;

所有的函数作用域内都有一个 this对象代表调用该函数的对象。在全局作用域中,this代表全局对象(浏览器里的 window)。当一个函数作为对象的方法调用时,默认 this的值等于该对象。 this在函数调用时才被设置

bind是 ECMAScript 5 新增的,它会创建一个新函数返回。其参数与 call类似,而且其所有参数代表需要被永久设置在新函数中的命名参数(绑定了的参数(没绑定的参数依然可以传入),就算调用时再传入其它参数,也不会影响这些绑定的参数)。

3. 对象

对象是属性的无序集合;

在 Chrome 中,对象属性会按 ASCII 表排序,而不是定义时的顺序

判断属性是否存在的方法是使用 in操作符。 in操作符会检查自有属性和原型属性。

所有的对象都拥有的 hasOwnProperty()方法(其实是继承自 Object.prototype原型对象的),该方法在给定的属性存在且为自有属性时返回 true

删除属性:delete obj.xxx

MDN:delete 操作符不能删除的属性有:

①显式声明的全局变量不能被删除,该属性不可配置(not configurable); 

②内置对象的内置属性不能被删除; 

③不能删除一个对象从原型继承而来的属性(不过你可以从原型上直接删掉它)。

所有人为添加的属性默认都是可枚举的。可枚举的内部特征 [[Enumerable]]都被设置为 true。对象的大部分原生方法的 [[Enumerable]]特征都被设置为 false。可用 propertyIsEnumerable()方法检查一个属性是否为可枚举的。arr.propertyIsEnumerable("length")

属性分为 数据属性访问器属性两种类型:数据属性包含一个值,访问器属性定义了当一个属性被读取(getter)和被写入(setter)时调用的函数。

数据属性和访问器属性均由以下两个属性特制: 

[[Enumerable]]决定了是否可以遍历该属性;

[[Configurable]]决定了该属性是否可配置。

数据属性额外拥有两个访问器属性不具备的特征:

[[Value]]包含属性的值(哪怕是函数)。

[[Writable]]布尔值,指示该属性是否可写入。

访问器属性额外拥有两个特征:

[[Get]]和 [[Set]],内含 getter和 setter函数。

所有人为定义的属性默认都是可枚举、可配置的。

可以用 Object.defineProperty() 方法改变属性特征:

数据属性额外拥有两个访问器属性不具备的特征:

[[Value]]包含属性的值(哪怕是函数)。

[[Writable]]布尔值,指示该属性是否可写入。

所有属性默认都是可写的。

在 Object.defineProperty()被调用时:

a. 如果属性本来就有,则会按照新定义属性特征值去覆盖默认属性特征(enumberableconfigurable和 writable均为 true),只有你指定的特征会被改变;[page]

b. 定义新的属性时,没有为所有的特征值指定一个值,则所有布尔值的特征值会被默认设置为 false。即不可枚举、不可配置、不可写的。 

访问器属性额外拥有两个特征:

[[Get]]和 [[Set]],内含 getter和 setter函数。

Object.defineProperties() 方法可以定义任意数量的属性,甚至可以同时改变已有的属性并创建新属性。

获取属性特征 Object.getOwnPropertyDescriptor()

接受两个参数:对象和属性名。如果属性存在,它会返回一个属性描述对象,内涵 4个属性:configurable和 enumerable,另外两个属性则根据属性类型决定。

对象和属性一样具有指导其行为的内部特性:

[[Extensible]]是布尔值,指明该对象本身是否可以被修改。默认是 true。当值为 false时,就能禁止新属性的添加。

Object.preventExtensions():创建一个不可扩展的对象(即不能添加新属性);

Object.isExtensible():检查 [[Extensible]]的值。

Object.seal():创建一个不可扩展不可配置只能读写属性的对象;

Object.isSealed():判断一个对象是否被封印。

Object.freeze():创建一个数据属性都为只读的被封印对象(不能添加或删除属性,不能修改属性类型,也不能写入任何数据属性);

Object.isFrozen():判断对象是否被冻结。

4. 构造函数和原型对象

每个对象都有隐式的__proto__ ([[prototype]])属性,值为创建这个对象的构造函数的原型对象;几乎所有的函数(除了一些内建函数)都有prototype属性,值为这个构造函数的原型对象。所有创建的对象实例(同一构造函数,当然,可能访问上层的原型对象)共享该原型对象,且这些对象实例可以访问原型对象的属性。

构造函数的原型对象有个 constructor 属性,指向这个构造函数。

构造函数属性可以被覆盖(person.constructor = "")。

可借助 prototype原型对象共享同一个方法会更高效:

鉴别一个原型属性(通过继承来的属性):

当读取一个对象 obj 的属性时,JavaScript 引擎首先在该对象的自有属性查找属性名。如果找到则返回;否则会搜索 obj 对象的 [[Prototype]] 中的属性,找到则返回,找不到则返回undefined;(如果查找过程还没有到 Object.__proto__  则继续搜索 obj.__proto_.__proto__ ( obj的原型对象的原型对象 )中的属性,一直到 Object.__proto__为止。 Object.__proto__ === null)

Object.getPrototypeOf() 方法可读取 [[Prototype]] 属性的值;

isPrototypeOf() 方法会检查某个对象是否是另一个对象的原型对象:

直接改变构造函数的原型对象:

这种方式有一种副作用:

因为原型对象上具有一个 constructor属性,这是其他对象实例所没有的。当一个函数被创建时,它的 prototype属性也会被创建,且该原型对象的 constructor属性指向该函数。当使用字面量时,因没显式设置原型对象的 constructor属性,因此其 constructor属性是指向 Object。 [page]

因此,当通过此方式设置原型对象时,可手动设置 constructor属性:

因为每个对象的 [[Prototype]]只是一个指向原型对象的指针,原型对象的改动会立刻反映到所有引用它的对象。 当对一个对象使用封印 Object.seal()或冻结 Object.freeze()时,完全是在操作对象的自有属性,仍然可以通过在原型对象上添加属性来扩展这些对象实例。

内建对象的原型对象也能修改:

5. 继承

JavaScript中的继承是通过原型链实现的。对象实例继承了原型对象的属性,而原型对象作为对象也有自己的原型对象,一直到Object.prototype为止。所有对象都继承自 Object.prototype。任何以对象字面量形式定义的对象,其 [[Prototype]]的值都被设为 Object.prototype,这意味着它继承 Object.prototype的属性。

Object.create() 方法用指定的原型对象创建一个对象:

第一个是新对象的 [[Prototype]]所指向的对象;第二个参数是可选的一个属性描述对象,其格式与 Object.definePrototies()一样。

也可以用 Object.create()创建一个 [[Prototype]]为 null的对象:

var obj = Object.create(null);

console.log("toString" in obj); // false

该对象是一个没有原型对象链的对象,即是一个没有预定义属性的白板。

构造函数都有prototype属性,实质为:

关键词:
推荐阅读

Copyright   2015-2022 财报分析网版权所有  备案号:京ICP备12018864号-25   联系邮箱:29 13 23 6 @qq.com