面试题集

HTML部分

1. 你是如何理解 HTML 语义化的?

语义化是指根据内容的结构化(内容语义化),选择合适的标签(代码语义化),便于开发者阅读和写出更优雅的代码的同时,让浏览器的爬虫和机器很好的解析。
标题用h1-h5。文章用artical。段落用p。时间用time标签。 header标签,footer标签,main标签, nav,artical标签。

html分的历史阶段:

  1. 后台开发写前端页面
    使用table标签。会出现table套table的窘境
  2. 美工阶段
    div+css布局。不够语义化。
  3. 前端阶段
    语义化标签
2. meta viewport 是做什么用的,怎么写?

移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域。比如浏览器的可展示区域

width设置layout viewport的宽度,为一个正整数,或字符串"width-device"
initial-scale设置页面的最大缩放值,为一个数字,可以带小数
minimum-scale允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale允许用户的最大缩放值,为一个数字,可以带小数
height设置layout viewport的高度,这个属性并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为"no"或"yes"

CSS

两种盒模型
  • box-sizing: conent-box; 将盒子设置为标准模型(盒子默认为标准模型)
  • box-sizing: border-box; 将盒子设置为 IE 模型(也叫做怪异盒子)
content-box {  width: 100px;  height: 100px;  border: 50px solid;  padding: 50px;}

标准模型中,它在页面中实际占有的宽高为300px
IE 模型中,它的页面实际占有宽度还是100px。由于 border + padding 已经等于 100px 了,所以这里 content 已经被压缩到只剩 0 了

什么是边距重叠
两种现象
  1. 同一层相邻元素

  1. 父元素和子元素之间没有内容
实现垂直居中

如果 .parent 的 height 不写,你只需要 padding: 10px 0; 就能将 .child 垂直居中;

如果父元素height写了高度

#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    position: relative;
}
#child {
    width: 150px;
    height: 100px;
    background: orange;
    position: absolute;
    top: 50%;
    margin: -50px 0 0 0; 
}
#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    position: relative;
}
#child {
    background: orange;
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
}
#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    display: flex;
    align-items: center;
}
#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    position: relative;
}
#child{
  background: orange;
  position: absolute;
  width: 150px;
  height: 100px;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
水平垂直居中
  1. 水平居中

margin: 0 auto;

.wrap {
    position: relative;
    background-color: orange;
    width: 300px;
    height: 300px;
}
.example2 {
    background-color: red;
    width: 100px;
    height: 100px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin: -50px 0 0 -50px;
}

flex布局

居中显示
.warp {
  position: relative;
  background-color: orange;
  width: 200px;
  height: 200px;
}
.example3 {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: red;
  width: 100px;
  height: 100px;
  margin: auto;
}
.warp {
  position: relative;
  background-color: orange;
  width: 200px;
  height: 200px;
}
.example3 {
  position: relative;
  top:50%;
  transform:translateY(-50%);
  background-color: red;
  width: 100px;
  height: 100px;
  margin: 0 auto;
}
BFC

块格式化上下文

1.给父元素overflow:hidden。那么其浮动的子元素就会被包裹

  1. 兄弟之间划清界限
    假设现在有一对兄弟 div,其中一个加了浮动,那么两个 div 会重叠一部分


    4.png

如果让另一个 div 创建 BFC,那么这两者就会界限分明。


5.png
css优先级

内联 > ID选择器 > 类选择器 > 标签选择器。

  1. 越具体优先级越高
  2. 写在后面的覆盖前面的
  3. important ! 优先级最高。少用。
清楚浮动
.clearFix {
  content: '';
  display: block;
  clear: both;
}

js

ES6 语法知道哪些,分别怎么用?
  • 块级作用域
    let变量,const常量
  • 箭头函数
    。 默认参数
    。 剩余参数: 剩余参数语法允许我们将一个不定数量的参数表示为一个数组
    。 展开运算符: 可以展开数组
function multiply(a, b = 1) {
  return a * b;
}

console.log(multiply(5)); // 5

function fun1(...theArgs) {
  alert(theArgs.length);
}
fun1(5, 6, 7); // 弹出 "3", 因为theArgs有三个元素

function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));
// expected output: 6

[...iterableObj, '4', ...'hello', 6]; // 数组合并
  • 模板字符串
  • 对象属性加强
    。 属性定义支持短语法 obj = { x, y }
  • 解构赋值
var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20
  • Promise

手写函数防抖和函数节流
节流

一段时间执行一次之后,就不执行第二次

functiong fn() {}
let cd = false // 技能是否在冷却
button.onclick = function () {
  if(cd) {
    // 在冷却,什么也不错
  } else {
    fn() // 执行函数  或者fn在setTimeout里面执行。相当于施法有吟唱时间
    cd = true
    setTimeout(() => {
     cd = false
    }, 3000)
  }
}
防抖

用户在1s内连续点击两次。只执行最后一次。等一秒之后再执行。如果一秒内再次触发。则清除上次的执行timeout

比如再拖动窗口的时候。用户再一秒内可能改变了很多次窗口的大小。此时我只执行最后一次

function fn () {}
var timerId = null
button.onclick = function () {
  if(timerId) {
    window.clearTimeout(timerId)
  }
  timerId = setTimeout(() => {
    fn()
    timerId = null
  }, 1000)
}

手写一个AJAX
function ajax() {
  let request = new XMLHttpRequest()
  request.open('get', 'https://www.google.com') // 请求方式和请求路径
  request.onreadystatechange = () => { // 监听状态
    if (request.readyState === 4) { // 0:代理创建 1:open方法被调用 2:send方法被调用 3:下载中  4: 下载操作已完成
        if (request.status >= 200 && request.status <300) {
            let string = request.responseText
            let object = JSON.parse(string)
        }
    }
  }
  request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 设置请求头
  request.send(data) // 要传的参数  可以使用JSON.stringify()和JSON.parse()进行转换
}

this是什么

this


闭包/立即执行函数是什么?
  • 闭包

「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。

function foo(){
  var local = 1
  function bar(){ // bar 和local就形成了闭包。此时我需要把bar返回出去。这样外面就能方问到里面的局部变量
    local++
    return local
  }
  return bar
}

var func = foo()
func()

或者

!function(){
  var lives = 50
  window.奖励一条命 = function(){
    lives += 1
  }
  window.死一条命 = function(){
    lives -= 1
  }
}()

在其他js文件中就能通过windown.奖励一条命等去操作局部变量 lives

  • 立即执行函数
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。 常用形式
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()

立即执行函数的作用 创建一个独立的作用域。

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
  liList[i].onclick = function(){
    alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5。 因为i是全局变量
  }
}
var liList = ul.getElementsByTagName('li')
for(var i = 0; i< 6: i++) {
  !function(ii){
    liList.onclick = function() {
      alert(ii) // 0 1 2 3 4 5
    }
  }(i)
}

JSONP是什么

jsonp的核心是动态添加

例子二

跨域服务器

文件:remote.js
代码:
localHandler({"result":"我是远程js带来的数据"});

本地

 

例子三(我需要告诉服务器我的回调名称及参数)

跨域服务器

文件:flightResult.php
代码:
flightHandler({ "code":"CA1998", "price": 1780, "tickets": 5 });

本地



CORS是什么

它允许浏览器向跨源服务器。
浏览器将CORS请求分成两类:简单请求非简单请求

只要同时满足以下两大条件,就属于简单请求。

  • 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  • HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

GET /cors HTTP/1.1
Origin: http://api.bob.com // 来自哪里
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

//它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
Access-Control-Allow-Origin: http://api.bob.com 该字段是必须的。
// 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。
Access-Control-Allow-Credentials: true
withCredentials 属性

CORS请求默认不发送Cookie和HTTP认证信息。

一方面服务器端需要同意,设置
Access-Control-Allow-Credentials: true
另一方面前端开发设置
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

非简单请求

比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)

服务器收到"预检"请求以后,检查了Origin(来源)、Access-Control-Request-Method(请求方法)和Access-Control-Request-Headers(额外发送的头信息)字段以后,确认允许跨源请求,就可以做出回应。

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样

深拷贝
JSON.parse(JSON.stringify())

能完成大部分数据得深拷贝。但存在问题

1.undefined、function、symbol这三种类型的值就是非安全的,所以格式化后,就被过滤掉了

  1. set、map这种数据格式的对象,也并没有被正确处理,而是处理成了一个空对象
  2. 循环引用报错
  3. 相同的引用会被重复复制

**写一个递归调用得函数进行深拷贝

function deepCopy(data) {
      if(typeof data !== 'object' || data === null){
          throw new TypeError('传入参数不是对象')
      }
      let newData = {};
      const dataKeys = Object.keys(data);
        dataKeys.forEach(value => {
        const currentDataValue = data[value];
        // 基本数据类型的值和函数直接赋值拷贝 
       if (typeof currentDataValue !== "object" || currentDataValue === null) {
            newData[value] = currentDataValue;
        } else if (Array.isArray(currentDataValue)) {
           // 实现数组的深拷贝
          newData[value] = [...currentDataValue];
        } else if (currentDataValue instanceof Set) {
           // 实现set数据的深拷贝
           newData[value] = new Set([...currentDataValue]);
        } else if (currentDataValue instanceof Map) {
           // 实现map数据的深拷贝
           newData[value] = new Map([...currentDataValue]);
        } else { 
           // 普通对象则递归赋值
           newData[value] = deepCopy(currentDataValue);
        } 
     }); 
    return newData;
}

测试数据

// 测试数据项
var data = {
  age: 18,
  name: "liuruchao",
  education: ["小学", "初中", "高中", "大学", undefined, null],
  likesFood: new Set(["fish", "banana"]),
  friends: [
    { name: "summer",  sex: "woman"},
    { name: "daWen",   sex: "woman"},
    { name: "yang",    sex: "man" }
  ], 
  work: { 
    time: "2019", 
    project: { name: "test",obtain: ["css", "html", "js"]} 
  }, 
  play: function() {console.log("玩滑板");}
}

如何用正则实现 trim()?

function trim(string){
    return string.replace(/^\s+|\s+$/g, '')
}

不用 class 如何实现继承?用 class 又如何实现?

不用class

function Animal(name){ 
    this.name = name; 
    this.colors = ["red", "blue", "green"]; 
} 
 
Animal.prototype.sayName = function(){ 
    console.log(this.name); 
}

function Dog(name, age){   
    //继承属性 
    Animal.call(this, name); 
    this.age = age; 
} 
 
let f = function () {}
f.prototype = Animal.prototype

//继承方法 
Dog.prototype = new f();  
Dog.prototype.constructor = Dog; 
Dog.prototype.sayAge = function(){ 
    alert(this.age); 
}; 

用class实现继承

class Animal{
     constructor(color){
         this.color = color
     }
     move(){}
 }
 class Dog extends Animal{
     constructor(color, name){
         super(color)
         this.name = name
     }
     say(){}
 }

数组去重

  1. 利用indexOf实现去重。

indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (res.indexOf(arr[i]) === -1) {
            res.push(arr[i])
        }
    }
    return res
}
  1. 相邻元素去重

先用sort进行排序

function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    arr = arr.sort()
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] !== arr[i-1]) {
            res.push(arr[i])
        }
    }
    return res
}
  1. 使用set

set中的值是唯一的

function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    return [...new Set(arr)]
}

DOM

事件冒泡、事件捕获、事件委托

用户点击,当father和child都存在点击事件时,先执行哪一个事件
事件冒泡认为应该先从子元素开始执行。往后面冒泡。
事件捕获则是从父元素开始执行。最后执行子元素。
event.stopPropagation()可组织事件冒泡或者捕获。
在子元素点击事件执行时添加stopPropagation就可以组织父元素的点击事件执行
addEventListener第三个参数可以设置事件冒泡或者事件捕获

 ul.addEventListener('click', function(e){
     if(e.target.tagName.toLowerCase() === 'li'){
         fn() // 执行某个函数
     }
 }) // 默认为false。事件冒泡

高阶版

当li里面有个span。点击了span

function delegate(element, eventType, selector, fn) {
     element.addEventListener(eventType, e => {
       let el = e.target
       while (!el.matches(selector)) {
         if (element === el) {
           el = null
           break
         }
         el = el.parentNode
       }
       el && fn.call(el, e, el)
     })
     return element
   }

HTTP

HTTP 状态码知道哪些?分别什么意思?
  1. 100 Continue
    这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。
  2. 102 Processing
    此代码表示服务器已收到并正在处理该请求,但没有响应可用。
  3. 200 OK
    请求成功
  4. 201 Created
    该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应。
  5. 204 No content
    服务器成功处理了请求,但不需要返回任何实体内容
  6. 301 Moved Permanently
    被请求的资源已永久移动到新位置.
  7. 302 Found
    请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。
  8. 400 Bad Request
    1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。
    2、请求参数有误。
  9. 403 Forbidden
    服务器已经理解请求,但是拒绝执行它。权限
  10. 404 No Found
    请求失败,请求所希望得到的资源未被在服务器上发现。
  11. 500 Internal Server Error
    服务器遇到了不知道如何处理的情况。

2开头一般表示成功。3开头表示需要进一步的操作。4开头表示客户端错误。5开头表示服务器端错误。

你可能感兴趣的:(面试题集)