web前端面试题

1.数据结构和算法

1)反转单词

export default (str) => {
  // 字符串按空格进行分隔,保存数组,数组的元素的先后顺序就是单词的顺序
  let arr = str.split(' ')
  // 对数组进行遍历,然后每个元素进行反转
  let result = arr.map(item => {
    return item.split('').reverse().join('')
  })
  return result.join(' ')
}

2)冒泡排序

export default arr => {
  // 冒泡排序
  // 为什么 i = arr.lentgh - 1 因为j<i,假如i = len; 而下面又有j<i。会出现报错  
  for (let i = arr.length - 1, tmp; i > 0; i--) {
 
    // 下面的for循环其实就是把最大的值一直往下放
    // 1.tmp就是当前所认为最大的值
    // 2.假如tmp比下一个还要大,那么交换
    for (let j = 0; j < i; j++) {
      tmp = arr[j];
      if (tmp > arr[j + 1]) {
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
  }
  return arr;
};
 
import sort from '../../code/sort/lesson1-1';
 
test('冒泡排序', () => {
  expect(sort([1, 9, 5, 3, 4])).toEqual([1, 3, 4, 5, 9]);
});

 3)选择排序

export default arr => {
  // 选择排序
  for (let i = 0, len = arr.length, min; i < len; i++) { // 此处从0开始一个个比较
    min = arr[i] // 最小值的初始值设为当前遍历到的这个值
 
    // 下面整个for循环其实无非是从i的第二个开始遍历
    // 1.如果发现该数比min小,那么min变成该数,该数变成min
    // 2.遍历完成之后,i值就是最小的那个
    // 总结: 进行上面的遍历之后,就可以找到i往后最小的值,这也就是选择排序的中心思想
    for (let j = i + 1; j < len; j++) {
      if (arr[j] < min) {
        let c = min
        min = arr[j]
        arr[j] = c
      }
    }
    arr[i] = min
  }
 
  return arr
}

4)快速排序

export default (arr) => {
  let quickSort = (arr) => {
    let len = arr.length
    if (len < 2) {
      return arr
    } else {
      // 选标尺元素
      let flag = arr[0]
      let left = []
      let right = []
      // 把剩余的元素遍历下,比标尺元素小的放左边,大的放右边
      for (let i = 1, tmp; i < len; i++) {
        tmp = arr[i]
        if (tmp < flag) {
          left.push(tmp)
        } else {
          right.push(tmp)
        }
      }
      // 进行递归操作
      return quickSort(left).concat(flag, quickSort(right))
    }
  }
  return quickSort(arr)
}

5)时间复杂度

找时间复杂度的技巧

 a.找出算法中的基本语句(算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体)

b.计算基本语句的执行次数的数量级(只要保证基本语句执行次数的函数中的最高次幂正确即可)

举例

a.一个简单语句的时间复杂度为O(1)。int count = 0;

b.100个简单语句的时间复杂度也为O(1)。(100是常数,不是趋于无穷大的n)。int count = 0;

c.一个循环的时间复杂度为O(n).

int n=8,count = 0;

for(inti=1;i<=10n+100;i++){

  count++;

}

d.时间复杂度为的循环语句

int n=8,count=0;

for(int i=1;i<=n;i*=2){

 count++

}

e.时间复杂度为

f

.

2.Javascript系列

*什么是跨域

跨域是指从一个域名的网页去请求另一个域名的资源。比如:A上的页面获取B上的资源。

概念:只要协议、主机、端口有任何一个不同,都被当作是不同的域。

*哪些办法可以实现跨域

a.JSONP 动态创建<script>标签,并利用其src属性提供一个callback参数构造回调函数来接收数据,从而达到与第三方网址建立通信的目的,这就是JSONP

简单理解

jsonp.html

运行一下就会弹出miaov

b)跨域资源共享(CORS)

目前客户端已经实现,需要服务端做配置(header

服务器端代码

  1. <?php

  2. header('Access-Control-Allow-Origin:http://www.a.com'); //这是允许访问该资源的域

  3. echo 'hello';

这样就可以正常访问了

*表单可以跨域吗?

表单可以跨域。只不过无法返回请求数据。

*jsonp方案需要服务端怎么配合 

在服务器端,需要对script的src进行url解析,将data作为参数放入回调函数中,最后通过res.end(callback(data))中将要执行的函数放入客户端的script中,在客户端对该函数进行执行。

*Ajax发生跨域要设置什么(前端) 

基本上目前所有的浏览器都实现了CORS标准,其实目前几乎所有的浏览器ajax请求都是基于CORS机制的,只不过可能平时前端开发人员并不关心而已(所以说其实现在CORS解决方案主要是考虑后台该如何实现的问题)。后端设置看下面

*Access-Control-Allow-Origin在服务端哪里配置

使用headers属性

*加上CORS之后从发起到请求正式成功的过程

简单请求的流程:浏览器直接发送CORS跨域请求,并在header信息中增加一个Origin字段,表明这是一个跨域的请求。服务器根据这个值,决定是否同意这次请求。如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应,浏览器收到这个回应发现这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道错了,从而会抛出一个错误,被XMLHttpRequestonerror回调函数捕获。注意这种错误无法通过状态码识别,此时HTTP回应的状态码可能是200

非简单请求的过程:非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。下面是一段浏览器的JavaScript脚本。

*promise、async有什么区别

1.简洁

2.错误处理

在promise中,try/catch不能捕获JSON.parse抛出的异常,因为该操作是在promise的catch中处理的

在async/await中,catch代码块现在可以捕获JSON.parse抛出的异常了:

3.可读性提高 

条件分支或者中间值的情况下使用async/await可读性大大提高

4.异常堆栈

假设有一段串行调用多个promise的代码,在promise串中的某一点抛出了异常:

从promise串返回的异常堆栈中没有包含关于异常是从哪一个环节抛出的信息。

5.方便每一步进行调试

*asyncawait的理解,内部原理

async/await可以使异步代码在形式上更接近于同步代码。这就是它最大的价值。

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

*介绍下Promise,内部实现

promise用来实现一步操作,

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

解决了回调地狱的问题

*如何设计Promise.all()

Promise.all方法     多任务处理         

Promise.all(iterable)         iterable:包含多个 Promise 的迭代器对象,比如数组     当迭代器对象中的所有 Promise 状态都会 fulfilled/resolved 的时候,整体才是 fulfilled/resolved,否则就是 rejected

*使用Async会注意哪些东西

第一点,前面已经说过,await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

第二点,多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

第三点,await命令只能用在async函数之中,如果用在普通函数,就会报错。

第四点,async 函数可以保留运行堆栈。

*Async里面有多个await请求,可以怎么优化(请求是否有依赖)

*PromiseAsync处理失败的时候有什么区别

Promise中使用.catch,Async使用try/catch

*PromiseCallback有什么区别

1,callback函数处理异步:代码逻辑复杂,可读性差----回调地狱;不可return;
2,promise处理异步:对比callback,易读,可以return,不需要层层传递callback;处理多个异步等待合并
3,async,await--ES2017 ,promise的语法糖

*Promise构造函数是同步还是异步执行,then

Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的​​​​​​​

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值