我正在参与掘金创作者训练营第6期,点击了解活动详情
前言
有时候对于Object,Proxy,Reflect,可能小脑袋是空空如也的,想着每次遇到问题了再去查文档,但是脑袋里面都不知道某种方法是干什么的,遇到某个bug,或者写到紧急时刻需要某种方法来解决某些问题。临时去找的话太急了。小脑袋都是嗡嗡的。所以按照每种的方法写成表格的形式。视觉效果应该好些,快速查找。
Object
Object 构造函数
Object 构造函数 (1) | 作用 |
---|---|
Object() | 创建一个新的 Object 对象。该对象将会包裹(wrapper)传入的参数 |
Object 静态方法
Object 静态方法 (19) | 作用 |
---|---|
assign() | 通过复制一个或多个对象来创建一个新的对象。 |
create() | 使用指定的原型对象和属性创建一个新对象。 |
defineProperty() | 给对象添加一个属性并指定该属性的配置。 |
defineProperties() | 给对象添加多个属性并分别指定它们的配置 |
entries() | 返回给定对象自身可枚举属性的 [key, value] 数组 |
freeze() | 冻结对象:其他代码不能删除或更改任何属性 |
getOwnPropertyDescriptor() ) | 返回对象指定的属性配置。 |
getOwnPropertyNames() | 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名 |
getOwnPropertySymbols() | 通返回一个数组,它包含了指定对象自身所有的符号属性。 |
getPrototypeOf() | 返回指定对象的原型对象 |
is() | 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同) |
isExtensible() | 判断对象是否可扩展。 |
isFrozen() | 判断对象是否已经冻结。 |
isSealed() | 判断对象是否已经密封 |
keys() | 返回一个包含所有给定对象自身可枚举属性名称的数组 |
preventExtensions() | 阻止对象的任何扩展。 |
seal() | 防止其他代码删除对象的属性。 |
setPrototypeOf() | 设置对象的原型(即内部 [[Prototype]] 属性) |
values() | 返回给定对象自身可枚举值的数组 |
Object 实例属性
Object 实例属性 (2) | 作用 |
---|---|
Object.prototype.constructor | 一个引用值,指向 Object 构造函数。 |
Object.prototype.__proto__ | 指向一个对象,当一个 object 实例化时,使用该对象作为实例化对象的原型 |
Object 实例方法
Object 实例方法 (10) | 作用 |
---|---|
prototype.__defineGetter__() | 将一个属性与一个函数相关联,当该属性被访问时,执行该函数,并且返回函数的返回值 |
prototype.__defineSetter__() | 将一个属性与一个函数相关联,当该属性被设置时,执行该函数,执行该函数去修改某个属性 |
prototype.__lookupGetter__() | 返回一个函数,该函数通过给定属性的 Object.prototype.__defineGetter__() 得出 |
prototype.__lookupSetter__() | 返回一个函数,该函数通过给定属性的 Object.prototype.__defineSetter__() 得出 |
prototype.hasOwnProperty() | 返回一个布尔值,用于表示一个对象自身是否包含指定的属性,该方法并不会查找原型链上继承来的属性 |
prototype.isPrototypeOf() | 返回一个布尔值,用于表示该方法所调用的对象是否在指定对象的原型链中 |
prototype.propertyIsEnumerable() | 返回一个布尔值,用于表示内部属性 ECMAScript [Enumerable] 是否被设置。 |
prototype.toLocaleString() | 调用 toString()。 |
prototype.toString() | 返回一个代表该对象的字符串 |
prototype.valueOf() | 返回指定对象的原始值。 |
Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等
// target,目标对象,(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
// handler, 通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 `p` 的行为。
const p = new Proxy(target, handler)
关于proxy
的表格
proxy方法 (1) | 作用 |
---|---|
Proxy.revocable() | 创建一个可撤销的Proxy 对象,一旦某个代理对象被撤销,它将变得几乎完全不可用,在它身上执行任何的可代理操作都会抛出 TypeError 异常 |
const revocable = Proxy.revocable({}, {
get(target, name) {
return name;
}
});
// 返回一个包含了代理对象本身和它的撤销方法
console.log(revocable) // {proxy: Proxy, revoke: ƒ}
const proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // 抛出 TypeError
proxy.foo = 1 // 还是 TypeError
delete proxy.foo; // 又是 TypeError
typeof proxy // "object",因为 typeof 不属于可代理操作
handler对象的方法 (12) | 作用 |
---|---|
handler.getPrototypeOf() | Object.getPrototypeOf 方法的捕捉器 |
handler.setPrototypeOf() | Object.setPrototypeOf 方法的捕捉器 |
handler.isExtensible() | Object.isExtensible 方法的捕捉器 |
handler.preventExtensions() | Object.preventExtensions 方法的捕捉器 |
handler.getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor 方法的捕捉器 |
handler.defineProperty() | Object.defineProperty 方法的捕捉器 |
handler.has() | in 操作符的捕捉器 |
handler.get() | 属性读取操作的捕捉器 |
handler.set() | 属性设置操作的捕捉器 |
handler.deleteProperty() | delete 操作符的捕捉器 |
handler.ownKeys() | Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器 |
handler.apply() | new 操作符的捕捉器。。 |
// 捕捉器:当Object上某个方法被触发时,被处于Proxy上的形参handler对象里面的相对应的进行监听的方法
const monster = {
name: "牧羊"
};
const monsterPrototype = {
name: "沐浴阳光"
};
const handler = {
getPrototypeOf(target) {
// `getPrototypeOf` 方法的返回值必须是一个对象或者 `null`,否则会抛出错误
return monsterPrototype;
}
};
const proxy = new Proxy(monster, handler);
//Object.getPrototypeOf 触发时被 handler.getPrototypeOf()进行捕获从而操作handler.getPrototypeOf里面的逻辑
console.log(Object.getPrototypeOf(proxy) === monsterPrototype);
// true
console.log(Object.getPrototypeOf(proxy.name);
//"沐浴阳光"
5 种
触发 getPrototypeOf
代理方法的方式
// Object.getPrototypeOf
// Reflect.getPrototypeOf
// __proto__
// Array.prototype.isPrototypeOf
// instanceof
const obj = {};
const handler = {
getPrototypeOf(target) {
return Array.prototype;
}
};
var p = new Proxy(obj, handler);
console.log(
Object.getPrototypeOf(p) === Array.prototype, // true
Reflect.getPrototypeOf(p) === Array.prototype, // true
p.__proto__ === Array.prototype, // true
Array.prototype.isPrototypeOf(p), // true
p instanceof Array // true
);
in
操作符
如果指定的属性
在指定的对象或其原型链中,则in
运算符返回true
,否则返回false
// 对象
const obj = { option: 'vue', number: 2 };
console.log('option' in obj);// true
//使用 `delete` 运算符删除了一个属性,则 `in` 运算符对所删除属性返回 `false`
delete obj.option;
if ('option' in car === false) {
obj.option = 'react';
}
console.log(obj.option); // react
// 如果只是将一个属性的值赋值为`undefined`,而没有删除它,则 `in` 运算仍然会返回`true`,因为修改的是属性值,但是属性,比如说number还在的
obj.number = undefined
console.log('number' in obj); // true
// 数组
var fruits = new Array("apple", "banana", "grape", "tangerine", "watermelon");
0 in fruits // 返回 true
3 in fruits // 返回 true
6 in fruits // 返回 false
"apple" in fruits // 返回 false (必须使用索引号,而不是数组元素的值)
"length" in fruits // 返回 true (length 是一个数组属性)
Symbol.iterator in fruits // 返回 true (数组可迭代,只在 ES2015+ 上有效)
// 内置对象
"PI" in Math // 返回 true
fruits[3] = undefined;
3 in trees; // true
new
操作符
语法: new constructor[([arguments])]
news属性 | 作用 |
---|---|
constructor | 用来指定对象实例是什么类型的类或函数 (构造函数) |
arguments | 用来被 constructor 调用的参数列表 |
new
关键字会进行如下的操作:
- 创建一个空对象(即
{}
); - 添加属性
__proto__
到步骤 1 新创建的对象上,将该属性链接到构造函数的原型对象上; - 将步骤 1 新创建的对象作为
this
的上下文 ; - 如果该函数没有返回对象,则返回
this
。
// 编写函数来定义对象类型,构造函数Car
function Car(name, height, birthday) {
this.name = name;
this.height = height;
this.birthday = birthday;
}
// 通过 `new` 来创建对象实例
const car1 = new Car('北京现代', 2 , 1993); // new Car()操作后的结果 作为`this`的上下文
const car2 = new Car();
console.log(car1.name); // "北京现代"
// 可以使用`prototype` 属性将需要多次使用的属性添加到以前定义的对象类型上。定义一个共享属性
console.log(car1.color); // undefined
Car.prototype.color = "red";
car1.color = 'blue';
console.log(car1.color) // blue
console.log(car1.__proto__.color) //red
console.log(car2.__proto__.color) //red
console.log(car1.color) // blue
console.log(car2.color) //red
Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers
的方法相同。
与大多数全局对象不同,Reflect
不是构造函数,所以不能通过new
运算符来进行调用,也不能将Reflect
对象作为一个函数来调用。Reflect
的所有属性和方法(就像Math
对象)都是静态的。
Reflect静态方法 (14) | 作用 |
---|---|
Reflect.apply() | 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似) |
Reflect.construct() | 对构造函数进行 new 操作,相当于执行 new target(...args) 。 |
Reflect.defineProperty() | 和 Object.defineProperty() 类似。如果设置成功就会返回 true |
Reflect.deleteProperty() | 作为函数的delete 操作符,相当于执行 delete target[name] |
Reflect.get() | 获取对象身上某个属性的值,类似于 target[name] |
Reflect.getOwnPropertyDescriptor() | 获取对象身上某个属性的值,类似于 target[name] |
Reflect.getOwnPropertyDescriptor() | 类似于 Object.getOwnPropertyDescriptor() 。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined |
Reflect.getPrototypeOf() | 类似于 Object.getPrototypeOf() |
Reflect.has() | 判断一个对象是否存在某个属性,和 in 运算符的功能完全相同。 |
Reflect.isExtensible() | 类似于 Object.isExtensible() |
Reflect.ownKeys() | 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys() , 但不会受enumerable 影响). |
Reflect.preventExtensions() | 类似于 Object.preventExtensions() 。返回一个Boolean |
Reflect.set() | 将值分配给属性的函数。返回一个Boolean ,如果更新成功,则返回true 。 |
Reflect.setPrototypeOf() | 设置对象原型的函数。返回一个 Boolean , 如果更新成功,则返回true |
Reflect
部分方法用法
Reflect.apply()
语法: Reflect.apply(target, thisArgument, argumentsList)
该方法与 ES5 中Function.prototype.apply()
方法类似:调用一个方法并且显式地指定 this
变量和参数列表 (arguments) ,参数列表可以是数组,或类似数组的对象
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
使用 Reflect.apply
方法会使代码更加简洁易懂
//Reflect.apply('目标函数','this指向','传入的实参列表')
Reflect.apply(Math.floor, undefined, [2.9]); // 2
Reflect.apply(String.fromCharCode, undefined, [108, 101, 109, 111,110 ]); // "lemon"
Reflect.apply(RegExp.prototype.exec, /fa/, ["confabulation"]).index; // 3
Reflect.apply("".charAt, "ponies", [4]); // "e"
Reflect.construct()
语法: Reflect.construct(target, argumentsList[, newTarget])
Reflect.construct
允许使用可变的参数来调用构造函数,这和使用new 操作符
搭配对象展开符
调用一样
function OneClass() {
this.name = '今晚不要下雨';
}
function OtherClass() {
this.name = '天晴了';
}
// 创建一个对象:
var obj1 = Reflect.construct(OneClass, [], OtherClass);
// 与上述方法等效:
var obj2 = Object.create(OtherClass.prototype);
OneClass.apply(obj2, args);
console.log(obj1.name); // '今晚不要下雨'
console.log(obj2.name); // '今晚不要下雨'
console.log(obj1 instanceof OneClass); // false
console.log(obj2 instanceof OneClass); // false
console.log(obj1 instanceof OtherClass); // true
console.log(obj2 instanceof OtherClass); // true
Reflect.get()
语法: Reflect.get(target, propertyKey[, receiver])
// Reflect.get(取值的目标对象;获取的值的键值;取值的目标对象中如果指定了`getter`,那么则为`getter`调用时的`this`值)
// Object
var obj = { x: 1, y: 2 };
Reflect.get(obj, "x"); // 1
// Array
Reflect.get(["索引0", "索引1"], 1); // "索引1"
// Proxy.handler和Reflectget.get结合
var x = {p: 1 , l: 2};
const handler = {
get(t, k, r) {
// t传进来的对象x
// k, Reflect.get的第二个参数"foo"
// r, Proxy对象
return k + "下雨吗";
}
};
var obj = new Proxy(x, handler);
Reflect.get(obj, "今天"); // "今天下雨吗"
Reflect.set()
语法: Reflect.set(target, propertyKey[, receiver])
静态方法 Reflect.set()
工作方式就像在一个对象上设置一个属性,返回布尔值表明设置属性是否成功。
// Object
var obj = {};
Reflect.set(obj, "prop", "value"); // true
obj.prop; // "value"
// Array
var arr = ["duck1", "duck2", "duck3"];
arr[2]; // "duck3"
Reflect.set(arr, 2, "goose"); // true
arr[2]; // "goose"
// 截断数组.
Reflect.set(arr, "length", 1); // true
arr; // ["duck1"];
Reflect.set(arr, "length", 3); // true
arr //["duck1", , ];
//只有一个参数时, 值是 "undefined".
var obj = {};
Reflect.set(obj); // true
Reflect.getOwnPropertyDescriptor(obj, "undefined");
// { value: undefined, writable: true, enumerable: true, configurable: true }
Reflect.ownKeys()
语法: Reflect.ownKeys(target)
静态方法 Reflect.set()
返回一个由目标对象自身的属性键
组成的数组。target
必须是Object,不然会抛出错误TypeError
Reflect.ownKeys({z: 3, y: 2, x: 1}); // [ "z", "y", "x" ]
Reflect.ownKeys([]); // ["length"]
Reflect.deleteProperty()
语法: Reflect.deleteProperty(target,propertyKey)
静态方法 Reflect.deleteProperty()
返回一个布尔值表明该属性是否被成功删除。target
必须是Object,不然会抛出错误TypeError
var obj = { x: 1, y: 2 };
//Reflect.deleteProperty(目标对象, 被删除的键)
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
// 删除数组索引为3的项,数组的占位还留着的
Reflect.deleteProperty(arr, "3"); // true
arr; // [1, 2, 3, , 5]
// 虽然被删除了,但是位置还保留着的,索引长度不变
arr.length // 5
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,被冻结后,删除不了,返回 false
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
Reflect.has()
语法: Reflect.has(target,propertyKey)
静态方法 Reflect.has()
和in
操作符类似,检查目标对象是否存该属性,存在返回true,不存在返回fasle
Reflect.has({x: 0}, "x"); // true
Reflect.has({x: 0}, "y"); // false
// 如果该属性存在于原型链中,返回 true
Reflect.has({x: 0}, "toString");
// Proxy 对象的 .has() 方法
obj = new Proxy({}, {
has(t, k) {
return k.startsWith("door");
}
});
// Reflect.has方法被Proxy代理的has监听触发了
Reflect.has(obj, "doorbell"); // true
Reflect.has(obj, "dormitory"); // false
Reflect.getPrototypeOf()
语法: Reflect.getPrototypeOf(target)
静态方法 Reflect.getPrototypeOf()
获取原型的目标对象,如果给定对象没有继承的属性,则返回 null
。target必须是Object,不然会抛出错误TypeError
Reflect.getPrototypeOf({}); // Object.prototype
Reflect.getPrototypeOf(Object.prototype); // null
Reflect.getPrototypeOf(Object.create(null)); // null
与 Object.getPrototypeOf()
比较
// 如果参数为 Object,返回结果相同
Object.getPrototypeOf({}) // Object.prototype
Reflect.getPrototypeOf({}) // Object.prototype
// 在 ES5 规范下,对于非 Object,抛异常
Object.getPrototypeOf('foo') // Throws TypeError
Reflect.getPrototypeOf('foo') // Throws TypeError
// 在 ES2015 规范下,Reflect 抛异常,Object 强制转换非 Object
Object.getPrototypeOf('foo') // String.prototype
Reflect.getPrototypeOf('foo') // Throws TypeError
// 如果想要模拟 Object 在 ES2015 规范下的表现,需要强制类型转换
Reflect.getPrototypeOf(Object('foo')) // String.prototype
总结
不积跬步,无以至千里。Object
,Proxy
,Reflect
在源码中出现的次数很多。先把这些知识点看懂记牢,相信之后看源码的话会轻松很多。掌握的更快!!!让我们一起快乐的学习