161期
1. commonjs中的module.export和module怎么实现的?
2. export和default export有什么区别?
3. commonJs的模块和esmodule的模块有什么区别?
上面问题的答案会在第二天的公众号(程序员每日三问)推文中公布
也可以小程序刷题,已收录500+面试题及答案
160期问题及答案
1. JS中改变this指向的方法有哪些?
在JavaScript中,this
指向的是函数调用的上下文,它可能是全局对象、函数内部的局部对象、某个对象的方法或者通过构造函数创建的实例。但有时,我们需要改变this
的指向,以适应不同的编程场景。JavaScript提供了几种方法来实现这一点:
call()
方法:call()
方法可以让我们在调用函数时,将函数内部的this
指向第一个参数指定的对象。如果第一个参数为null
或undefined
,this
会指向全局对象。function showName(label) { console.log(label + ':', this.name); } const person = { name: 'Alice' }; showName.call(person, 'Person Name'); // 输出:Person Name: Alice
apply()
方法:apply()
方法的作用与call()
方法类似,唯一的区别是apply()
方法接受参数为一个数组(或者类数组对象)。function sum(a, b) { return a + b + this.c; } const obj = { c: 3 }; console.log(sum.apply(obj, [1, 2])); // 输出:6
bind()
方法:bind()
方法可以创建一个新的函数,这个新函数的this
被永久绑定为bind()
方法的第一个参数指定的对象,不管这个新函数是如何被调用的。function greet(greeting) { console.log(greeting + ' ' + this.name); } const user = { name: 'John' }; const greetUser = greet.bind(user); greetUser('Hello'); // 输出:Hello John
箭头函数:箭头函数不绑定自己的
this
,它会捕获其所处上下文的this
值作为自己的this
值。因此,在箭头函数内部使用this
时,其指向在它被创建时的上下文。const person = { name: 'Emma', sayHi: function() { setTimeout(() => { console.log('Hi, ' + this.name); }, 1000); } }; person.sayHi(); // 1秒后输出:Hi, Emma
请注意,在箭头函数中,尝试使用call()
、apply()
或bind()
方法改变this
指向是不会有效果的,因为箭头函数的this
已经按词法作用域绑定了。
使用上下文对象:有时候,你可能不想用上述方法中的任意一个来改变this的指向,你也可以通过将需要的this值保存到一个变量中,然后在需要的地方使用这个变量。
function Timer() { this.seconds = 0; var self = this; // 保存this值 setInterval(function() { self.seconds++; }, 1000); } var timer = new Timer(); setTimeout(() => console.log(timer.seconds), 3100); // 大约3秒后输出:3
上述方法都是在不同场景下用来改变函数内部this
指向的常见技术。一定要根据具体的编程需求和场景来选择合适的方法。
2. 说说React事件和原生事件的执行顺序?
在React中,事件处理机制由React自己的合成事件(SyntheticEvent)系统处理,并不是原生事件处理机制。React的合成事件系统是基于原生事件系统之上实现的,它在内部为了处理跨浏览器的兼容性问题,抹平了浏览器之间的差异,同时也提供了一种方式来在React的组件树中更加一致地处理事件。
React事件和原生事件的执行顺序取决于如何注册这些事件。如果你使用React来绑定事件,那么合成事件会首先处理,然后才是任何原生事件处理器。React在文档的根节点上添加了单一的事件监听器来处理所有事件,这种事件处理机制称为事件委托。
具体执行顺序如下:
当事件发生时,首先触发React的合成事件处理机制。
若在React中注册的事件中调用了
event.stopPropagation()
,事件将不会冒泡到DOM树更上层的原生事件监听器。如果没有在React的合成事件中阻止事件冒泡,合成事件处理完成后,事件会继续冒泡,按照事件监听器在DOM树中的注册位置,触发对应的原生事件监听器。
如果原生事件处理器调用了
event.stopPropagation()
,继续冒泡的过程则停止。
举例来说,如果你在一个React元素上通过onClick
属性注册了事件处理函数,并且也在其父元素的原生DOM上通过addEventListener
注册了一个click
事件处理器,点击该React元素时会发生如下情况:
React内部的合成click事件首先被触发。
如果合成事件处理函数中没有调用
event.stopPropagation()
,事件会继续传播。DOM树中的原生click事件监听器随后被触发。
需要注意的是,从React 17开始,React事件处理不再使用文档根节点上的事件委托,而是将事件委托到了React挂载的根节点(即ReactDOM.render(<App />, root)
中的root
)。相比之前的版本,这改变了一些事件处理的细节,但总体的执行顺序仍然如上所述。
示例代码:
class MyComponent extends React.Component {
componentDidMount() {
// 在原生DOM上注册一个click事件
this.ref.addEventListener('click', this.handleNativeClick);
}
componentWillUnmount() {
// 组件卸载前移除在原生DOM上注册的click事件
this.ref.removeEventListener('click', this.handleNativeClick);
}
handleNativeClick = (e) => {
console.log('native event');
// 可以调用e.stopPropagation()阻止事件冒泡到React合成事件
};
handleClick = (e) => {
console.log('synthetic event');
// 使用e.stopPropagation()可以阻止事件冒泡到原生事件
};
render() {
// 使用React的合成事件注册click事件
return <div onClick={this.handleClick} ref={(el) => { this.ref = el; }}>Click Me</div>;
}
}
在上述示例中,如果点击<div>
元素,控制台会首先打印synthetic event
,然后打印native event
。如果我们在handleClick
(合成事件处理器)中调用了e.stopPropagation()
,handleNativeClick
将不会执行,因此控制台只会打印synthetic event
。
3. 去除字符串中出现次数最少的字符,不改变原字符串的顺序
要去除一个字符串中出现次数最少的字符,不改变原字符串的顺序,可以按照以下步骤编写代码:
首先统计字符串中每个字符出现的次数。
找出出现次数最少的字符,可能有多个。
遍历原字符串,构建一个新字符串,只包含出现次数不是最少的字符。
以下是用JavaScript实现的示例代码:
function removeLeastFrequentChars(str) {
const charMap = {};
let minFrequency = Infinity;
let result = '';
// 统计每个字符的出现次数
for (const char of str) {
if (!charMap[char]) {
charMap[char] = 1;
} else {
charMap[char] += 1;
}
// 与最小出现次数进行比较
minFrequency = Math.min(minFrequency, charMap[char]);
}
// 找出出现次数最少的字符集合
const leastFrequentChars = new Set();
for (const char in charMap) {
if (charMap[char] === minFrequency) {
leastFrequentChars.add(char);
}
}
// 构建不包含出现次数最少字符的字符串
for (const char of str) {
if (!leastFrequentChars.has(char)) {
result += char;
}
}
return result;
}
// 示例
const input = 'ababac';
const output = removeLeastFrequentChars(input);
console.log(output); // 'ababa'
在这个例子中,我们通过charMap
对象来计数每个字符的出现次数,然后通过leastFrequentChars
集合确定哪些字符是出现次数最少的。最后,我们遍历原字符串str
,并构建出新的字符串result
,其中不包括出现次数最少的字符。这样,新字符串保留了原有字符的顺序,只是去除了那些出现次数最少的字符。
因为微信公众号修改规则,如果不标星或点在看,你可能会收不到我公众号文章的推送,请大家将本公众号星标,看完文章后记得点下赞或者在看,谢谢各位!
学习不打烊,充电加油只为遇到更好的自己,每天早上9点纯手工发布面试题,每天坚持花20分钟来学习与思考,在千变万化,类库层出不穷的今天,不要等到找工作时才狂刷题,提倡每日学习。