165期
1. 前端跨页面通信,你知道哪些方法?
2. 什么是 CI/CD?
3. flex 布局下,怎么改变元素的顺序?
上面问题的答案会在第二天的公众号(程序员每日三问)推文中公布
也可以小程序刷题,已收录500+面试题及答案
164期问题及答案
1. 说说你对 new.target 的理解
new.target
是 JavaScript 中的一个元数据属性,它在函数或构造器内部使用时,提供了一种检测该函数或构造器是通过 new
运算符调用的还是作为普通函数调用的方法。这个属性对于构造器特别有用,因为它允许构造器了解它们是如何被调用的。
当一个函数或构造器通过 new
运算符被调用时,new.target
返回一个指向该构造器或函数的引用。如果该函数或构造器不是通过 new
调用的,则 new.target
的值是 undefined
。
这个特性在设计可以既作为构造器又可以作为普通函数调用的函数时特别有用。通过检查 new.target
的值,你可以决定函数应该如何行为。
例如,假设你有一个名为 MyClass
的构造器函数,你可以在函数内部使用 new.target
来检测 MyClass
是作为构造器被调用的还是作为普通函数被调用的:
function MyClass() {
if (new.target) {
console.log('MyClass instantiated with new');
} else {
console.log('Called as a regular function');
}
}
// 当作构造器使用
var instance = new MyClass(); // 输出: MyClass instantiated with new
// 当作普通函数使用
MyClass(); // 输出: Called as a regular function
在上面的例子中,当 MyClass
通过 new
被实例化时,new.target
是 MyClass
。但如果直接调用 MyClass
函数(不使用 new
),new.target
的值就是 undefined
,从而使得函数可以相应地调整其行为。
2. 你是怎么理解ES6中 Decorator 的?使用场景有哪些?
在 ES6(ECMAScript 2015)中,装饰器(Decorator)是一个提案中的语法,用于在定义类和类成员时提供额外的声明式处理。装饰器是一个特殊类型的函数,它可以被附加到类声明、方法、访问器、属性或参数上。装饰器使用 @expression
这种形式,其中 expression
必须计算出一个函数,这个函数在运行时会被调用,被装饰的声明信息作为参数传入。
理解装饰器
类装饰器:应用于类构造函数,用于观察、修改或替换类定义。参数是类的构造函数。
方法装饰器:应用于方法的属性描述符,可用于观察、修改或替换方法定义。参数包括类的原型对象、方法的名称以及方法的属性描述符。
访问器装饰器:应用于访问器的属性描述符,类似于方法装饰器。
属性装饰器:应用于类的属性,可以用来修改属性的定义。
参数装饰器:应用于类构造函数或方法的参数。
使用场景
日志和监控:可以用装饰器来自动记录某个方法的调用信息,便于调试和监控。
数据绑定:在框架中,装饰器可以用来绑定属性与某些 UI 元素。
权限验证:在访问某些资源前,通过装饰器来进行权限检查。
自动发布事件:用装饰器来自动发布事件,无需在每个方法中手动发布。
延迟计算/懒加载:使用装饰器来延迟某些处理,比如懒加载模块或数据。
修改或替换类成员:如自动绑定方法到实例上,或者修改类方法的行为。
依赖注入:在某些框架中,装饰器用于依赖注入。
示例
一个简单的日志装饰器示例:
function log(target, name, descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling ${name} with`, args);
return originalMethod.apply(this, args);
}
return descriptor;
}
class MyClass {
@log
myMethod(arg1, arg2) {
console.log(`Method was called with args: ${arg1} and ${arg2}`);
}
}
const obj = new MyClass();
obj.myMethod('Hello', 'World');
在这个例子中,log
装饰器会在 myMethod
被调用时输出日志信息。
需要注意的是,虽然装饰器在一些 JavaScript 社区和框架中广泛使用(如 Angular),但截至目前(2023年),装饰器仍然是一个 ECMAScript 提案,并未正式成为 JavaScript 语言规范的一部分。因此,在使用装饰器时需要依赖于 Babel 等转译器或特定的 JavaScript 运行时环境。
3. ES6中的 Reflect 对象有什么用?
ES6(ECMAScript 2015)引入了 Reflect
对象,它是一个内置的对象,提供了一系列静态方法来执行 JavaScript 的反射操作。这些操作包括了属性查找、赋值、枚举、函数调用等,与 Object
类的一些方法功能类似,但 Reflect
的方法更低层、更通用。
Reflect
对象的主要用途:
统一的对象操作:
Reflect
提供的方法对应于 JavaScript 语言内部的操作,使得这些操作可以在 JavaScript 代码中以函数的形式被调用。这带来了一种更一致和函数式的方式来处理对象和属性。与
Proxy
对象协作:Reflect
的方法与Proxy
对象的处理程序方法是对应的。这意味着你在Proxy
的处理程序中可以方便地调用对应的Reflect
方法。这使得创建代理变得更简单,同时保持行为的一致性。更好的错误处理:与
Object
的某些方法相比(如delete
操作符),Reflect
的方法会返回布尔值以指示操作是否成功,而不是抛出错误。这使得错误处理变得更加灵活。未来的兼容性:随着语言的发展,新的语言特性和行为可能首先在
Reflect
对象上实现,因此使用Reflect
可以在一定程度上确保代码的未来兼容性。
常用的 Reflect
方法:
Reflect.apply(target, thisArgument, argumentsList)
: 用于调用函数。Reflect.construct(target, argumentsList)
: 类似于new
操作符,用于创建一个新对象。Reflect.get(target, propertyKey)
: 获取对象属性的值。Reflect.set(target, propertyKey, value)
: 设置对象属性的值。Reflect.defineProperty(target, propertyKey, attributes)
: 类似于Object.defineProperty
。Reflect.deleteProperty(target, propertyKey)
: 删除对象的属性。Reflect.has(target, propertyKey)
: 类似于in
操作符,判断对象是否拥有某个属性。Reflect.ownKeys(target)
: 返回对象的所有自有属性键。
示例:
使用 Reflect.get
获取对象属性:
const obj = { x: 1, y: 2 };
console.log(Reflect.get(obj, 'x')); // 输出 1
使用 Reflect.set
设置对象属性:
Reflect.set(obj, 'z', 3);
console.log(obj.z); // 输出 3
这些示例展示了 Reflect
如何以一种更一致和模块化的方式处理对象操作。总的来说,Reflect
是 JavaScript 中处理对象和执行反射操作的一个强大工具。
因为微信公众号修改规则,如果不标星或点在看,你可能会收不到我公众号文章的推送,原创不易,请大家将本公众号星标,看完文章后记得点下赞或者在看,谢谢各位!
学习不打烊,充电加油只为遇到更好的自己,每天早上9点纯手工发布面试题,每天坚持花20分钟来学习与思考,在千变万化,类库层出不穷的今天,不要等到找工作时才狂刷题,提倡每日学习。