前端面试题(三)

581 阅读13分钟

1、flex布局 容器属性

  1. flex-direction属性决定主轴的方向(即项目的排列方向)。
  • flex-direction: row | row-reverse | column | column-reverse;
  1. flex-wrap属性定义轴线,如果一条轴线排不下,如何换行。
  • flex-wrap: nowrap | wrap | wrap-reverse;
  • nowrap(默认):不换行 | wrap:换行,第一行在上方。 |wrap-reverse:换行,第一行在下方。
  1. flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
  • flex-flow: || ;
  1. justify-content属性定义了项目在主轴上的对齐方式。
  • justify-content: flex-start | flex-end | center | space-between | space-around;
  1. align-items属性定义项目在交叉轴上如何对齐。
  • align-items: flex-start | flex-end | center | baseline | stretch;
  1. align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
  • align-content: flex-start | flex-end | center | space-between | space-around | stretch;

2、flex子容器常见属性

  • Order: 属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
  • flex-grow: 属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
  • flex-shrink: 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
  • flex-basis: 属性定义了在分配多余空间之前,项目占据的主轴空间。浏览器根据这个属性计算主轴是否有多余空间。默认值为auto,即项目的本来大小。
  • flex: 属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
  • align-self: 属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

3、js的数据类型及数据类型的判断

  1. 原始数据类型
  • Undefined:表示一个变量被声明了但没有被赋值。其值只有一个,即 undefined。
  • Null:表示一个空值。其值只有一个,即 null。null 通常用于表示一个空的对象引用。
  • Boolean:表示逻辑值,有两个值:true 和 false。
  • Number:表示数值。JavaScript 中的数值可以是整数或浮点数,还可以使用科学记数法。
  • String:表示文本数据。
  • Symbol(ES6 新增):表示独一无二的值。
  • BigInt(ES2020 新增):用于表示大于 2^53 - 1 的整数。
  1. 对象数据类型
  • Object:是 JavaScript 中所有对象的基类。
  • Array:表示数组,是特殊的对象。
  • Function:表示函数,是特殊的对象。
  • Date:表示日期和时间。
  • RegExp:表示正则表达式。
  • 其他内置对象,如 Math、Global(在浏览器环境中为 window)等。
  • 自定义对象:用户通过 {} 或 new Object() 创建的对象。
  1. 判断数据类型:
  • typeof 操作符:用于判断基本数据类型,但对于对象类型,除了 function 类型返回 "function" 外,其余对象类型(包括数组和null)都返回 "object"
console.log(typeof 1); // "number"  
  • instanceof 操作符:用于判断某个变量是否属于某个对象的实例。对于自定义对象、数组、内置对象等很有用。
console.log({} instanceof Object); // true  
  • Object.prototype.toString.call() 方法:这是最准确判断数据类型的方法。通过调用 Object.prototype 上的 toString 方法,并传入要检测的变量作为参数,可以返回表示该变量类型的字符串
console.log(Object.prototype.toString.call(function(){})); // "[object Function]"

4、数组哪些方法可以改变原数组

  1. 改变原数组的: push() 向数组的末尾添加一个或多个元素,并返回新的数组 pop() 删除并返回数组的最后一个元素。 shift() 删除并返回数组的第一个元素。 unshift() 向数组的开头添加一个或多个元素,并返回新的数组。 sort() 对数组的元素进行排序,并返回数组 reverse() 反转数组的元素顺序,并返回数组 fill() 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引 copyWithin() 在当前数组内部,将指定位置的成员复制到其他位置,然后返回当前数组。

  2. 不改变原数组的:

5、splice方法有几个参数

splice() 方法最少需要一个参数(start),最多可以有三个参数(start, deleteCount, 以及要添加的一个或多个元素)

let myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

// 从索引 2 的位置开始删除 0 个元素,然后添加 'drum'
let removed = myFish.splice(2, 0, 'drum');
// 此时 myFish 变为 ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']
// removed 是一个空数组,因为没有元素被删除

// 从索引 3 的位置开始删除 1 个元素
removed = myFish.splice(3, 1);
// 此时 myFish 变为 ['angel', 'clown', 'drum', 'sturgeon']
// removed 是被删除的元素的数组:['mandarin']

// 从索引 3 的位置开始删除 1 个元素
removed = myFish.splice(1);
// 此时 myFish 变为 ['clown', 'drum', 'sturgeon']

6、js中new一个实例对象经历了哪些步骤

使用new关键字创建实例对象的过程可以概括为:创建一个新对象,设置其原型链,将构造函数的作用域绑定到新对象,执行构造函数中的代码,最后返回新对象(除非构造函数显式地返回了另一个对象)。 这个过程确保了新创建的对象既能够访问到构造函数原型上的属性和方法,又能够在构造函数内部通过this添加自己的属性和方法。

7、原型和原型链

原型(Prototype) 是面向对象编程中继承的基础 简单来说,原型就是一个对象,它包含了可以被其他对象共享的属性和方法。 JavaScript中的每个函数都有一个特殊的属性prototype,这个属性指向了一个对象,即原型对象。而每个实例对象内部都有一个指向其构造函数的原型对象的链接。这个链接在ES5之前通常通过__proto__属性来访问,在ES6及之后的规范中,建议使用Object.getPrototypeOf()方法来获取对象的原型。 原型链(Prototype Chain) 原型链(Prototype Chain)是由一系列原型对象通过__proto__(或内部[[Prototype]]链接)连接而成的链表。当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎就会沿着原型链向上查找,直到找到该属性或方法或原型链的终点为止。

function Person(name) { this.name = name; }
Person.prototype.sayHello = function() { console.log('Hello, my name is ' + this.name); };

var person1 = new Person('Alice');
var person2 = new Person('Bob');
person1.sayHello(); // 输出: Hello, my name is Alice
person2.sayHello(); // 输出: Hello, my name is Bob

console.log(person1.proto === Person.prototype); // true,在ES5之前
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true,推荐使用的方式 console.log(Person.prototype.proto === Object.prototype); // true(在某些环境中)

Object.prototype 是JavaScript中所有普通对象的最终原型(即原型链的顶端),它定义了所有对象共享的默认方法和属性,如 toString()、valueOf() 和 constructor 等。查看 Person.prototype 的 proto 时,会看到它指向 Object.prototype,这表明 Person.prototype 继承了 Object.prototype 上的所有方法和属性。

8、React15 到react16有什么明显更新

  • React 15的主要特点
    1. createClass 方法:在React 15中,可以使用React.createClass方法来创建组件类,但这个方法在后续版本中被弃用。
    2. PropTypes:React 15引入了PropTypes,用于验证组件接收的props类型和必需性,有助于在开发过程中发现潜在的错误。
    3. 生命周期方法:React 15支持一系列的生命周期方法,如componentWillMount、componentWillReceiveProps和componentWillUpdate等,这些方法在组件的不同阶段被调用,允许开发者在这些阶段执行特定的逻辑。
  • React 16的主要更新
    1. Hooks:React 16引入了Hooks,这是React 16.8版本中的重大更新。Hooks让函数式组件有了和类组件一样的状态和其他React特性,无需编写类。Hooks的引入极大地提高了代码的可复用性和组织性。
    2. Fiber架构:React 16通过引入Fiber架构对核心算法进行了重写。Fiber架构改进了React的调度能力和性能,使得React能够更好地处理大规模和复杂的应用程序。Fiber架构使得任务的执行可以被中断和恢复,从而提高了应用的响应性和性能。

9、setstate是同步还是异步

大多数使用场景和React的设计意图来看,setState在大部分场景下表现为 异步 ,这种设计是为了提高性能和优化页面渲染速度。但是setState的行为并非简单地分为同步或异步,而是依赖于其调用时的上下文和环境 异步场景 1. 合成事件处理器中:在React封装的合成事件(如onClick、onChange等)处理器中调用setState时,React会将这些更新请求放入一个队列中,并在事件处理完成后(即当前事件处理函数的执行栈清空后)进行批量处理。这样做是为了提高性能,避免过多的DOM重绘和重排。 2. 生命周期钩子函数中:在React的生命周期钩子函数(如componentDidMount、shouldComponentUpdate等,但请注意componentDidUpdate是更新后的钩子,其中的setState可能再次触发更新,但其本身的调用依然是基于之前的状态)中调用setState时,也通常是异步的。需要注意的是,在componentWillUnmount中调用setState是不被推荐的,因为它可能会导致内存泄漏或不必要的渲染 同步场景 1. 连续调用:在同一个事件处理函数或生命周期钩子中连续调用setState时,这些调用看似是同步的,因为它们被加入到同一个更新队列中,并在下一次渲染前一起被处理。然而,这并不意味着setState本身是同步的,而是React的批处理机制导致的。 2. 原生事件和异步代码中:在某些情况下,如在原生事件处理器(如通过addEventListener添加的事件)或异步代码(如setTimeout、Promise的.then()方法)中调用setState时,它可能是同步的。这是因为在这些场景中,React的批处理机制可能没有被激活,因此setState会立即触发更新。但是,这并不构成setState通常情况下的行为,且这种做法应该谨慎使用,因为它可能破坏React的更新策略和性能优化。

10、React 合成事件

  1. 定义: React合成事件(SyntheticEvent)是React模拟原生DOM事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。
  2. 常见的React合成事件: 鼠标事件:如onClick、onMouseOver、onMouseOut等,用于处理鼠标的点击、悬停、移出等动作。 键盘事件:如onKeyDown、onKeyPress、onKeyUp等,用于处理键盘的按键动作。 表单事件:如onChange、onSubmit、onFocus、onBlur等,用于处理表单元素的变化、提交、聚焦、失焦等动作。 触摸事件:如onTouchStart、onTouchMove、onTouchEnd等,用于处理触摸屏设备的触摸动作。 剪贴板事件:如onCopy、onCut、onPaste等,用于处理剪贴板相关的操作。
  3. 特性:
    1. 跨浏览器兼容性:React的合成事件可以屏蔽浏览器的差异,保证在各种浏览器上运行一致。
    2. 性能优化:React的合成事件可以对事件进行池化处理,重用事件对象,避免创建大量的事件对象,从而提高性能。
    3. 事件委托:React的合成事件实现了事件委托机制,将事件处理程序绑定在组件树的根节点上,统一管理和处理组件内部和外部的事件,从而避免多次绑定事件处理程序的问题。
    4. 支持自定义事件:React的合成事件可以支持自定义事件,开发者可以自定义组件事件,提供更多的自定义能力。
    5. 统一的接口:React为各种事件提供了统一的接口,使得开发者可以更方便地处理和管理事件。

11、react合成事件是如何绑定的

React合成事件的绑定是通过React的事件系统来完成的,这个过程在React的渲染过程中自动进行,无需开发者手动操作。React的合成事件系统是建立在React的虚拟DOM之上的,它通过事件委托(Event Delegation)的方式来实现事件的绑定和触发。

  • 以下是React合成事件绑定的大致过程:

    1. 事件注册: 当React组件被渲染到DOM中时,React会遍历其虚拟DOM树,并识别出哪些元素需要绑定事件处理器(如onClick、onMouseMove等)。 对于需要绑定事件的元素,React会在其内部维护一个事件监听器的映射表(或类似的数据结构),将事件名称和对应的事件处理函数关联起来。
    2. 事件委托: React不会为每个需要绑定事件的元素都单独绑定一个事件监听器。相反,它会将所有事件监听器都绑定在根节点(或靠近根节点的某个节点)上,这就是事件委托。 当事件发生时,事件会冒泡到根节点(或委托节点),React的事件系统会在冒泡过程中捕获这些事件,并根据之前建立的映射表找到对应的事件处理函数。
    3. 事件合成: 在事件处理函数被调用之前,React会创建一个合成事件对象(SyntheticEvent),这个对象是对浏览器原生事件对象的封装,提供了跨浏览器的一致接口。 合成事件对象包含了事件的所有相关信息(如事件类型、目标元素、事件发生的时间等),并且提供了一些额外的功能(如preventDefault()、stopPropagation()等)。
    4. 事件处理: 一旦找到了对应的事件处理函数,React就会调用这个函数,并将合成事件对象作为参数传递给它。 开发者在事件处理函数中可以根据需要处理事件,并可以访问合成事件对象来获取事件的相关信息。
    5. 事件清理: 当组件被卸载或事件监听器需要被移除时,React会自动清理与之相关的事件监听器,以防止内存泄漏。
  • 注意: 虽然React的合成事件系统对开发者来说是透明的,但开发者仍然需要遵守React的事件处理规范。例如,在事件处理函数中,如果需要阻止事件的默认行为或冒泡,应该使用合成事件对象提供的preventDefault()和stopPropagation()方法,而不是直接使用原生事件对象的相应方法。

  • 此外: React还提供了useEvent Hook,它允许开发者在函数组件中创建并引用一个事件处理函数,这有助于避免在组件的每次渲染中都重新创建事件处理函数,从而提高性能。然而,useEvent Hook本身并不直接涉及事件的绑定过程,它更多地是与事件处理函数的稳定性和性能优化相关。