前端面试题详解整理59|一个树建立前缀索引 双等号,三等号,object.is()的区别不借助js如何实现html原生懒加载,.Symbol的介绍,使用场景,

33 阅读10分钟

阿里前端一面

部门:阿里妈妈
总结:电话面,答得都挺好的,但是才半个小时就结束了我感觉被kpi了,但是面试官看了我的github,又不像kpi了
大都是常见八股,干脆只写比较难的

1.不借助js如何实现html原生懒加载(搜不到,好像就这个没答上来)

在不使用JavaScript的情况下,可以使用HTML的loading属性来实现图片的原生懒加载。loading属性可以设置为以下三个值之一:

  1. auto:默认值,浏览器自动选择何时加载图片。
  2. lazy:浏览器会在视口附近的图片即将进入视图时开始加载。
  3. eager:浏览器会立即加载图片。

以下是一个示例,演示如何使用loading属性实现原生的懒加载:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lazy Loading Images</title>
</head>
<body>
    <h1>Lazy Loading Images</h1>
    <img src="placeholder.jpg" data-src="image.jpg" alt="Lazy Loaded Image" loading="lazy">
</body>
</html>

在上面的示例中,img元素的src属性设置了一个占位图片,而data-src属性设置了实际图片的URL。loading属性被设置为lazy,表示浏览器会在图片进入视口附近时开始加载实际图片,而不是立即加载。

这样做的好处是,浏览器会自动处理图片的加载时机,根据用户的浏览行为来优化性能,同时不需要编写JavaScript代码来实现懒加载效果。但需要注意的是,loading属性并不是所有浏览器都支持,因此在实际项目中可能需要使用JavaScript来实现兼容性处理。

2.Symbol的介绍,使用场景,获取原来可能存在的symbol怎么做(symbol.for)

Symbol是ES6引入的一种新的基本数据类型,用于创建唯一的、不可变的值。Symbol值是通过Symbol构造函数创建的,每个Symbol值都是唯一的,即使是创建了相同描述的Symbol值,它们也是不相等的。

使用场景:

  1. 创建唯一的对象属性名:由于Symbol值是唯一的,可以用作对象的属性名,以避免属性名冲突的问题。
  2. 定义私有属性和方法:在类的定义中,可以使用Symbol值来定义私有属性和方法,因为Symbol值是不可见的,外部无法直接访问到。
  3. 作为常量:可以使用Symbol值来定义常量,因为Symbol值是唯一的,可以确保常量的唯一性。

获取可能已存在的Symbol: 在JavaScript中,可以使用Symbol.for(key)方法来获取可能已存在的Symbol。Symbol.for(key)会首先在全局Symbol注册表中查找具有指定键的Symbol值,如果找到则返回该Symbol值,否则会创建一个新的Symbol值并注册到全局注册表中。

以下是一个示例:

// 创建一个Symbol值,并注册到全局Symbol注册表中
const symbol1 = Symbol.for('mySymbol');

// 获取已存在的Symbol值
const symbol2 = Symbol.for('mySymbol');

// 判断两个Symbol值是否相等
console.log(symbol1 === symbol2); // 输出 true

在上面的示例中,symbol1symbol2是通过Symbol.for('mySymbol')创建的,它们的描述相同,因此它们是相等的,即使它们是通过不同的变量来获取的。这是因为它们都是在全局Symbol注册表中注册的同一个Symbol值。

3.双等号,三等号,object.is()的区别

双等号(==)、三等号(===)和Object.is()是JavaScript中用于比较两个值的操作符或方法,它们之间有一些区别:

  1. 双等号(==)

    • 双等号是JavaScript中的相等操作符,用于比较两个值是否相等。在进行比较时,双等号会进行类型转换,如果两个值的类型不同,则会尝试将它们转换为相同的类型,然后再进行比较。
    • 双等号的行为比较隐式,不够严谨,容易引起一些意想不到的结果。比如,0 == false'' == false 都会返回true,这是因为双等号在比较时会进行类型转换。
  2. 三等号(===)

    • 三等号是JavaScript中的严格相等操作符,用于比较两个值的类型和值是否完全相等。在进行比较时,三等号不会进行类型转换,只有当两个值的类型和值都相同时才会返回true,否则返回false。
    • 三等号的行为更加严谨和可预测,推荐在大多数情况下使用,尤其是在需要严格比较值的类型时。
  3. Object.is()方法

    • Object.is()是ES6引入的方法,用于比较两个值是否严格相等。它的行为与三等号相似,但有两个特殊情况:首先,NaNNaN相等,其次,+0-0不相等。
    • Object.is()的行为更加符合直觉,避免了一些双等号和三等号的隐式类型转换和特殊情况。

总的来说,推荐使用三等号(===)进行严格相等比较,如果需要处理特殊情况或者想要更加明确的行为,可以考虑使用Object.is()方法。避免使用双等号(==),因为它的行为相对隐式,容易导致混淆和错误。

作者:Tantanz
链接:www.nowcoder.com/feed/main/d…
来源:牛客网

阿里 饿了么 前端 一二三面

一面
项目面,问项目技术
http缓存
二面

笔试 用一个树建立前缀索引

要建立一个前缀索引树(Trie树),首先需要定义Trie节点的数据结构。每个Trie节点应该包含一个字典或者映射,用于存储子节点,以及一个布尔值,表示当前节点是否是一个单词的结束。

以下是一个简单的JavaScript实现:

class TrieNode {
    constructor() {
        this.children = {}; // 子节点字典
        this.isEndOfWord = false; // 是否是单词的结束
    }
}

class Trie {
    constructor() {
        this.root = new TrieNode(); // 根节点
    }

    // 向Trie树中插入一个单词
    insert(word) {
        let node = this.root;
        for (let char of word) {
            if (!node.children[char]) {
                node.children[char] = new TrieNode();
            }
            node = node.children[char];
        }
        node.isEndOfWord = true; // 标记单词的结束
    }

    // 检查一个单词是否在Trie树中
    search(word) {
        let node = this.root;
        for (let char of word) {
            if (!node.children[char]) {
                return false; // 如果找不到字符,则单词不存在
            }
            node = node.children[char];
        }
        return node.isEndOfWord; // 返回最后一个字符节点是否表示单词的结束
    }

    // 检查一个字符串是否是其他任何单词的前缀
    startsWith(prefix) {
        let node = this.root;
        for (let char of prefix) {
            if (!node.children[char]) {
                return false; // 如果找不到字符,则不是任何单词的前缀
            }
            node = node.children[char];
        }
        return true; // 如果能够找到所有字符,则说明是其他单词的前缀
    }
}

// 示例用法
const trie = new Trie();
trie.insert('apple');
console.log(trie.search('apple'));   // 输出 true
console.log(trie.search('app'));     // 输出 false
console.log(trie.startsWith('app')); // 输出 true
trie.insert('app');
console.log(trie.search('app'));     // 输出 true

在这个实现中,每个Trie节点包含一个名为children的字典,用于存储子节点。插入一个单词时,从根节点开始遍历单词的每个字符,如果当前字符的子节点不存在,则创建一个新的节点。插入完成后,将最后一个字符的节点标记为单词的结束。搜索一个单词或者检查一个字符串是否是其他单词的前缀时,也是从根节点开始遍历,如果遇到不存在的字符节点,则返回false;如果遇到单词的最后一个字符,则返回该节点的isEndOfWord属性。

通过这种方式,我们可以有效地构建和使用Trie树来建立前缀索引,用于高效地搜索、匹配和过滤单词或者字符串。

项目 

大文件上传,

大文件上传是指上传文件大小较大的情况,通常指几十兆甚至几个G的文件。在前端开发中,由于HTTP协议的限制以及浏览器和服务器的性能限制,直接上传大文件存在一些挑战。以下是一些常见的处理方法:

  1. 分片上传:将大文件切分成多个小块(片),分别上传到服务器,然后在服务器端进行合并。这样做可以避免一次性上传大文件所带来的网络和性能压力,并且可以实现断点续传功能。前端可以使用File.slice()方法将文件切分成多个片,并通过多个HTTP请求进行上传。

  2. 流式上传:将大文件通过流式方式上传,即边读取文件内容,边上传到服务器,而不是一次性读取整个文件内容后再上传。这种方法可以减少内存占用,并且可以在上传过程中实时监测上传进度。前端可以使用FileReader API读取文件内容,并通过XMLHttpRequest或者fetch API进行上传。

  3. 使用WebSocket或者WebRTC:WebSocket和WebRTC可以实现双向通信,可以用于大文件的实时传输。前端可以将文件内容通过WebSocket或者WebRTC发送到服务器,服务器接收到数据后进行处理或者存储。

  4. 使用第三方服务:一些第三方服务(如阿里云、七牛云等)提供了专门的大文件上传服务,可以利用它们的SDK来实现大文件的上传功能。这些服务通常会提供断点续传、并发上传等高级功能,能够更好地处理大文件上传的问题。

不管使用哪种方法,都需要注意上传过程中的网络稳定性、服务器性能以及用户体验等因素,以确保大文件上传的顺利进行。同时,还需要考虑安全性问题,例如对上传的文件进行安全检查和限制,防止恶意文件上传和攻击。

断点续传

断点续传是指在文件上传过程中,如果由于网络中断或者其他原因导致上传中断,可以在恢复上传时从中断的位置继续上传,而不是重新开始上传整个文件。这可以提高上传的可靠性和效率,尤其是在上传大文件时。

实现断点续传的基本思路是将文件分成若干个固定大小的块(片),并记录每个块已经上传的字节数或者标记已上传的块。当上传中断后,可以根据已上传的字节数或者标记的块继续上传剩余的部分,而不必重新上传整个文件。

以下是一个简单的实现断点续传的示例:

// 假设这是一个上传文件的函数
function uploadFile(file, startByte) {
    // 模拟上传过程
    setTimeout(() => {
        const chunkSize = 1024 * 1024; // 每个块的大小
        const chunk = file.slice(startByte, startByte + chunkSize); // 切分文件为块
        const percent = (startByte + chunk.size) / file.size * 100; // 计算上传进度

        console.log(`Uploading ${percent.toFixed(2)}%`);

        // 模拟上传成功后的操作
        if (startByte + chunk.size >= file.size) {
            console.log('Upload complete!');
        } else {
            // 模拟上传中断
            // 模拟断点续传,继续上传下一块
            uploadFile(file, startByte + chunk.size);
        }
    }, 1000); // 模拟延迟
}

// 使用示例
const file = new File(["dummy content"], "example.txt", { type: "text/plain" });
uploadFile(file, 0); // 开始上传文件

在上面的示例中,uploadFile函数用于模拟上传文件的过程。每次上传时,根据起始字节和块大小切分文件,并计算上传进度。如果上传过程中断,可以根据已上传的字节数继续上传剩余的部分,而不必重新上传整个文件。 深挖项目技术点
三面
项目
hr混合面

offer
三场面试八股含量低,深挖项目。三次都是阿里会议,无电话面。
现在应该还有hc 速冲,2000房补 350一天(本科) 包酒店路费

作者:如雨
链接:www.nowcoder.com/feed/main/d…
来源:牛客网