面试题集锦(1)

116 阅读5分钟

什么是跨域?跨域请求资源的方法有哪些?

1、什么是跨域? 由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。存在跨域的情况: 网络协议不同,如http协议访问https协议。 端口不同,如80端口访问8080端口。 域名不同,如qianduanblog.com访问baidu.com。 子域名不同,如abc.qianduanblog.com访问def.qianduanblog.com。 域名和域名对应ip,如www.a.com访问20.205.28.90. 2、跨域请求资源的方法: (1)、porxy代理 定义和用法:proxy代理用于将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。 实现方法:通过nginx代理; 注意点:1、如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。 (2)、CORS 【Cross-Origin Resource Sharing】 定义和用法:是现代浏览器支持跨域资源请求的一种最常用的方式。 使用方法:一般需要后端人员在处理请求数据的时候,添加允许跨域的相关操作。如下:

res.writeHead(200, {
    "Content-Type": "text/html; charset=UTF-8",
    "Access-Control-Allow-Origin":'http://localhost',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type'
});

(3)、jsonp 定义和用法:通过动态插入一个script标签。浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。 特点:通过情况下,通过动态创建script来读取他域的动态资源,获取的数据一般为json格式。 实例如下:

<script>
    function testjsonp(data) {
       console.log(data.name); // 获取返回的结果
    }
</script>
<script>
    var _script = document.createElement('script');
    _script.type = "text/javascript";
    _script.src = "http://localhost:8888/jsonp?callback=testjsonp";
    document.head.appendChild(_script);
</script>

缺点:   1、这种方式无法发送post请求(这里)   2、另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

介绍一下 JS 的基本数据类型。

UndefinedNullBooleanNumberString

如何利用JavaScript实现一个自定义事件,存在on,off,emit三个方法?

这个题目的意义在哪里?我想,应该是对于一些特定的业务逻辑,比如在注册一个“通知”的事件,在与Native交互之后,假设这个交互是在入口级别的页面里,那么如何发送给具体某个业务呢?事件应该是最简单的一种方式,在某个具体的业务中注册一个事件,然后在与Native交互完,拿到某些数据后,然后触发这个事件。

我们来一步一步实现一个最简单的事件类Event,不考虑任何其他复杂的情况。假设在这个Event类的内部有一个this._events = [] 数组来维系整个事件系统,我们分别实现on,off,emit三个方法即可。

on(注册一个事件):

Event.prototype.on = function(type,fun){
    let cbs = this._events[type];
    cbs ? cbs.push(fun) : this._events[type] = [];
        if (!cbs) {
            this._events[type].push(fun)
    }        
}

这里为什么要将this._events设计为二维数组?因为事件可以是多个,但是事件名可能相同。这个逻辑意图非常的明显,根据type参数从this._events中获取是否存在。如果不存在,创建一个type为key的数组,并将事件句柄程序push到数组中。

off(注销一个事件):

Event.prototype.off = function (type, fun) {
    let cbs = this._events[type];
    //事件列队中无事件
    if (!cbs) {
      return this;
    }
    //删除所有的事件
    if (!event && !fun) {
      this._events = {};
      return this;
    }
    //只有事件名称时
    if (event && !fun) {
      this._events[type] = null;
      return this;
    }
    //删除某个事件队列中的某个事件
    let cb;
    let i = cbs.length;
    while (i--) {
      cb = cbs[i];
      if (cb === fun || cb.fun === fun) {
        cbs.splice(i, 1);
        break;
      }
    }
  }

虽然注销事件方法的逻辑可能相比之下稍许多了些,但它的实现也非常简单,只要只存在事件组key名的情况,或者删除某个事件队列中的某个事件句柄程序即可。

emit(触发一个事件):

Event.prototype.emit = function(type){    
    let cbs = this._events[type];    
    let args = tools.toArray(arguments,1);    
    if (cbs) {        
        let i = 0;        
        let j = cbs.length;        
        for(;i<j;i++){            
            let cb = cbs[i];            
            cb.apply(this,args);
        }
    }
}

逻辑依然非常简单,通过事件名从this._events获取相应的事件句柄程序数组,然后将arguments转成数组,(这里考虑的是可能会传入参数)如果事件句柄程序数组存在,进行循环,再讲args参数apply给每一个取出来的事件句柄程序。

##请描述一个网页从开始请求道最终显示的完整过程?

一个网页从请求到最终显示的完整过程一般可以分为如下7个步骤:
(1)在浏览器中输入网址;
(2)发送至DNS服务器并获得域名对应的WEB服务器IP地址;
(3)与WEB服务器建立TCP连接;
(4)浏览器向WEB服务器的IP地址发送相应的HTTP请求;
(5)WEB服务器响应请求并返回指定URL的数据,或错误信息,如果设定重定向,则重定向到新的URL地址;
(6)浏览器下载数据后解析HTML源文件,解析的过程中实现对页面的排版,解析完成后在浏览器中显示基础页面;
(7)分析页面中的超链接并显示在当前页面,重复以上过程直至无超链接需要发送,完成全部数据显示。

请描述一下 cookies,sessionStorage 和 localStorage 的区别?

Web Storage有两种形式:LocalStorage(本地存储)和sessionStorage(会话存储)。
这两种方式都允许开发者使用js设置的键值对进行操作,在在重新加载不同的页面的时候读出它们。这一点与cookie类似。
(1)与cookie不同的是:Web Storage数据完全存储在客户端,不需要通过浏览器的请求将数据传给服务器,因此x相比cookie来说能够存储更多的数据,大概5M左右。
(2LocalStorage和sessionStorage功能上是一样的,但是存储持久时间不一样。
LocalStorage:浏览器关闭了数据仍然可以保存下来,并可用于所有同源(相同的域名、协议和端口)窗口(或标签页);
sessionStorage:数据存储在窗口对象中,窗口关闭后对应的窗口对象消失,存储的数据也会丢失。
注意:sessionStorage 都可以用localStorage 来代替,但需要记住的是,在窗口或者标签页关闭时,使用sessionStorage 存储的数据会丢失。
(3)使用 local storage和session storage主要通过在js中操作这两个对象来实现,分别为window.localStoragewindow.sessionStorage. 这两个对象均是Storage类的两个实例,自然也具有Storage类的属性和方法。

说说js中的event loop机制?

首先javascript是单线程机制,就是指当我们在执行一个任务的时候,其它的事情都得等待他执行完毕

在js中所有任务分为两种, 同步任务及异步任务

执行栈执行主线程任务,当有操作dom,ajax交互,使用定时器异步操作的时候,这些任务会被移入到 callback queue 任务队列中 当主线程任务执行完毕为空时,会读取callback queue队列中的函数,进入主线程执行 上述过程会不断重复,也就是常说的Event Loop(事件循环)

在一个事件循环中,异步任务返回结果后会被扔进一个任务列队中,根据异步事件上的类型,这个事件会被放到对应的宏任务或者微任务列队中去, 当执行栈为空的时候,主线程会先查看微任务中的事件列队,如果微任务不是空先依次执行微任务如果是空的再去宏任务列队中取出一个事件并把对应的回调加入到当前执行栈,如此反复,进入循环

下面用一道题来加深印象

setTimeout(function () {
  console.log(1);
});

new Promise( (resolve,reject) => {
  console.log(2)
}).then( (val) => {
  console.log(val);
})

输出的结果是2,1

解释:

定时器是宏任务,Promise是异步的是微任务。所以先执行微任务 console.log(2),在执行宏任务console.log(1)

怎么理解js中的内存泄漏?

内存泄漏的定义为当程序不再需要的内存,由于某种原因其不会返回到操作系统或可用内存池,内存泄漏会导致一系列问题,比如: 运行缓阳,崩溃,高延迟等

js中常见的内存泄露:

1、意外的全局变量

2、遗忘的计时器或回调函数

3、脱离文档的DOM引用

4、闭包

怎么理解js中是原型链? 如何实现继承?

  • 每个构造函数都有一个原型对象

  • 每个原型对象都包含一个指向构造函数的指针

  • 每个实例都包含一个指向原型对象的指针

  • 查找方式是一层层向上查找直至顶层Object.prototype

实现继承的方式常用的有:

  • 原型链继承

  • 借用构造函数(call,apply)

  • 组合继承(原型链+构造函数)

  • 原型式继承

  • 寄生式组合式继承

new 运算符具体干了什么?

1、创建一个空的对象

2、将空的对象的proto成员指向构造函数的prototype成员对象

3、调用构造函数将this指向前面创建的对象