原始类型(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
操作符并没有真的读取任何东西,也就没有临时对象的创建。
也可以手动创建原始封装类型。
注意:手动创建原始封装类型和使用原始值是有区别的。所以尽量避免手动创建原始封装类型。
函数也是对象,使函数不同于其它对象的决定性特点是函数存在一个被称为 [[Call]]
的内部属性。内部属性无法通过代码访问而是定义了代码执行时的行为。ECMAScript为JavaScript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注。
[[Call]] 属性是函数独有的,表明该对象可以被执行。由于仅函数拥有该属性,ECMAScript 定义 typeof 操作符对任何具有 [[Call]] 属性的对象返回 "function"。过去因某些浏览器曾在正则表达式中包含 [[Call]]
属性,导致正则表达式被错误鉴别为函数。
函数声明和函数表达式的一个重要区别是:函数声明会被提升至上下文(要么是该函数被声明时所在的函数范围,要么是全局范围)的顶部。
函数参数保存在类数组对象 arguments
(Array.isArray(arguments)
返回 false
)中。可以接收任意数量的参数。 函数的 length
属性表明其期望的参数个数。
可以像使用对象一样使用函数(因为函数本来就是对象,Function 构造函数更加容易说明)。[page]
定义多个同名的函数时,只有最后的定义有效,之前的函数声明被完全删除(函数也是对象,变量只是存指针)。
对象某个属性的值是函数,该函数就称为方法;
所有的函数作用域内都有一个 this
对象代表调用该函数的对象。在全局作用域中,this
代表全局对象(浏览器里的 window)。当一个函数作为对象的方法调用时,默认 this
的值等于该对象。 this在函数调用时才被设置。
bind
是 ECMAScript 5 新增的,它会创建一个新函数返回。其参数与 call
类似,而且其所有参数代表需要被永久设置在新函数中的命名参数(绑定了的参数(没绑定的参数依然可以传入),就算调用时再传入其它参数,也不会影响这些绑定的参数)。
对象是属性的无序集合;
在 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. 如果属性本来就有,则会按照新定义属性特征值去覆盖默认属性特征(enumberable
、configurable
和 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()
:判断对象是否被冻结。
每个对象都有隐式的__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()
时,完全是在操作对象的自有属性,仍然可以通过在原型对象上添加属性来扩展这些对象实例。
内建对象的原型对象也能修改:
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