一、箭头函数中的 this 会继承自包含它的常规函数的 this 值。如果没有被包含,则指向 window
const shape = {
radius: 10,
diameter() {
return this.radius * 2
},
perimeter: () => 2 * Math.PI * this.radius
}
shape.diameter()
shape.perimeter()
考点:常规函数和箭头函数在处理 this
关键字时的不同行为
1、常规函数中的 this
:this
的值通常指向调用该函数的对象。
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius
};
shape.diameter();
当 shape.diameter()
被调用时,this
关键字指向 shape
对象。因此,this.radius
的值是 10
,shape.diameter()
返回 20
。
2、箭头函数中的 this
:箭头函数不会绑定自己的 this
,它的 this
值继承自包含它的常规函数的 this
值。如果箭头函数没有在任何常规函数中被包含,那么 this
将指向全局对象(在浏览器中是 window
)
perimeter
是一个箭头函数。在定义 perimeter
时,它的 this
并不会指向 shape
对象,而是继承自它的外围作用域。在这里,外围作用域是全局作用域(window
)。
在全局作用域中,this.radius
是 undefined
,因为 window
对象没有 radius
属性。因此,shape.perimeter()
的返回值是 NaN
(2 * Math.PI * undefined
)。
二、JavaScript 中对象属性访问的两种主要方式——点语法(.)和括号语法([])
-
点语法简单直观,但不支持动态属性名。
-
括号语法支持动态属性名,可以通过变量或表达式来访问属性。
-
访问不存在的属性时,两种语法都不会抛出错误,而是返回
undefined
。 -
如果属性名是
undefined
或null
,使用括号语法访问属性会抛出错误。 -
当你尝试调用一个不存在的函数属性时,不管使用点语法还是括号语法,都会在运行时抛出一个
TypeError
错误pet.bark();
const bird = {
size: 'small'
}
const mouse = {
name: 'Mickey',
small: true
}
1、点语法(.
)
点语法是访问对象属性的最直观方式。它要求属性名必须是一个有效的 JavaScript 标识符,并且不能是保留字或包含空格或特殊字符。点语法不能用于动态属性名。
如果尝试使用点语法访问一个不存在的属性,将返回undefined
,而不会抛出错误:
console.log(mouse.bird); // 输出 undefined,不抛出错误
2、括号语法([]
)
括号语法允许你使用变量或表达式来动态地访问对象的属性。属性名可以是任何字符串,甚至是由变量或表达式计算得到的字符串。
const bird = {
size: 'small'
};
console.log(mouse[bird.size]); // 首先计算 bird.size,得到 'small',然后访问 mouse['small'],输出 true
使用括号语法时,如果属性名对应的值不存在,同样会返回undefined
,但不会抛出错误。
三、new Number()
是一个内建的函数构造器,有一堆额外的功能并且它是一个对象
let a = 3
let b = new Number(3)
let c = 3
console.log(a == b)
console.log(a === b)
console.log(b === c)
new Number()
是一个内建的函数构造器。虽然它看着像是一个 number,但它实际上并不是一个真实的 number:它有一堆额外的功能并且它是一个对象。
四、函数允许你将数据(属性)和行为(函数)结合在一起
function bark() {
console.log('Woof!')
}
bark.animal = 'dog'
这在 JavaScript 中是可以的,因为函数是对象!(除了基本类型之外其他都是对象)
函数是一个特殊的对象。你写的这个代码其实不是一个实际的函数。函数是一个拥有属性的对象,并且属性也可被调用。
五、可以直接给常规对象扩展属性和方法。而给构造函数添加属性:如果你想一次性给所有实例添加特性,你应该使用原型
Person.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`;
}
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const member = new Person("Lydia", "Hallie");
Person.getFullName = function () {
return `${this.firstName} ${this.lastName}`;
}
console.log(member.getFullName());
输出:TypeError
构造函数添加属性和方法
构造函数本身:构造函数本身可以拥有属性和方法,这些被称为静态属性和静态方法。静态属性和方法可以通过构造函数直接访问,而不需要创建实例。
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// 给构造函数添加静态属性
Person.staticProperty = 'This is a static property';
// 给构造函数添加静态方法
Person.staticMethod = function() {
console.log('This is a static method');
};
console.log(Person.staticProperty); // 输出: This is a static property
Person.staticMethod(); // 输出: This is a static method
构造函数的原型:构造函数的原型(Person.prototype
)是用来在所有实例之间共享属性和方法的。当你给原型添加一个方法时,所有通过该构造函数创建的实例都可以访问这个方法,而不需要在每个实例上单独存储这个方法。
Person.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`;
};
const member = new Person("Lydia", "Hallie");
console.log(member.getFullName()); // 输出: Lydia Hallie
六、当使用 new
时,this
引用我们创建的空对象。当未使用 new
时,this
引用的是全局对象(global object)
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
const lydia = new Person('Lydia', 'Hallie')
const sarah = Person('Sarah', 'Smith')
console.log(lydia)
console.log(sarah)
输出:Person {firstName: “Lydia”, lastName: “Hallie”}and
undefined
对于 sarah
,我们没有使用 new
关键字。当使用 new
时,this
引用我们创建的空对象。当未使用 new
时,this
引用的是全局对象(global object)。
我们说 this.firstName
等于 "Sarah"
,并且 this.lastName
等于 "Smith"
。实际上我们做的是,定义了 global.firstName = 'Sarah'
和 global.lastName = 'Smith'
。而 sarah
本身是 undefined
。
七、一元后自增运算符x++
,先返回后增加;一元前自增运算符 ++x
,先增加后返回
let number = 0
console.log(number++)
console.log(++number)
console.log(number)
输出:0
2
2
一元后自增运算符 ++
:
- 返回值(返回
0
) - 值自增(number 现在是
1
)
一元前自增运算符 ++
:
- 值自增(number 现在是
2
) - 返回值(返回
2
)
八、扩展运算符(...args
)会返回实参组成的数组。而数组是对象,因此 typeof args
返回 "object"
function getAge(...args) {
console.log(typeof args)
}
getAge(21)
输出:“object”
九、关闭 tab 标签页 后,sessionStorage
存储的数据才会删除。
如果使用 localStorage
,那么数据将永远在那里,除非调用了 localStorage.clear()
十、所有对象的键(不包括 Symbol)在底层都是字符串,即使你自己没有将其作为字符串输入。对于集合,它不是这样工作的。在我们的集合中没有 '1'
:set.has('1')
返回 false
。它有数字类型为 1
,set.has(1)
返回 true
。
const obj = { 1: 'a', 2: 'b', 3: 'c' }
const set = new Set([1, 2, 3, 4, 5])
obj.hasOwnProperty('1')
obj.hasOwnProperty(1)
set.has('1')
set.has(1)
输出:true
true
false
true
所有对象的键(不包括 Symbol)在底层都是字符串,即使你自己没有将其作为字符串输入。这就是为什么 obj.hasOwnProperty('1')
也返回 true
。
对于集合,它不是这样工作的。在我们的集合中没有 '1'
:set.has('1')
返回 false
。它有数字类型为 1
,set.has(1)
返回 true
。
十、.call
是立即执行的。.bind
方法创建了一个新的函数, 返回函数的副本,但带有绑定上下文!它不是立即执行的。
函数执行的上下文:this 的值
const person = { name: 'Lydia' }
function sayHi(age) {
console.log(`${this.name} is ${age}`)
}
sayHi.call(person, 21)
sayHi.bind(person, 21)
输出:Lydia is 21
function
使用 bind 的例子
const person = { name: 'Lydia' };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
const personSayHi = sayHi.bind(person, 21);
personSayHi();
使用call
或bind
的选择取决于你的需求:
- 如果你需要立即调用函数并改变
this
的上下文,使用call
。 - 如果你需要创建一个新的函数,以备后用,并且带有固定的
this
上下文和参数,使用bind
。
十一、事件处理机制有三个阶段:捕获阶段、目标阶段和冒泡阶段
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
事件捕获:
- 事件从祖先元素开始,沿着 DOM 树向下传播,直到目标元素。
- 比如,在你的示例中,事件捕获的顺序是:
<div onclick="console.log('first div')">
-><div onclick="console.log('second div')">
-><button onclick="console.log('button')">
。
目标阶段:
- 事件到达目标元素,触发目标元素的事件处理函数。
- 在这个案例中,目标元素是
<button>
,当点击按钮时,会触发console.log('button')
。
事件冒泡:
- 事件从目标元素开始,沿着 DOM 树向上传播,直到根元素。
- 在你的示例中,事件冒泡的顺序是:
<button onclick="console.log('button')">
-><div onclick="console.log('second div')">
-><div onclick="console.log('first div')">
。
扩展:事件流控制
你可以通过event.stopPropagation()
来阻止事件在某个阶段继续传播。比如,如果你在<button>
的事件处理函数中调用event.stopPropagation()
,事件将不会冒泡到<div>
元素。
<button onclick="event.stopPropagation(); console.log('button')">
Click!
</button>
这样,点击按钮时,控制台只会输出 button
,而不会输出 second div
和 first div
。
十二、只有 7 种内置类型:null
,undefined
,boolean
,number
,string
,object
, symbol
和 bigint
。function
不是一种类型,函数是对象,它的类型是object
。
十三、Promise.race
的工作原理:
- 创建:
Promise.race
接受一个Promise
数组作为参数,并立即创建一个新的Promise
对象。 - 竞争:数组中的每个
Promise
开始执行,它们之间开始竞争,看哪个首先解决或拒绝。 - 解决:一旦数组中的任何一个
Promise
解决,Promise.race
返回的Promise
对象也会解决,并且其解决的值是第一个解决的Promise
的值。 - 拒绝:如果第一个解决的
Promise
是被拒绝的,Promise.race
返回的Promise
对象也会被拒绝,并且其拒绝的原因是第一个被拒绝的Promise
的原因。
Promise.all
的工作原理:
- 创建:
Promise.all
接受一个Promise
数组,并立即创建一个新的Promise
对象。 - 等待:它等待所有输入的
Promise
都解决。 - 解决:当所有的
Promise
都解决后,返回的Promise
对象解决,并且其解决的值是一个数组,包含了所有输入Promise
解决的值,顺序与输入数组相同。 - 拒绝:如果任何一个输入的
Promise
被拒绝,返回的Promise
对象也会立即被拒绝,其拒绝的原因是第一个被拒绝的Promise
的原因。
十四、在 JavaScript 中,当一个对象被赋值给一个变量时,该变量实际上保存的是指向该对象内存地址的引用。当你将对象赋给另一个变量或将其作为参数传递给函数时,你复制的是这个引用,而不是对象本身。
let person = { name: "Lydia" }; // 创建对象并保存引用在变量 person
const members = [person]; // 将 person 的引用复制到数组 members 中
person = null; // 改变 person 变量的引用,现在它指向 null
注意:这里不是更改引用地址上的值,而是改变了 person 变量的引用
如果想改变person
引用上的值,并且让members
数组中的引用也变化
你需要做的是修改person
对象的属性,而不是改变person
变量的引用本身。由于person
和members
数组中的元素都指向同一个对象,对对象属性的任何修改都会反映在所有指向该对象的引用上。
let person = { name: "Lydia" }; // 创建对象并保存引用在变量 person
const members = [person]; // 将 person 的引用复制到数组 members 中
// 修改 person 对象的属性
person.name = "John";
// 输出 members 数组,将看到 person 对象的 name 属性已经被修改
console.log(members[0].name); // 输出: John
十五、parseInt
检查字符串中的字符是否合法。一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
const num = parseInt("7*6", 10);
输出:7
设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制:十进制、十六机制、八进制、二进制等等……),parseInt
检查字符串中的字符是否合法。一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
*
就是不合法的数字字符。所以只解析到"7"
,并将其解析为十进制的7
. num
的值即为7
.
十六
(() => {
let x = (y = 10);
})();
console.log(typeof x);
console.log(typeof y);
输出:“undefined”, “number”
解析:y = 10
x = y = 10
因为 x 是 let 定义的块作用域变量,在作用域外无法访问到,所以输出 undefined
y 是全局作用域变量,在外部可以正确访问到
十七、通过 var
, const
或 let
关键字声明的变量无法用 delete
操作符来删除
通常的做法是将它们的值重新赋值为undefined
或者将它们赋值为null
。
1. 重新赋值为 undefined
var myVar = 'some value';
// 当你想要"删除"这个变量时
myVar = undefined;
2. 重新赋值为 null
let myLet = 'some value';
// 当你想要"删除"这个变量时
myLet = null;
3. 使用 const
声明的常量
对于使用const
声明的常量,由于它们的值不能被重新赋值,你不能将它们设置为undefined
或null
。但是,你可以通过将它们赋给一个不再使用的变量来实际上让它们不再被访问。
const myConst = 'some value';
// 你不能重新赋值给常量,但可以覆盖变量
myConst = 'another value'; // TypeError
十八、
const person = { name: "Lydia" };
Object.defineProperty(person, "age", { value: 21 });
console.log(person);
console.log(Object.keys(person));
输出:{ name: “Lydia”, age: 21 },
[“name”]
通过defineProperty
方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty
方法给对象添加了一个属性之后,属性默认为 不可枚举 (not enumerable). Object.keys
方法仅返回对象中 可枚举 (enumerable) 的属性,因此只剩下了"name"
.
用defineProperty
方法添加的属性默认不可变。你可以通过writable
, configurable
和 enumerable
属性来改变这一行为。这样,defineProperty
方法可以让您更好地控制要添加到对象的属性。
十九、JSON.stringify 的第二个参数是 替代者 (replacer).
JSON.stringify
的第二个参数是 替代者 (replacer). 替代者 (replacer) 可以是个函数或数组,用以控制哪些值如何被转换为字符串。
如果替代者 (replacer) 是个 数组,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为"level"
和 "health"
的属性被包括进来,"username"
则被排除在外。data
就等于 "{"level":19, "health":90}"
.
而如果替代者 (replacer) 是个 函数,这个函数将被对象的每个属性都调用一遍。 函数返回的值会成为这个属性的值,最终体现在转化后的 JSON 字符串中(译者注:Chrome 下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出 JSON 字符串),而如果返回值为undefined
,则该属性会被排除在外。
二十、push()
方法返回新数组的长度
二十一、for-in
循环:可以遍历一个对象自有的、继承的、可枚举的、非 Symbol 的属性,在数组中,可枚举属性是数组元素的“键”,即它们的索引。for-of
循环,我们可以迭代可迭代对象(包括 Array
,Map
,Set
,String
,arguments
等)
const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]
for (let item in myLifeSummedUp) {
console.log(item)
}
for (let item of myLifeSummedUp) {
console.log(item)
}
输出:0
1
2
3and
”☕“
”💻“
”🍷“
”🍫”
通过for-in
循环,我们可以遍历一个对象自有的、继承的、可枚举的、非 Symbol 的属性。在数组中,可枚举属性是数组元素的“键”,即它们的索引。类似于下面这个对象:
{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
其中键则是可枚举属性,因此 0
,1
,2
,3
被记录。
通过for-of
循环,我们可以迭代可迭代对象(包括 Array
,Map
,Set
,String
,arguments
等)。当我们迭代数组时,在每次迭代中,不同属性的值将被分配给变量item
,因此“☕”
,“💻”
,“🍷”
,“🍫”
被打印。
二十二、const
和let
声明的变量是具有块级作用域的,块是大括号({}
)之间的任何东西
function checkAge(age) {
if (age < 18) {
const message = "Sorry, you're too young."
} else {
const message = "Yay! You're old enough!"
}
return message
}
console.log(checkAge(21))
输出:ReferenceError
const
和let
声明的变量是具有块级作用域的,块是大括号({}
)之间的任何东西,即上述情况if / else
语句的花括号。由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError
。
const message = "Sorry, you're too young."
是在if
语句块中声明的,因此message
变量只在if
块内可见。同样,else
块中的const message = "Yay! You're old enough!"
也只在else
块内可见。
二十三、箭头函数与常规函数的一个显著区别在于:箭头函数没有 prototype
属性,不能用作构造函数,不能使用 new
操作符创建实例
function giveLydiaPizza() {
return "Here is pizza!"
}
const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."
console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)
输出:{ constructor: …}
undefined
扩展:
Prototype 属性
常规函数有一个 prototype
属性,这是 JavaScript 用于构造函数继承的重要特性。每一个常规函数在创建时,都会自动带有一个 prototype
属性,它是一个对象,这个对象包含了一个 constructor
属性,指向该函数本身。这使得常规函数可以用作构造函数,用 new
操作符创建新的对象实例。例如:
function Person(name) {
this.name = name;
}
const person1 = new Person('Lydia');
在这个例子中,Person
函数的 prototype
属性可以用来定义所有实例共享的方法和属性
Person.prototype.greet = function() {
return `Hello, my name is ${this.name}`;
};
console.log(person1.greet()); // "Hello, my name is Lydia"
当你访问一个常规函数的 prototype
属性时,你会得到一个对象:
console.log(giveLydiaPizza.prototype); // { constructor: giveLydiaPizza }
箭头函数与常规函数的一个显著区别在于:箭头函数没有 prototype
属性。它们设计为简洁的非构造函数,因此不能用作构造函数,不能使用 new
操作符创建实例。由于这个原因,箭头函数也不需要 prototype
属性,因此访问时会返回 undefined
:
console.log(giveLydiaChocolate.prototype); // undefined
二十四、Symbol
类型是不可枚举的。Object.keys
方法返回对象上的所有可枚举的键属性
const info = {
[Symbol('a')]: 'b'
}
console.log(info)
console.log(Object.keys(info))
输出:{Symbol(‘a’): ‘b’}and
[]
Symbol
类型是不可枚举的。Object.keys
方法返回对象上的所有可枚举的键属性。Symbol
类型是不可见的,并返回一个空数组。记录整个对象时,所有属性都是可见的,甚至是不可枚举的属性。
这是Symbol
的众多特性之一:除了表示完全唯一的值(防止对象意外名称冲突,例如当使用 2 个想要向同一对象添加属性的库时),您还可以隐藏
这种方式对象的属性(尽管不完全。你仍然可以使用Object.getOwnPropertySymbols()
方法访问 Symbol
。
尽管 Symbol 属性不可枚举,但可以使用Object.getOwnPropertySymbols()
方法获取对象上的所有 Symbol 属性:
const symbols = Object.getOwnPropertySymbols(info);
console.log(symbols); // [ Symbol(a) ]
console.log(info[symbols[0]]); // 'b'
当使用console.log()
打印整个对象时,所有属性(包括不可枚举的 Symbol 属性)都会显示出来。这是因为console.log()
展示的是对象的完整视图,而不仅仅是可枚举属性。
console.log(info); // { [Symbol(a)]: 'b' }
二十五、当值不是预期类型时,会抛出TypeErrors
,当你编写了一些非有效的 JavaScript 时,会抛出语法错误
const name = "Lydia"
console.log(name())
输出:TypeError
当值不是预期类型时,会抛出TypeErrors
。JavaScript 期望name
是一个函数,因为我们试图调用它。但它是一个字符串,因此抛出TypeError
:name is not a function
当你编写了一些非有效的 JavaScript 时,会抛出语法错误,例如当你把return
这个词写成retrun
时。 当 JavaScript 无法找到您尝试访问的值的引用时,抛出ReferenceErrors
。
二十六、Promise 和其状态
Promise 是一种用于处理异步操作的对象。它代表一个在未来某个时间点可能完成或失败的操作及其结果值。Promise 有三种状态:
-
Pending(待定): 初始状态,既没有被解决(fulfilled),也没有被拒绝(rejected)。
-
Fulfilled(已解决): 意味着操作成功完成。
-
Rejected(已拒绝): 意味着操作失败。
-
状态转换
当我们创建一个 Promise,它默认处于
pending
状态。在某个时间点,Promise 可能会被解决(fulfilled)或拒绝(rejected)。
二十七、map
,filter
和slice
返回一个新数组,find
返回一个元素,而reduce
返回一个减小的值。splice
和unshift
改变原数组
map
方法
map
方法用于通过对数组中的每个元素调用提供的函数,创建一个新数组。
array.map(callback(currentValue, index, array), thisArg)
filter
方法
filter
方法用于创建一个新数组,其中包含所有通过提供函数实现的测试的数组元素。
array.filter(callback(element, index, array), thisArg)
slice
方法
slice
方法用于从一个数组中返回选定的元素(浅拷贝),以新数组的形式返回。
array.slice(start, end)
-
start
(可选): 从该索引开始提取元素(包含该元素)。 -
end
(可选): 在该索引之前停止提取元素(不包含该元素)。如果未指定,则默认为数组的长度。const fruits = ['apple', 'banana', 'cherry', 'date']; const slicedFruits = fruits.slice(1, 3); console.log(slicedFruits); // ['banana', 'cherry']
find
方法
find
方法返回数组中满足提供的测试函数的第一个元素的值。如果没有找到这样的元素,则返回 undefined
。
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(num => num > 3);
console.log(found); // 4
splice
方法
splice
方法通过删除或替换现有元素或原地添加新元素来更改数组的内容,并返回被删除的元素(如果有)。
array.splice(start, deleteCount, item1, item2, ...)
start
: 开始更改的索引位置。deleteCount
(可选): 一个整数,表示要移除的数组元素的数量。如果为 0,则不删除元素。item1, item2, ...
(可选): 要添加到数组的新元素。
const fruits = ['apple', 'banana', 'cherry', 'date'];
const removed = fruits.splice(1, 2, 'blueberry', 'blackberry');
console.log(fruits); // ['apple', 'blueberry', 'blackberry', 'date']
console.log(removed); // ['banana', 'cherry']
二十八、JSON.stringify
和 JSON.parse
JSON.stringify
方法
JSON.stringify
方法用于将 JavaScript 对象或值转换为 JSON 字符串。
JSON.stringify(value, replacer, space)
value
: 要转换为 JSON 字符串的 JavaScript 值(通常是对象或数组)。replacer
(可选): 一个函数或数组,用于指定哪些属性应该被包含在 JSON 字符串中。space
(可选): 一个用于控制结果字符串缩进、空白和换行符的字符串或数字。
const obj = { name: "Alice", age: 25 };
const jsonString = JSON.stringify(obj);
console.log(jsonString); // '{"name":"Alice","age":25}'
// 使用 space 参数进行缩进
const jsonStringPretty = JSON.stringify(obj, null, 2);
console.log(jsonStringPretty);
/*
{
"name": "Alice",
"age": 25
}
*/
JSON.parse
方法
JSON.parse
方法用于将 JSON 字符串转换为 JavaScript 对象。
JSON.parse(text, reviver)
text
: 要解析为 JavaScript 对象的 JSON 字符串。reviver
(可选): 一个用于转换结果的函数,在每个键值对被解析时调用。
const jsonString = '{"name":"Alice","age":25}';
const obj = JSON.parse(jsonString);
console.log(obj); // { name: 'Alice', age: 25 }
二十九、Object.prototype.toString.call()
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"
console.log(Object.prototype.toString.call(/regex/)); // "[object RegExp]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(Symbol())); // "[object Symbol]"
console.log(Object.prototype.toString.call(10n)); // "[object BigInt]"
三十、
const handler = {
set: () => console.log("Added a new property!"),
get: () => console.log("Accessed a property!")
};
const person = new Proxy({}, handler);
person.name = "Lydia";
person.name;
输出:Added a new property!
Accessed a property!
Proxy 对象
Proxy
对象用于定义基本操作(例如属性查找、赋值、枚举、函数调用等)的自定义行为。这些行为可以通过一个称为 “handler” 的对象来指定。
const proxy = new Proxy(target, handler);
target
:要包装的目标对象(可以是任何类型的对象,包括函数)。handler
:包含一组定义捕捉器(trap)的对象,这些捕捉器拦截对目标对象的操作。
handler 对象和捕捉器
handler
对象是一个普通的 JavaScript 对象,其中的属性是捕捉器函数。这些函数会在相应的操作被执行时调用。常用的捕捉器包括:
get(target, property, receiver)
:拦截对象属性的读取。set(target, property, value, receiver)
:拦截对象属性的设置。has(target, property)
:拦截in
操作符。deleteProperty(target, property)
:拦截delete
操作符。apply(target, thisArg, argumentsList)
:拦截函数调用。construct(target, args, newTarget)
:拦截new
操作符。