天天一道面试题

前言


为了巩固本身的知识和提高技术栈的广度以及深度,天天都会学习一道面试题(本文会持续更新)

如何获取数组中最大的数 (2020/11/27)

1.排序法react

const arr = [1, 2, 3, 4, 5, 6];
arr.sort((a, b) => {
  return b - a;
});
const max = arr[0];
console.log(max); // 输出最大值 6

2.假设法面试

const arr = [2, 1, 3, 5, 4, 6];
for (let i = 1; i < arr.length; i++) {
  max = arr[0];
  const cur = arr[i];
  cur > max ? (max = cur) : max;
}
console.log(max); // 输出最大值 6

3.内置 Max()方法算法

/**
 * 内置函数Math.max()支持传递多个参数,但不支持直接传递一个数组,因此须要借助apply()来传递一个数组。
 *
 * apply()与call()方法相似,区别在于apply()接受的是参数数组,call()接受的是参数列表。
 */
const arr = [1, 2, 3, 4, 5, 6];
const max = Math.max.apply(null, arr);
console.log(max); // 输出最大值 6

4.ES6 扩展运算符数据库

const arr = [1, 2, 3, 4, 5, 6];
console.log(Math.max(...arr)); // 输出最大值 6

什么是虚拟 DOM (2020/11/28)

DOM 树是对 HTML 的抽象,VDOM 就是对真实 DOM 树的抽象。VDOM 不会触及浏览器的部分,只是存在于 Javascript 空间的树形结构。编程

虚拟 DOM(VDOM)是真实 DOM 的内存表示,一种编程概念,一种模式。它会和真实的 DOM 同步,在更新 DOM 树时,虚拟 DOM 使用 diff 算法对比新旧 DOM 的变化,实现局部更新,节省了浏览器性能。跨域

DNS 如何进行解析 (2020/11/29)

  • DNS(Domain Name System): "域名系统"的英文缩写,是互联网上做为域名和 IP 地址相互映射的一个分布式数据库,它用于 TCP/IP 网络,它所提供的服务是用来将主机名和域名转换为 IP 地址的工做。数组

  • 域名解析: 经过域名,最终获得该域名对应的 IP 地址的过程就是域名解析。浏览器

DNS 实例解析:缓存

1.打开浏览器,输入一个域名(例如输入www.4399.com),发出一个 DNS 请求到本地 DNS 服务器(中国电信等网络链接服务商提供)。安全

2.本地 DNS 服务器查询 DNS 请求是否存在缓存记录,存在,返回结果;不存在,则本地 DNS 服务器向 DNS 根服务器(随机根服务器d.root.servers.net)发送查询请求。

3.DNS 根服务器(DNS 根服务器不记录存储具体的域名和 IP 的映射关系)返回域服务器地址

4.根据返回结果,本地 DNS 服务器向域服务器(返回对应域服务器地址c.gtld.servers.net)发送查询请求。

5.域服务器(域服务器不会直接返回域名与 IP 的映射关系)返回本域名的解析服务器地址

6.根据返回结果,本地 DNS 服务器向域名的解析服务器(例如: .4399.com域服务器)发送查询请求。

7.域名的解析服务器返回请求域名对应的 IP 地址(例如: 116.207.132.239)。

8.根据返回结果,本地 DNS 服务器向客户端返回具体 IP 地址,并将查询结果缓存在本地 DNS 服务器中,加速下次客户端的访问。

如何获取图片原始尺寸信息 (2020/11/30)

/**
 * naturalWidth && naturalHeight 不兼容IE6/7/8
 */
getImageOriginal = () => {
  let img = document.getElementById("bg-img");
  const width = img.naturalWidth;
  const height = img.naturalHeight;
};

React 类组件和函数组件的区别 (2020/12/01)

  • 类组件: 拥有更多的特性,拥有 state 状态和生命周期钩子。

  • 函数组件: 单纯接受 props 参数,是一个无状态组件。

随着 Hooks 的产生,函数组件也能够拥有自身的 state 状态。虽然 Hooks 解决了函数组件 state 的问题,使得代码更加简洁轻便,可是类组件仍是拥有着函数组件没有的其余特性。

什么是 JSX (2020/12/02)

下面例子的标签语法是 JSX 语法。

/**
 * JSX 是一个 Javascript 的语法扩展,既不是字符串也不是 HTML,具备 Javascript 的所有功能。
 *
 * JSX 语法中,能够在大括号中放置任何有效的 Javascript 表达式。
 *
 * JSX 也是一个表达式,能够赋值给变量、也能够做为参数传入函数。
 */
const element = <h1>Hello, World!</h1>;

React 中 state 和 props 有什么区别 (2020/12/03)

相同点:

React 组件的数据分为两种,props 和 state,两个数据的改变,均可能会引起组件从新渲染。
(props 和 state 能够保存信息,信息能够控制组件的渲染输出)

区别:

1.props 是组件的对外接口;state 是组件的内部状态。

2.props 是传递给组件的(相似于函数的形参);state 是在组件内被组件本身管理的(相似于在一个函数内声明的变量)。

3.props 是不可修改的,全部 React 组件都必须像纯函数同样保护它们的 props 不被修改;state 是多变的、能够修改的,每次 setState 都会异步更新。

何时应该选择 Class 实现一个组件,何时应该选择一个函数实现一个组件 (2020/12/04)

Class 类组件: 拥有自身 state 状态管理,拥有生命周期方法,继承 ReactComponent 实例化。

无状态的函数组件: 函数组件没有连接到 ReactComponent 实例的 this 属性和生命周期方法。

原则一: 若是你的组件须要访问 this 就用 Class 实现组件。

原则二: 若是你的组件须要生命周期方法,使用 Class 实现组件。

黄金原则: 若是你可使用无状态组件,那就使用函数实现一个组件。

总结:

  • 若是可使用无状态函数,就是尽管用函数。

  • 不然,就使用 Class 类。

setState 能够接受函数为参数吗? 有什么做用 (2020/12/05)

setState 函数的弊端: setState 不会马上改变(更新)React 组件中的 state 值(产生的效果不直观)。

做用: 函数式的 setState 能够解决 setState 存在的弊端,让 setState 函数产生的结果更直观有效。函数接收两个参数,第一个是当前的 state 值,第二个是当前的 props 值,函数应该返回一个对象(表明要对 this.setState 的更改)。

// 函数式 setState
class Counter extends React.Component {
  state = { count: 0 };
  handleIncrement = () => {
    this.setState((state, props) => {
      return {
        count: state.count + 1,
      };
    });
  };

  render() {
    const { count } = this.state;
    return (
      <div>
        <button onClick={this.handleIncrement}>+++</button>
        <span>{count}</span>
      </div>
    );
  }
}

描述一下 React 组件的各个生命周期函数 (2020/12/06)

React 组件的生命周期分为三个部分: 装载期(Mounting)更新期(Updating)卸载期(Unmounting)

1.装载期(组件第一次在 DOM 树中渲染的过程)

装载期调用函数顺序:

/**
 * constructor(创造一个组件的实例,调用对应的构造函数)
 *
 * getInitialState(初始化组件的内部状态this.state) && getDefaultProps(初始化外部接口props)
 *
 * componentWillMount(在render函数以前调用,能够在服务端调用、也能够在浏览器端调用)
 *
 * render(返回一个JSX描述结构的纯函数)
 *
 * componentDidMount(在render函数以后调用,函数调用时,render函数返回的结构已经渲染、组件已经"装载"到DOM树中;只能在浏览器端调用)
 */

2.更新期(组件被从新渲染的过程)

更新期调用函数顺序:

/**
 * componentWillReceiveProps(nextProps): 只要是父组件的render函数被调用,render函数里子组件就会更新,
 * 无论props变与不变,都会触发该函数。经过this.setState方法触发的更新过程不会调用这个函数。
 *
 * shouldComponentUpdate(nextProps, nextState): 决定一个组件何时不须要渲染。返回一个布尔值,true,render从新渲染;false,render不须要渲染。
 *
 * componentWillUpdate(在render函数以前调用,只有在浏览器端调用)
 *
 * render(渲染纯函数,决定了渲染什么)
 *
 * componentDidUpdate(prevProps, prevState): 在render函数以后调用,能够在服务端调用,也能够在浏览器端调用。
 */

3.卸载期(组件从 DOM 中删除的过程)

卸载期:

/**
 * componentWillUnmount(React组件要从DOM树中删除前,调用卸载函数): componentWillUnmount 中的工做与 componentDidMount相关联。
 *
 * componenWillUnmount能够清理React组件生产的内存垃圾,避免形成内存泄漏。
 */

什么是 shouldComponentUpdate 函数? 有什么做用 (2020/12/07)

shouldComponentUpdate 函数是 React 组件生命周期中更新期的一个具备高性能、决定性的函数。在更新过程当中,React 组件首先调用 shouldComponentUpdate 函数,若是函数返回 true,就继续更新过程(render 函数);返回 false,就马上终止更新过程,不会触发后续更新渲染。

做用:

1.shouldComponentUpdate 函数返回一个布尔值,告知 React 组件在更新过程当中是否要继续更新。

2.shouldComponentUpdate 函数使用恰当,能够大大提升 React 组件的性能。

当组件的 setState 函数被调用以后,会发生什么 (2020/12/08)

setState 函数调用后触发组件更新,页面从新绘制。根据生命周期中的更新期,setState 函数不会调用 componentWillReceiveProps 函数,可是其他的更新函数调用不变。

/**
 * shouldComponentUpdate(当shouldComponentUpdate函数被调用的时候,this.state没有获得更新)
 *
 * componentWillUpdate(当componentWillUpdate函数被调用的时候,this.state依然没有获得更新)
 *
 * render(直到render函数被调用的时候,this.state才获得更新)
 *
 * componentDidUpdate()
 */

什么是 Fiber? 是为了解决什么问题 (2020/12/09)

Fiber 是更新过程碎片化的数据结构(每执行完一段更新过程,就把控制权交还React负责任务协调的模块,比对是否有新的紧急的任务须要更新,有,则优先更新紧急任务;无,则回到节点继续更新剩余任务)。

解决问题:

在 16.0 版本以前的 React 中,更新过程是同步的一层组件套一层组件,逐渐深刻的过程,在更新完全部组件以前不会中止,调用时长长。而 Javascript 具备单线程的特色,每一个同步任务时长不能太长,时长过长会对其余的输入的响应削弱甚至无响应,React Fiber 就是为了解决同步操做时长过长致使的性能问题。

什么是 HoC(Higher-Order Component)? 适用于什么场景 (2020/12/10)

HOC 高阶组件: 接受一个组件做为输入,返回一个新组件做为结果的函数。

import React from 'react';

function wrapperComponent(wrappedComponent) {
  return class WrappingComponent extends React.Component {
    render() {
      const {id, ...props} = this.props;
      return <WrappedComponent {...props}>
    }
  }
}

export default wrapperComponent;

使用场景:

1.重用代码: 有时一个功能逻辑会在多处 React 组件中使用,利用高阶组件的方式把这部分公用逻辑提取出来,就能够减小组件代码的重复使用率。

2.修改现有 React 组件的行为: 对于一些高度封装的 React 组件(第三方组件或团队内本身封装好的组件),对这一类 React 组件进行二次开发时,不想改动封装组件内部逻辑,利用高阶组件的方式就能够基于原有的组件函数产生新的组件,这样就不会对原有的组件产生任何改动,保证项目代码运行正常。

为何咱们利用循环产生的组件中要用上 key 这个特殊的 prop (2020/12/11)

在 React 组件中,循环渲染的组件须要加上 key 属性,没有 key 时,React 会发出警告(a key should be provided for list items),告知咱们组件必需要有 key 属性。

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((item, index) => {
    return <li key={item.toString()}>{item}</li>;
  });

  return (
    <div>
      <ul>{listItems}</ul>
    </div>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById("root")
);

key 的做用: key 属性帮助 React 识别元素,肯定元素的增删查改;在循环渲染的组件中,能够根据特定的 key 值,对相应的组件作特别的操做处理等。

let 与 const 有什么区别 (2020/12/12)

类似:

  • 都是只在声明所在的块级做用域内有效。
  • 都不能在所在做用域内有相同名称的变量和函数。

区别:

  • const 声明的变量(常量)必须初始化;let 声明的变量不用初始化。
  • const 声明的变量(常量)不能够赋值改变;let 声明的变量能够改变,值和类型均可以改变,没有限制。

什么是 React Hooks? (2020/12/13)

Hooks 是 React 16.8 中添加的一个全新的 API,它可让你在不编写 class 的状况下使用 state 以及其余的 React 特性。React Hooks 的意思是,组件尽可能写成纯函数,若是须要外部功能和反作用,就用钩子把外部的代码"钩"进来。React Hooks 就是那些钩子,你须要什么功能,就是用什么钩子。React 默认提供了一些经常使用的钩子,或者也可使用封装属于本身的钩子。全部的钩子都是为函数引入外部功能,因此 React 约定,钩子一概使用use前缀命名。

React Hooks 使用规则是什么? (2020/12/14)

Hooks 就是 Javascript 函数,可是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hooks。不要再循环、条件判断或者子函数中调用。

  • 只能在React 的函数组件中调用 Hooks。不要在其余 Javascript 函数中调用。

简述 Flux 思想 (2020/12/15)

一个 Flux 包含四个部分:

  • Dispatcher: 处理动做分发,维持 Store 之间的依赖关系。

  • Store: 负责存储数据和处理数据相关逻辑。

  • Action: 驱动 Dispatcher 的 Javascript 对象。

  • View: 视图部分,负责显示用户界面。

Flux 的好处,最重要的就是"单向数据流"的管理方式。在 Flux 的理念中,若是要改变界面,必须改变 store 中的状态;若是要改变 store 中的状态,必须派发一个 action 对象。

Flux 流程:

1.用户访问 View

2.View 发出用户指定的 Action。

3.Dispatcher 收到 Action,要求 Store 进行相应的更新。

4.Store 更新后,发出一个"change"事件。

5.View 收到"change"事件后,更新页面。

options 请求方法有什么用 (2020/12/16)

options 请求方法的主要用途有两个:

1.获取服务器支持的 HTTP 请求方法。

2.用来检查服务器的性能(形如: AJAX进行跨域请求时的预检,须要向另一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全)。

简述 https 原理,以及与 http 的区别 (2020/12/17)

HTTPS 原理:

1.客户端(Client)发起一个 HTTPS 的请求。

2.服务端(Server)把事先配置好的公钥证书返回给客户端。

3.客户端验证公钥证书有效性,验证经过则继续;不经过则显示警告信息。

4.客户端使用伪随机数生成器生成加密所使用的对称密钥,而后使用证书的公钥加密这个对称密钥,发送给服务端。

5.服务端使用本身的私钥解密这个消息,得到密钥。

6.服务端使用得到的对称密钥加密"明文内容 A",发送给客户端。

7.客户端使用对称密钥解密响应的密文,获得"明文内容 A"。

8.客户端再次发起 HTTPS 请求,使用对称密钥加密请求的"明文内容 B"。

9.服务端使用以前得到的对称密钥解密密文,获得"明文内容 B"。

区别:

一、https 协议须要到 ca 申请证书,通常免费证书较少,于是须要必定费用。

二、http 是超文本传输协议,信息是明文传输,https 则是具备安全性的 ssl 加密传输协议。

三、http 和 https 使用的是彻底不一样的链接方式,用的端口也不同,前者是 80,后者是 443。

四、http 的链接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 http 协议安全。

实现数组扁平化 (2020/12/18)

1.flat() 方法

const arr = [[1, 2], [3, 4], 5, 6];
console.log(arr.flat()); // 输出: [1,2,3,4,5,6]

2.reduce() 与 concat() 方法

const arr = [[1, 2], [3, 4], 5, 6];
console.log(arr.reduce((acc, val) => acc.concat(val), [])); // 输出: [1,2,3,4,5,6]

3.扩展运算符

const arr = [[1, 2], [3, 4], 5, 6];
console.log([].concat(...arr)); // 输出: [1,2,3,4,5,6]

4.正则式

const arr = [[1, 2], [3, 4], 5, 6];
const results = JSON.parse(
  "[" + JSON.stringify(arr).replace(/\[|\]/g, "") + "]"
);
console.log(results); // 输出: [1,2,3,4,5,6]

实现数组去重 (2020/12/19)

1.ES6 Set() 方法

const arr = [1, 3, 2, 4, 3, 1, 5, 2];
console.log([...new Set(arr)]); // 输出: [1,3,2,4,5]

2.两层 for 循环 + splice()

const arr = [1, 3, 2, 4, 3, 1, 5, 2];
function unique(arr) {
  let length = arr.length;
  for (let i = 0; i < length; i++) {
    for (let j = i + 1; j < length; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1);
        length--;
        j--;
      }
    }
  }
  return arr;
}
const results = unique(arr);
console.log(results); // 输出: [1,3,2,4,5]

3.indexOf() 方法

const arr = [1, 3, 2, 4, 3, 1, 5, 2];
const unique = (arr) => {
  let results = [];
  for (let i = 0; i < arr.length; i++) {
    if (results.indexOf(arr[i]) === -1) {
      results.push(arr[i]);
    }
  }
  return results;
};
console.log(unique(arr)); // 输出: [1,3,2,4,5]

4.includes() 方法

const arr = [1, 3, 2, 4, 3, 1, 5, 2];
const unique = (arr) => {
  let results = [];
  for (let i = 0; i < arr.length; i++) {
    if (!results.includes(arr[i])) {
      results.push(arr[i]);
    }
  }
  return results;
};
console.log(unique(arr)); // 输出: [1,3,2,4,5]

你知道那些 http 头部 (2020/12/20)

HTTP 头域包括通用头、请求头、响应头和实体头。每一个头域由域名、冒号、域值组成。

1.通用头部是客户端和服务端均可以使用的头部,能够在客户端、服务端和其余应用程序之间提供一些很是有用的通用功能,如 Date 头部。

2.请求头部是请求报文特有的,它们为服务器提供了一些额外信息,好比客户端但愿接收什么类型的数据,如 Accept 头部。

3.响应头部便于客户端提供信息,好比,客服端在与哪一种类型的服务器进行交互,如 Server 头部。

4.实体头部指的是用于应对实体主体部分的头部,好比,能够用实体头部来讲明实体主体部分的数据类型,如 Content-Type 头部。

实现深浅拷贝 (2020/12/21)

1.浅拷贝: 若是数组元素是基本类型,拷贝一份,互不影响;而若是数组元素是对象或者数组,就会拷贝对象和数组的引用。这样原数组(对象)和新数组(对象)都会改变的复制引用拷贝方法称为浅拷贝。数组的concat()slice()方法就是一种浅拷贝。

const arr = [1, 2, { name: "tom" }];
const newArr = arr.concat();
arr[2].name = "jerry";
console.log(arr); // 输出 [1,2,{name:'jerry'}]
console.log(newArr); // 输出 [1,2,{name:'jerry'}]

实现浅拷贝:

function shallowCopy(obj) {
  if (typeof obj != "object") return; // 判断传入的参数,确保拷贝的只有对象
  let newObj = obj instanceof Array ? [] : {}; // 判断参数obj类型,新建数组或者对象
  // 遍历obj,判断是obj的属性才拷贝
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

2.深拷贝: 彻底的拷贝一个对象和数组,原数组(对象)和新数组(对象)二者相互分离,二者之间的修改彻底独立且不会相互影响,这样的复制引用拷贝方法称为深拷贝。JSON.stringify()方法就是一种深拷贝。

const arr = [1, 2, { name: "tom" }];
const newArr = JSON.parse(JSON.stringify(arr));
arr[2].name = "jerry";
console.log(arr); // 输出 [1,2,{name:'jerry'}]
console.log(newArr); // 输出 [1,2,{name:'tom'}]

实现深拷贝:

function deepCopy(obj) {
  if (typeof obj != "object") return;
  let newObj = obj instanceof Array ? [] : {};
  // 判断属性值的类型,若是是对象,递归调用深拷贝函数
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] =
        typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}

实现函数柯里化 (2020/12/22)

柯里化: 一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术(将一个接受多个参数的函数变为接受一个参数返回一个函数的固定形式)。

实现柯里化:

function curry() {
  const _args = [...arguments];
  function fn() {
    _args.push(...arguments);
    return fn;
  }
  fn.toString = function () {
    return _args.reduce((sum, cur) => sum + cur);
  };
  return fn;
}

实现判断一个类型的方法,能够区分 Null 与 Object (2020/12/23)

typeof 是一元操做符,能够对数据类型进行判断,返回值是表示操做数类型的一个字符串。可是 Javascript 的数据类型中,Null 和 Object 的 typeof 都返回 object字符串,难以区分二者数据类型;为了更好的去区分二者之间的关系,可使用 Object.prototype.toString 来检验二者的区分。

var class2type = {};

// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error Null Undefined"
  .split(" ")
  .map(function (item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
  });

function type(obj) {
  // 兼容IE6
  if (obj === null) {
    return obj + "";
  }
  // 基本类型使用typeof,引用类型使用Object.prototype.toString
  return typeof obj === "object" || obj === "function"
    ? class2type[Object.prototype.toString.call(obj)] || "object"
    : typeof obj;
}

实现防抖节流 (2020/12/24)

防抖: 触发高频时间后 N 秒内函数只会执行一次,若是 N 秒内高频时间再次触发,则从新计算时间。防抖经常使用于用户进行搜索输入节约请求资源......

const debounce = (fn, time) => {
  let timeout = null;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  };
};

节流: 高频时间触发,但 N 秒内只会执行一次,因此节流会稀释函数的执行频率。节流经常使用于鼠标不断点击触发、监听滚动事件......

const throttle = (fn, time) => {
  let flag = true;
  return function () {
    if (!flag) {
      return;
    }
    flag = false;
    setTimeout(() => {
      fn.apply(this, time);
      flag = true;
    }, time);
  };
};

检查重复字符串 (2020/12/25)

1.方法一: 正则式判断

/**
 * 1.利用()进行分组。
 *
 * 2.利用/加数字表示引用,例如: /1就是引用第一个分组。
 *
 * 思路: 将[a-zA-Z]作分组,引用分组进行判断是否有连续重复。
 */
const str = "hello";
const str1 = "tom";
function isRepeatStr(str) {
  return /([a-zA-Z])\1/.test(str);
}
const res = isRepeatStr(str);
const res1 = isRepeatStr(str1);
console.log(res); // 输出 true
console.log(res1); // 输出 false

2.方法二: 字符串

/**
 * charAt(): 从一个字符串中返回指定的字符。
 */
const str = "hello";
const str1 = "tom";
function isRepeatStr(str) {
  let reg = /[a-zA-Z]/;
  for (let i = 0; i < str.length; i++) {
    if (str.charAt(i) == str.charAt(i + 1) && reg.test(str[i])) {
      return true;
    }
  }
  return false;
}
const res = isRepeatStr(str);
const res1 = isRepeatStr(str1);
console.log(res); // 输出 true
console.log(res1); // 输出 false

call()、apply()、bind()的区别 (2020/12/26)

1.call() 和 apply() 改变了函数的 this 上下文后便执行该函数,bind() 则是返回改变了上下文后的一个函数。

2.call() 和 apply() 的第一个参数都是要改变上下文的对象,call() 第二个参数以参数列表的形式展示;apply() 第二个参数则是以参数数组的形式展示。

/**
 * call()语法:
 * fun.call(thisArg, arg1, arg2,......)
 * thisArg: 函数运行时指向的this值。
 * arg1,arg2......: 绑定函数调用时传入的参数列表。
 */

/**
 * apply()语法:
 * apply(thisArg, [argsArray])
 * thisArg: 函数运行时指向的this值。
 * [argsArray]: 绑定函数调用时传入的参数数组。
 */

/**
 * bind()语法:
 * bind(thisArg[, arg1[, arg2[, ......]]])
 * thisArg: 函数运行时原函数指向的this值。
 * [, arg1[, arg2[, ......]]]: 绑定函数调用时传入的参数。
 */

区别总结: 函数须要改变 this 指向时使用 call()、apply()、bind()。

  • 传递参数很少,使用 call(thisArg, ...args)
  • 传递参数较多,使用 apply(thisArg, [...args])
  • 生成一个新函数长期绑定某个函数的某个对象使用,使用 bind(thisArg, ...args)

实现 add(1)(2)(3) (2020/12/27)

function add(...args) {
  return args.reduce((a, b) => a + b);
}

function currying(fn) {
  let args = [];
  return function temp(...newArgs) {
    if (newArgs.length) {
      args = [...args, ...newArgs];
      return temp;
    } else {
      let value = fn.apply(this, args);
      args = [];
      return value;
    }
  };
}

let addCurry = currying(add);
console.log(addCurry(1)(2)(3)()); // 输出 6

HTTP 状态码有哪些,分别表明什么意思? (2020/12/28)

HTTP 状态码:

1xx:指示信息类,表示请求已接受,继续处理。

2xx:指示成功类,表示请求已成功接受。

3xx:指示重定向,表示要完成请求必须进行更近一步的操做。

4xx:指示客户端错误,请求有语法错误或请求没法实现。

5xx:指示服务器错误,服务器未能实现合法的请求。

常见的状态码:

200 OK:客户端请求成功

206 Partial Content:客户发送了一个带有Range头的GET请求,服务器完成了它(当时音频或视频文件很大时返回206)

301 Moved Permanently:所请求的页面已经转移至新的URL

302 Found:所请求的页面已经临时转移至新的URL

304 Not Modified:客户端有缓冲的文档并发出看一个条件性的请求,服务器告诉客户,原来缓冲的文档还能够继续使用

403 Forbidden:对请求页面的访问被禁止

404 Not Found:请求资源不存在

500 Internal Server Error:服务器发生不可预期的错误原来缓冲的文档还能够继续使用

503 Server Unavailable:请求未完成,服务器临时过载或宕机,一段时间后可恢复正常

浏览器输入 url 后发生了什么? (2020/12/29)

/**
 * 大体流程:
 *
 * 1.url解析: 浏览器输入url,判断输入的url是不是一个合法的url;同时检查浏览器是否存在相对应的缓存,存在,返回缓存并渲染页面;不存在,则发送DNS请求。
 *
 * 2.DNS域名解析: 浏览器向DNS服务器请求解析输入url对应的IP地址,返回解析的IP地址给客户端。
 *
 * 3.创建TCP链接: 接收解析好的IP地址,根据IP地址和默认端口80,和服务器创建TCP链接。
 *
 * 4.发送HTTP请求: 浏览器发出读取文件的HTTP请求。
 *
 * 5.服务器处理请求: 服务器对浏览器HTTP请求作出响应,返回相对应的HTML文本给浏览器。
 *
 * 6.关闭TCP链接: 释放关闭TCP链接。
 *
 * 7.浏览器解析HTML,渲染页面: 浏览器接收服务器返回的HTML文本,解析HTML文本内容渲染页面。
 */

判断数组的几种方法 (2020/12/30)

数组判断方法:

1.Array.isArray()

const arr = [1, 2, 3];
const arr1 = "tom";
console.log(Array.isArray(arr)); // 输出 true
console.log(Array.isArray(arr1)); // 输出 false

2.obj instanceof Array

const arr = [1, 2, 3];
const arr1 = "tom";
console.log(arr instanceof Array); // 输出 true
console.log(arr1 instanceof Array); // 输出 false

3.obj.constructor === Array

const arr = [1, 2, 3];
const arr1 = "tom";
console.log(arr.constructor === Array); // 输出 true
console.log(arr1.constructor === Array); // 输出 false

4.Object.prototype.toString

const arr = [1, 2, 3];
const arr1 = "tom";
console.log(Object.prototype.toString.call(arr) === "[object Array]"); // 输出 true
console.log(Object.prototype.toString.call(arr1) === "[object Array]"); // 输出 false
相关文章
相关标签/搜索