记录面试题!

一、js深浅拷贝

//深拷贝   
function deepCopy(data) {         
    if (data === null || typeof data !== "object") {
               return data;         
    }  ​         
    let arr = Array.isArray(data) ? [] : {};         
    for (let key in data) {               
        arr[key] = deepCopy(data[key]);         
    }            
    return arr;         
}         

//深拷贝
let data = {             
 name: "zyd",              
 age: 18,              
 list: [1, 2, 3, [4, 5, 6,]],              
 say: function () {                  
  console.log("Hello!");             
 }         
}          
console.log(data);          
let arr = deepCopy(data);          
arr.list[0] = 100;          
console.log(arr);  
//浅拷贝  
let arr1 = [1, 2];  
let arr2 = [...arr1];  ​  
console.log(arr2); // [1, 2]  ​  
let obj1 = { a: 1, b: 2 };  
let obj2 = { ...obj1 };  ​  
console.log(obj2); // { a: 1, b: 2 }  ​  
let obj1 = { a: 1, b: 2 };  
let obj2 = Object.assign({}, obj1);  ​  
console.log(obj2); // { a: 1, b: 2 }

二、数组常用的方法

push() 方法可以在数组的末尾添加一个或多个元素,并返回新数组的长度。

pop() 方法可以从数组的末尾移除一个元素,并返回该元素的值。

unshift() 方法可以在数组的开头添加一个或多个元素,并返回新数组的长度。

shift() 方法可以从数组的开头移除一个元素,并返回该元素的值。

forEach() 方法可以对数组中的每个元素执行一次指定的函数。

map() 方法可以将数组中的每个元素按照指定的方式转换成一个新的元素,并返回一个新数组。

filter() 方法可以筛选出数组中符合条件的元素,并返回一个新数组。

reduce() 方法可以对数组中的所有元素进行累加计算,并返回一个结果。

indexOf() 方法可以返回数组中第一个匹配指定值的元素的索引,如果没有找到则返回 -1。

lastIndexOf() 方法可以返回数组中最后一个匹配指定值的元素的索引,如果没有找到则返回 -1。

includes() 方法可以返回数组是否包含指定的值。

sort() 方法可以对数组进行排序,默认按照字母顺序排序。

reverse() 方法可以将数组中的元素按照相反的顺序排列。

splice() 方法可以向数组中插入、删除或替换元素,并返回被删除的元素。

concat() 方法可以将多个数组合并成一个新数组。

join() 方法可以将数组中的所有元素按照指定的分隔符连接成一个字符串。

slice() 方法可以从数组中提取指定位置的元素,并返回一个新数组。

三、跨域

跨域(Cross-Origin)指的是在Web开发中,当一个网页尝试从一个不同域名下的服务器请求资源时会出现的安全限制。这种情况下,由于浏览器的同源策略(Same-Origin Policy)限制,页面无法直接使用XMLHttpRequest或Fetch API向不同域的服务器发送请求。

同源策略要求网页中所有的脚本只能访问其所属的域名下的资源,它的目的是防止恶意网站窃取用户数据。同源策略规定了协议、域名、端口号必须完全一致,否则就属于跨域。

在项目中,可以采取以下方法来解决跨域问题:

  1. CORS(跨域资源共享):在服务端设置合适的CORS头部,允许指定的域名访问资源。通过在响应头中添加特定的字段,如Access-Control-Allow-Origin,Access-Control-Allow-Methods等,来实现跨域资源共享。
  2. JSONP(JSON with Padding):通过动态创建script标签,向目标服务器请求数据,并在响应中返回JSON数据,并通过回调函数的方式处理返回的数据。
  3. 代理:在自己的服务器上设置代理,将客户端请求转发到目标服务器,然后把响应结果返回给客户端。这样客户端请求的就是同源的资源,不存在跨域问题。
  4. WebSocket:通过WebSocket协议进行跨域通信,WebSocket并不受同源策略的限制。
  5. 使用反向代理:在服务器端设置反向代理,将来自不同域的请求转发到目标服务器,然后将响应返回给客户端。

四、useRef

useRef的语法如下:

const refContainer = useRef(initialValue);

其中,initialValue是初始值,可以是任何类型的值。refContainer是一个可变的ref对象,它的current属性被初始化为initialValue。在组件渲染时,refContainer.current的值会被保留,并在后续的渲染中保持不变。

使用useRef的场景:

  1. 访问DOM元素:通过useRef可以访问到DOM元素,从而获取或修改它们的属性。
  2. 存储组件实例:通过useRef可以存储组件实例的引用,方便在组件内部进行操作。
  3. 缓存数据:可以使用useRef来缓存一些临时的数据,这些数据不需要触发组件的重新渲染。

使用useRef的示例:

import { useRef } from 'react';
function Example() {    
    const inputRef = useRef(null);  ​    
    function handleButtonClick() {      
        inputRef.current.focus();   
    }  ​   
    return (      
        <div>        
            <input type="text" ref={inputRef} />        
            <button onClick={handleButtonClick}>Focus Input</button>      
        </div>   
    );  
}

在上面的例子中,我们创建了一个inputRef对象,并将其作为ref传递给input元素。在handleButtonClick函数中,我们调用inputRef.current.focus()来聚焦输入框。

五、数组去重

  1. 使用 Set

利用 Set 数据结构的特性,Set 中的元素不会重复,可以将数组转换为 Set,然后再转回数组即可实现去重。

 let arr = [1, 2, 2, 3, 4, 4, 5]; 
 let uniqueArr = Array.from(new Set(arr));  
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用 indexOf 或 includes

遍历原数组,利用 indexOf 或 includes 方法判断元素是否已经存在于新数组中,如果不存在则添加到新数组中。

 let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = [];  
for (let i = 0; i < arr.length; i++) {   
    if (uniqueArr.indexOf(arr[i]) === -1) {     
      uniqueArr.push(arr[i]);   
    }  
} 
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用 filter

利用 filter 方法筛选出原数组中第一次出现的元素。

let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = arr.filter(function(item, index, array) {    
    return array.indexOf(item) === index;  
});  
console.log(uniqueArr); // [1, 2, 3, 4, 5]
  1. 使用 reduce

利用 reduce 方法遍历原数组,在遍历过程中将出现的元素存储到一个临时对象中,并以元素值为键,然后再将对象的键值提取出来作为去重后的数组。

 let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = arr.reduce(function(prev, curr) {    
    if (prev.indexOf(curr) === -1) {      
        prev.push(curr);   
    }    
    return prev;  
}, []);  
console.log(uniqueArr); // [1, 2, 3, 4, 5]

六、react性能优化

React是一个高性能的JavaScript库,但在复杂的应用中,仍然需要优化性能以提高应用的响应速度和用户体验。以下是一些React中常用的性能优化技术:

  1. 使用PureComponent或React.memo:PureComponent是React中的一个优化组件,它会自动检查props和state的变化,并且只在需要时重新渲染组件。如果组件的props和state都没有变化,那么PureComponent会直接使用之前的渲染结果。React.memo是类似的钩子函数,用于函数式组件。
  2. 避免不必要的渲染:在React中,当state或props发生变化时,组件会重新渲染。为了减少不必要的渲染,可以使用shouldComponentUpdate生命周期函数来手动控制组件的渲染。
  3. 使用虚拟化列表:在展示大量数据时,为了避免一次性渲染大量DOM元素导致性能问题,可以采用虚拟化列表的方式,只渲染当前可见区域内的元素。
  4. 避免多余的事件处理器:在React中,每个事件处理器都会占用一定的内存。为了避免内存泄漏和浪费,需要避免创建不必要的事件处理器。
  5. 使用useCallback和useMemo:useCallback用于缓存函数,避免不必要的重新创建,useMemo用于缓存计算结果,避免不必要的重复计算。
  6. 合理使用React.lazy和Suspense:React.lazy用于实现动态导入组件,Suspense用于在组件加载过程中显示占位符,避免用户看到空白页面。
  7. 尽可能使用函数式组件:函数式组件比类组件更轻量级,渲染速度更快,同时也更容易进行代码拆分和组合。
  8. 使用Redux或Context API进行状态管理:当应用的状态变得复杂时,可以使用Redux或Context API进行状态管理,避免状态分散在各个组件中,提高组件的重用性和可维护性。

七、react父子通信

父组件向子组件传递数据(通过props):

 // ParentComponent.js  
import React from 'react';  
import ChildComponent from './ChildComponent';  ​  
function ParentComponent() {    
    const data = 'Hello from parent';  ​    
    return (      
        <div>        
            <ChildComponent dataFromParent={data} />      
        </div>   
    );  
}  ​  
export default ParentComponent;  

// ChildComponent.js  
import React from 'react';  ​  
function ChildComponent(props) {   
     return (      
        <div>        
            <p>{props.dataFromParent}</p>      
        </div>   
    );  
}  ​  
export default ChildComponent;

在上面的例子中,父组件通过将data作为props传递给子组件ChildComponent,子组件可以通过props.dataFromParent来接收父组件传递的数据。

子组件向父组件通信(通过回调函数):

// ParentComponent.js  
import React from 'react';  
import ChildComponent from './ChildComponent';  ​  
function ParentComponent() {    
    function handleChildClick(dataFromChild) {      
        console.log('Data from child:', dataFromChild);   
    }  ​    
    return (      
        <div>        
            <ChildComponent onChildClick={handleChildClick} />      
        </div>   
    );  
}  ​
  
export default ParentComponent;  
// ChildComponent.js  
import React from 'react';  ​  
function ChildComponent(props) {    
    function handleClick() {      
        props.onChildClick('Hello from child');   
    }  ​    
    return (      
        <div>        
            <button onClick={handleClick}>Click Me</button>      
    </div>   
    );  
}  ​ 
export default ChildComponent;

八、在开发sdk的时候,接收参数都有什么,是什么规范的

在开发SDK时,接收参数的具体内容和规范可以根据SDK的用途和设计需求进行定义。以下是一些常见的接收参数的规范和建议:

  1. SDK初始化参数:通常在初始化SDK时,需要接收一些必要的参数来配置SDK的行为,例如API密钥、访问令牌、服务器地址等。
  2. 方法调用参数:SDK提供的各种方法可能需要不同的参数来完成相应的功能。这些参数应该根据方法的用途和需求来定义,例如查询条件、排序方式、过滤器等。
  3. 回调函数:某些情况下,SDK可能需要接收回调函数作为参数,用于异步操作的结果返回或事件的处理。回调函数可以是预定义的函数,也可以通过匿名函数传递。
  4. 配置项:一些SDK可能支持用户自定义的配置项,以满足个性化需求。这些配置项可以作为参数传递给SDK,例如主题颜色、布局样式等。

在定义接收参数的规范时,可以考虑以下几点:

  • 清晰明确:参数的名称应该具有描述性,能够清晰地表达其含义和作用。
  • 必要性和可选性:根据功能需求,将必要的参数定义为必须传递,而将可选的参数定义为可选项。
  • 类型和约束:明确参数的类型(如字符串、数字、函数等)以及可能的取值范围或约束条件。
  • 默认值:为可选参数提供合理的默认值,以方便用户在不传递该参数时使用。

除了参数的定义规范外,还可以通过文档、示例代码和注释等方式提供详细的参数说明和使用示例,以便开发者能够正确地使用SDK提供的接口。此外,如果SDK是面向多种编程语言的,还应该考虑各种语言的习惯和约定,并尽量保持一致性和易用性。

九、react生命周期

在早期版本的React中,组件生命周期由三个阶段组成:Mounting(挂载)、Updating(更新)和Unmounting(卸载)。随着React版本的更新,引入了新的生命周期方法,并在React 16.3版本后对生命周期方法进行了调整和更新。下面是React组件的生命周期方法:

挂载阶段(Mounting)

  1. constructor(props) :组件的构造函数,在组件被创建和初始化时调用。
  2. static getDerivedStateFromProps(props, state) :在组件挂载之前和更新时调用,用于根据props初始化state或者在props变化时更新state。
  3. render() :根据组件的props和state返回一个React元素,是类组件中唯一必须实现的方法。
  4. componentDidMount() :在组件挂载后立即调用,可以进行DOM操作、数据请求等副作用。

更新阶段(Updating)

  1. static getDerivedStateFromProps(props, state) :与挂载阶段相同,用于根据props更新state。
  2. shouldComponentUpdate(nextProps, nextState) :在props或state发生变化时调用,用于控制是否需要重新渲染组件,默认返回true。
  3. render() :同挂载阶段的render方法。
  4. getSnapshotBeforeUpdate(prevProps, prevState) :在更新DOM之前调用,适合获取更新前的DOM状态信息。
  5. componentDidUpdate(prevProps, prevState, snapshot) :在组件更新完成后调用,可以进行DOM操作、数据请求等副作用。

卸载阶段(Unmounting)

  1. componentWillUnmount() :在组件即将被卸载和销毁时调用,用于清理定时器、取消订阅等清理工作。

错误处理阶段(Error Handling)

  1. static getDerivedStateFromError(error) :在渲染过程中,子组件抛出错误时调用,用于更新state以渲染备用UI。
  2. componentDidCatch(error, info) :在渲染后捕获子组件抛出的错误,可以记录错误信息或发送错误报告。

新的生命周期方法

随着React的不断发展,还引入了一些新的生命周期方法:

  • UNSAFE_componentWillMount() :在组件挂载前被调用,不建议使用,可以用componentDidMount替代。
  • UNSAFE_componentWillReceiveProps(nextProps) :在组件接收新的props前被调用,不建议使用,可以用getDerivedStateFromProps或componentDidUpdate替代。
  • UNSAFE_componentWillUpdate(nextProps, nextState) :在组件即将更新时被调用,不建议使用,可以用getDerivedStateFromProps、getSnapshotBeforeUpdate或componentDidUpdate替代。
  • UNSAFE_componentWillUpdate(nextProps, nextState) :在组件即将更新时被调用,不建议使用,可以用getDerivedStateFromProps、getSnapshotBeforeUpdate或componentDidUpdate替代。

在新版的React中,推荐使用getDerivedStateFromProps、componentDidMount、shouldComponentUpdate、getSnapshotBeforeUpdate、componentDidUpdate等方法来处理组件的生命周期,而避免使用已经标记为不安全的生命周期方法。

场景题、 封装一个业务组件 实现点击checkbox 日历禁用 点击日历输出时间

当封装一个业务组件,实现点击Checkbox来禁用日历,并能够点击日历输出时间时,可以按照以下步骤进行:

  1. 创建一个业务组件:首先,创建一个React组件来封装该业务功能。可以使用函数组件(Functional Component)或类组件(Class Component)。
  2. 定义组件的状态:在组件内部定义状态(state),用于保存checkbox的选中状态和日历的禁用状态。可以使用useState钩子(在函数组件中)或setState方法(在类组件中)来管理状态。
  3. 处理checkbox的点击事件:为checkbox绑定点击事件处理函数,当checkbox被点击时,更新组件的状态,将checkbox的选中状态反转。
  4. 处理日历的禁用状态:根据checkbox的选中状态,动态设置日历的禁用状态。可以使用disabled属性或自定义类名来控制日历的样式。
  5. 处理日历的日期选择事件:为日历绑定日期选择事件处理函数,当选择日期时,获取选中的日期,并进行相应的逻辑处理。可以将选中的日期保存到组件的状态中,以便后续使用。
  6. 输出时间:根据需要,在组件中定义一个函数,用于格式化日期,并将选中的日期输出到控制台或其他地方。

下面是一个示例代码,演示了如何封装一个满足上述需求的业务组件:

 import React, { useState } from 'react';  ​  
function CalendarComponent() {    
    const [isChecked, setIsChecked] = useState(false);    
    const [selectedDate, setSelectedDate] = useState(null);  ​    
    const handleCheckboxChange = () => {      
        setIsChecked(!isChecked);   
    };  ​    
    const handleDateSelect = (date) => {      
        setSelectedDate(date);      // 可根据需要进行其他逻辑处理      
        console.log('选中的日期:', date);   
    };  ​    
    return (      
        <div>        
            <label>          
                <input type="checkbox" checked={isChecked} onChange={handleCheckboxChange} />                 
            </label>  ​        
        <div className={isChecked ? 'calendar disabled' : 'calendar'}>         
        {/* 日历组件的实现 */}         
        {/* 在日期被选择时调用 handleDateSelect 方法 */}        
        </div>      
        </div>   
    );  
}  ​ 
export default CalendarComponent;

在上述示例代码中,通过useState钩子定义了isChecked和selectedDate两个状态。handleCheckboxChange函数用于切换checkbox的选中状态,从而控制日历的禁用状态。handleDateSelect函数用于处理日历的日期选择事件,将选中的日期保存到selectedDate状态,并进行相应的逻辑处理。

请注意,上述示例代码只是一个简单的示例,并未包含完整的日历和日期选择功能。你可以根据具体需求自行实现日历组件和日期选择逻辑。

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值