ECMAScript 对象
ECMAScript 是一种基于对象的编程语言,其中对象是一组零个或多个属性的集合。ECMAScript 程序可以看作是一组相互通信的对象。
对象的创建
- 通过字面符号创建
let person = {
name: "Alice",
age: 18,
};
- 通过构造函数(创建和初始化对象的函数),然后执行初始化代码,为它们的属性分配初始值
function Person(name, age) {
this.name = name;
this.age = age;
}; // 构造函数 Person
let person = new Person("Alice",18);
字面符号也是通过构造函数实现的
let person = new Object(); // 构造函数 Object
person.name = "Alice";
person.age = 18;
几乎所有的对象都有一个构造函数,除了使用 Object.create(null)
创建的对象。
Object.create(null)
并不会创建 Object.prototype
这个委托。所以它比{}
更空。
console.log(Object); // ƒ Object() { [native code] }
console.log(Array); // ƒ Array() { [native code] }
console.log(Function); // ƒ Function() { [native code] }
console.log(Object.create(null)); // {}
[native code]
意味着这是一个原生的内置函数,它们是由宿主引擎实现的,而不是由 ECMAScript 代码定义的。这些对象又叫做内置对象(Built-in Objects)。
这些内置对象有多少呢,ECMAScript 文档有详细记录
对象名称 | 类型 |
---|---|
AggregateError | The constructor |
Array | The Array constructor |
ArrayBuffer | The ArrayBuffer constructor |
BigInt | The BigInt constructor |
BigInt64Array | The BigInt64Array constructor |
BigUint64Array | The BigUint64Array constructor |
Boolean | The Boolean constructor |
DataView | The DataView constructor |
Date | The Date constructor |
Error | The Error constructor |
EvalError | The EvalError constructor |
FinalizationRegistry | The FinalizationRegistry constructor |
Float32Array | The Float32Array constructor |
Float64Array | The Float64Array constructor |
Function | The Function constructor |
Int8Array | The Int8Array constructor |
Int16Array | The Int16Array constructor |
Int32Array | The Int32Array constructor |
Map | The Map constructor |
Number | The Number constructor |
Object | The Object constructor |
Promise | The Promise constructor |
Proxy | The Proxy constructor |
RangeError | The RangeError constructor |
ReferenceError | The ReferenceError constructor |
RegExp | The RegExp constructor |
Set | The Set constructor |
SharedArrayBuffer | The SharedArrayBuffer constructor |
String | The String constructor |
Symbol | The Symbol constructor |
SyntaxError | The SyntaxError constructor |
TypeError | The TypeError constructor |
Uint8Array | The Uint8Array constructor |
Uint8ClampedArray | The Uint8ClampedArray constructor |
Uint16Array | The Uint16Array constructor |
Uint32Array | The Uint32Array constructor |
URIError | The URIError constructor |
WeakMap | The WeakMap constructor |
WeakRef | The WeakRef constructor |
WeakSet | The WeakSet constructor |
如果不使用 new
关键字,而直接调用构造函数,会导致意想不到的结果。
new Date(2009, 11); // 将创建一个新的Date对象
Date(2009, 11) ; // 将会产生当前时间的字符串,而且不是一个对象
构造函数
构造函数是创建和初始化对象的函数,是函数的一种。
每个构造函数都是一个带有名为 prototype
(原型) 属性的函数,用于实现基于原型的继承和共享属性。
构造函数创建的每个对象都有对构造函数的 prototype
属性的隐式引用 __proto__
(指向原型)。
prototype
是构造函数的属性(函数专属)。__proto__
是实例对象的属性(对象专属)。
function Fn() {};
const fn = new Fn();
Fn.prototype === fn.__proto__; // 输出:true
内置对象的继承
绝大多数内置对象都是继承自 object 对象(除了 object 对象),而最终的原型 Object.prototype
没有再继承其它对象,它的 __proto__
属性指向 null。
Array.prototype.__proto__ === Object.prototype // 输出:true
Function.prototype.__proto__ === Object.prototype // 输出:true
console.log(Object.prototype.__proto__); // 输出:null
原型链
这种继承方式,使得我们操作实例对象的属性和方法时,首先在实例对象自身查找是否存在对应的私有属性或私有方法,找到了,则查找结束,直接使用该属性或方法。
如果在实例对象上未找到对应的属性或方法,则会基于 __proto__
属性向上查找,找到所属构造函数的 prototype
,继续在构造函数的 prototype
上查找是否存在对应的属性或方法。如果找到了,则查找结束,直接使用该属性或方法。
如果在构造函数的 prototype
上仍未找到对应的属性或方法,则会继续基于 __proto__
属性一直向上查找,直到找到最终原型,即 Object.prototype
。如果在 Object.prototype
上仍未找到对应的属性或方法,则返回 undefined,如果将 undefined 当作方法执行,就会报错。
当声明一个 object 变量 obj 时,它的原型链是这样的
let obj = {};
obj.__proto__ -> Object
Object.__proto__ -> null
当声明一个 Array 变量 arr 时,它的原型链是这样的
let arr = [];
arr.__proto__ -> Array
Array.__proto__ -> Object
Object.__proto__ -> null
当声明一个 Funtion 变量 fn 时,它的原型链是这样的
function fn() {};
fn.__proto__ -> Function
Function.__proto__ -> Object
Object.__proto__ -> null
继承
- 原型继承
B.prototype = new A()
- Call继承
function B(){
A.call(this);
}
new B() // 修改this,然后执行A函数,实现了继承
- 寄生组合继承
B.prototype = Object.create(A.prototype)
- Class继承
class Fn{
constructor(n.m)
super();
this.x = n;
this.y = m;
}
let f = new Fn(10,20)