字节前端日常实习(无转正)一面
1、自我介绍
2、CSS 实现一个圆
要使用 CSS 实现一个圆形,可以使用以下方法:
- 使用 border-radius 属性设置圆角为 50%。
- 将宽度和高度设置为相等的值。
- 可以使用 flex 或 grid 布局使元素保持正方形。
下面是一个示例:
.circle {
width: 100px;
height: 100px;
background-color: red;
border-radius: 50%;
}
<div class="circle"></div>
这样就创建了一个红色的圆形元素,其直径为 100px。
3、让元素垂直居中和水平居中的方法
要让元素实现垂直居中和水平居中,可以使用多种方法,以下是其中几种常用的方法:
- 使用 Flexbox 布局:
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
- 使用绝对定位和负边距:
.container {
position: relative;
}
.element {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 水平垂直居中 */
}
- 使用 Flexbox 和 margin 属性:
.container {
display: flex;
}
.element {
margin: auto; /* 水平垂直居中 */
}
- 使用 Grid 布局:
.container {
display: grid;
place-items: center; /* 水平垂直居中 */
}
这些方法都能够实现元素的水平居中和垂直居中,具体选择哪种方法取决于项目需求和布局的复杂程度。 4、讲讲 flex 属性
Flexbox(弹性盒子布局)是一种用于在容器中进行布局的现代 CSS 技术。Flexbox 提供了一种灵活的方式来排列、对齐和分配空间,特别适用于创建响应式和动态布局。
Flexbox 中的核心概念是容器和项目。容器是包含项目的父元素,而项目是容器内部的子元素。以下是 Flexbox 中常用的一些属性:
-
display:display: flex;: 将容器设置为弹性盒子,使其内部的子元素成为弹性项目。
-
容器属性:
flex-direction: 设置主轴的方向(row、row-reverse、column、column-reverse)。justify-content: 定义了项目在主轴上的对齐方式(flex-start、flex-end、center、space-between、space-around)。align-items: 定义了项目在交叉轴上的对齐方式(flex-start、flex-end、center、baseline、stretch)。flex-wrap: 定义了项目是否换行(nowrap、wrap、wrap-reverse)。align-content: 定义了多根轴线的对齐方式(flex-start、flex-end、center、space-between、space-around、stretch)。
-
项目属性:
flex-grow: 定义了项目的放大比例,默认为 0。flex-shrink: 定义了项目的缩小比例,默认为 1。flex-basis: 定义了项目在主轴上的初始大小,默认为 auto。flex: 是flex-grow,flex-shrink和flex-basis的简写形式。order: 定义了项目的排列顺序,默认为 0。
Flexbox 的强大之处在于它提供了灵活的布局方式,能够轻松实现各种复杂的布局需求,同时也能很好地适应不同尺寸和设备的屏幕。
5、H5 中的块元素和行内块元素
在 HTML5 中,元素通常被归类为块级元素(Block-level elements)和内联元素(Inline elements)。
-
块级元素(Block-level elements):
- 块级元素通常会在页面中创建一个块,独占一行,其宽度会填充父容器的整个宽度。
- 常见的块级元素包括
<div>、<p>、<h1>到<h6>、<ul>、<ol>、<li>、<table>、<form>等。
-
内联元素(Inline elements):
- 内联元素通常不会创建新的块,它们会在一行内显示,并且宽度只会占据其内容所需的空间。
- 常见的内联元素包括
<span>、<a>、<strong>、<em>、<img>、<input>、<button>、<label>等。
另外,HTML5 中还有一种特殊的元素称为行内块元素(Inline-block elements),它们具有块级元素的特性,但又像内联元素一样在一行内显示。常见的行内块元素包括 <div>(当设置为 display: inline-block; 时)、<span>、<img>(当设置为 display: inline-block; 时)等。
这些元素的分类有助于页面布局和样式设计。通过合理地选择和使用这些元素,可以更好地组织页面结构,并实现丰富的页面布局效果。
6、js 数据类型、判断数据类型的方法,call、apply、bind 方法、为什么不使用 toString 而是 Object.prototype.toString()
JavaScript 中的数据类型包括原始数据类型(Primitive data types)和对象类型(Object types)。
-
原始数据类型:
- 原始数据类型包括:字符串(String)、数字(Number)、布尔值(Boolean)、null、undefined 和 Symbol(ES6 新增)。
-
对象类型:
- 对象类型包括:对象(Object)、数组(Array)、函数(Function)、正则表达式(RegExp)等。
判断数据类型的方法有多种,常见的方法包括:
- 使用 typeof 操作符
- 使用 instanceof 操作符
- 使用 Object.prototype.toString.call() 方法
例如:
console.log(typeof "hello"); // 输出 "string"
console.log(typeof 123); // 输出 "number"
console.log(typeof true); // 输出 "boolean"
console.log(typeof {}); // 输出 "object"
console.log(typeof []); // 输出 "object"
console.log(typeof function() {}); // 输出 "function"
console.log([] instanceof Array); // 输出 true
console.log({} instanceof Object); // 输出 true
console.log(Object.prototype.toString.call("hello")); // 输出 "[object String]"
console.log(Object.prototype.toString.call([])); // 输出 "[object Array]"
关于 call、apply 和 bind 方法:
- 这三个方法都是用来改变函数的执行上下文(即
this的指向)。 call和apply方法都是立即执行函数,唯一的区别在于参数的传递方式不同:call方法接收参数列表,而apply方法接收一个参数数组。bind方法是创建一个新函数,并将原函数的执行上下文(this)绑定到指定对象,但不会立即执行。 bind方法创建一个新的函数,将原先函数的执行上下文绑定到指定对象当中不会立即执行
关于为什么不直接使用 toString 方法而是 Object.prototype.toString 方法:
-
在 JavaScript 中,每个对象都有一个
toString方法,用于返回对象的字符串表示形式。 -
但是,直接调用
toString方法可能会因为对象覆盖了该方法而返回意外的结果。 -
为了确保获取准确的对象类型,通常使用
Object.prototype.toString方法,该方法会返回一个表示对象类型的字符串,例如"[object Object]"、"[object Array]"等。
7、let、const、var,暂时性死区,先 console.log 输出变量再声明 和 如果先使用一个函数,再使用 var 声明,分别会报什么错误
在 JavaScript 中,如果先使用一个变量或函数而后再声明它,会导致不同的行为:
-
先使用再声明变量:
- 如果先使用一个变量而后再声明它,JavaScript 解释器会报错
ReferenceError: Cannot access 'variable' before initialization,因为在变量声明前尝试访问该变量会导致引用错误。
console.log(variable); // ReferenceError: Cannot access 'variable' before initialization var variable = "example"; - 如果先使用一个变量而后再声明它,JavaScript 解释器会报错
-
先使用再声明函数:
- 如果先调用一个函数而后再声明它,JavaScript 解释器不会报错,而是将函数声明提升到作用域顶部。这种现象被称为函数声明提升(Function Declaration Hoisting)。
functionExample(); // 函数调用不会报错 function functionExample() { console.log("Function Example"); }这是因为 JavaScript 在解释代码时会先将函数声明提升到作用域的顶部,所以在调用函数之前已经存在了函数的声明。但需要注意的是,对于函数表达式,不会发生声明提升。
总结:
-
对于变量,先使用再声明会报引用错误。
-
对于函数声明,先调用再声明不会报错,因为函数声明会被提升到作用域的顶部。
8、Promise 的方法、async await、Generator 函数,什么函数能被作为 Generator 函数
-
Promise的方法:
Promise.resolve(value): 返回一个解析过的Promise对象,可以是给定的值或者另一个Promise对象。Promise.reject(reason): 返回一个拒绝的Promise对象,带有一个指定的失败原因。Promise.all(iterable): 返回一个Promise对象,当所有给定的Promise都已经解决或者至少一个Promise被拒绝时,返回的Promise将被解决。Promise.race(iterable): 返回一个Promise对象,一旦迭代器中的其中一个Promise解决或拒绝,返回的Promise就会解决或拒绝。Promise.prototype.then(onFulfilled, onRejected): 添加解决和拒绝回调到Promise链中,返回一个新的Promise对象。Promise.prototype.catch(onRejected): 添加一个拒绝回调到Promise链中,返回一个新的Promise对象。
-
async/await:
async函数是用来定义一个返回Promise对象的异步函数。在 async 函数内部,可以使用await表达式来等待一个Promise对象的解决。await表达式会暂停 async 函数的执行,等待 Promise 对象的解决,然后恢复 async 函数的执行,并返回解决的值。
-
Generator函数:
- Generator函数是ES6引入的一种新的函数类型,通过
function*关键字定义。它可以通过yield语句来定义一个生成器对象,该对象可以被迭代器进行迭代。 - Generator函数内部可以使用
yield语句来产生值,函数的执行状态会被保存,直到下一次调用生成器对象的next()方法。
- Generator函数是ES6引入的一种新的函数类型,通过
-
什么函数能被作为Generator函数:
- 任何使用
function*关键字定义的函数都可以被视为 Generator 函数。Generator函数可以产生一个迭代器对象,该对象包含一个next()方法,用于依次获取函数内部yield语句产生的值。
- 任何使用
9、箭头函数与普通函数的区别,不能做构造函数,那说说使用new关键字的原理
箭头函数与普通函数的主要区别在于它们的语法形式和作用域绑定:
-
语法形式:
- 箭头函数使用箭头(
=>)来声明,通常采用匿名函数的形式。 - 普通函数使用关键字
function来声明,可以是匿名函数或具名函数。
- 箭头函数使用箭头(
-
this 的指向:
- 箭头函数的
this指向在定义时就已经确定,指向其父级作用域中的this。 - 普通函数的
this指向在运行时根据调用方式确定,可能会发生动态变化。
- 箭头函数的
-
不能用作构造函数:
- 箭头函数不能通过
new关键字来实例化,因为箭头函数没有自己的this,也没有prototype属性。 - 普通函数可以通过
new关键字来创建实例,通过prototype属性继承原型方法和属性。
- 箭头函数不能通过
关于 new 关键字的原理,当我们使用 new 关键字调用函数时,发生了以下几个步骤:
- 创建一个新的空对象。
- 将这个新对象的原型(
__proto__)指向构造函数的prototype属性。 - 将构造函数的
this指向这个新对象。 - 执行构造函数内部的代码,同时可以通过
this给新对象添加属性和方法。 - 如果构造函数没有显式返回一个对象,则返回这个新对象;否则,返回显式返回的对象。
因此,普通函数通过 new 关键字可以创建实例对象,而箭头函数由于缺少自己的 this 和 prototype,因此无法被 new 关键字调用。
10、React 生命周期函数
在React中,组件的生命周期函数主要包括以下阶段:
-
挂载阶段(Mounting):
constructor(): 在组件被创建时调用,用于初始化状态和绑定事件处理函数。static getDerivedStateFromProps(): 在组件接收到新的 props 时调用,在组件初始化和更新阶段都会被调用。render(): 根据组件的 props 和 state 来渲染组件的内容,必须返回一个React元素。componentDidMount(): 组件挂载后调用,可以执行DOM操作、网络请求等副作用。
-
更新阶段(Updating):
static getDerivedStateFromProps(): 同挂载阶段。shouldComponentUpdate(): 在组件接收到新的 props 或 state 时调用,用于控制是否重新渲染组件,默认返回true。render(): 同挂载阶段。getSnapshotBeforeUpdate(): 在最新的DOM渲染输出被提交到DOM树之前调用,可以用于保存当前DOM状态。componentDidUpdate(): 组件更新后调用,可以执行更新后的DOM操作或发起网络请求等副作用。
-
卸载阶段(Unmounting):
componentWillUnmount(): 组件即将被卸载和销毁时调用,用于清理定时器、取消订阅等操作。
-
错误处理阶段(Error Handling):
static getDerivedStateFromError(): 在子组件抛出错误后调用,用于渲染备用UI。componentDidCatch(): 在子组件抛出错误后调用,用于记录错误信息或发送错误报告。
这些生命周期函数使得我们可以在不同阶段执行适当的操作,从而控制组件的行为和状态,实现更丰富的交互和功能。需要注意的是,React 16.3之后推荐使用static getDerivedStateFromProps()和getSnapshotBeforeUpdate()等新的生命周期函数代替过时的生命周期函数,同时引入了React Hooks来管理组件的状态和副作用。
11、为什么要使用 hooks,除了复用一些数据状态的逻辑,还有其他原因码吗
使用Hooks的一个主要原因是它提供了一种更简洁、更灵活的方式来管理组件的状态和生命周期。除了可以复用数据状态的逻辑外,Hooks还具有以下几个重要优点:
-
更易于理解和维护: Hooks使得组件逻辑更加分离和清晰,使得组件的代码更易于理解和维护。每个状态和副作用都可以独立存在于自己的Hook函数中,不会像传统的类组件那样分散在多个生命周期方法中。
-
减少样板代码: 使用Hooks可以减少大量的样板代码,使得组件更加简洁。相比于类组件,Hooks不需要编写构造函数、bind方法和大量的生命周期方法,可以更专注于组件的核心逻辑。
-
更好的组件复用性: Hooks使得组件逻辑可以更轻松地提取和复用。通过将状态逻辑封装在自定义的Hook函数中,可以方便地在不同的组件之间共享状态逻辑,从而提高了组件的复用性。
-
更好的性能优化: Hooks的设计可以帮助React更好地优化组件的性能。由于Hooks可以在函数组件中直接使用,而不需要通过类组件的实例化和绑定,因此可以更容易地实现一些性能优化策略,比如更精细地控制组件的更新。
总的来说,Hooks是React提供的一种现代化的组件编写方式,它能够带来更好的代码组织、更清晰的逻辑分离、更高的组件复用性和更好的性能优化,是React开发中的一个重要利器。
12、代码:给一个数组的版本号排序
要对数组中的版本号进行排序,首先需要将版本号解析成可比较的格式,然后使用适当的排序方法进行排序。通常,版本号可以解析成数字数组,然后按照数字数组进行排序。以下是一个示例代码:
// 定义包含版本号的数组
let versions = ["1.3.2", "2.0", "1.5", "3.1.4", "1.0.0"];
// 定义解析版本号的函数
function parseVersion(version) {
return version.split(".").map(Number);
}
// 对版本号数组进行排序
versions.sort((a, b) => {
const versionA = parseVersion(a);
const versionB = parseVersion(b);
// 逐个比较版本号的每个部分
for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
const numA = versionA[i] || 0;
const numB = versionB[i] || 0;
if (numA !== numB) {
return numA - numB;
}
}
// 如果所有部分都相等,则按照版本号长度排序
return versionA.length - versionB.length;
});
// 输出排序后的版本号数组
console.log(versions);
这段代码首先定义了一个解析版本号的函数 parseVersion(),然后使用 sort() 方法对版本号数组进行排序。在排序过程中,首先将版本号解析成数字数组,然后逐个比较每个部分的大小,最终按照版本号的大小进行排序。排序后的版本号数组将按照从小到大的顺序排列。
12、反问
作者:起个响亮的名字___
链接:www.nowcoder.com/feed/main/d…
来源:牛客网