基础面试知识点

141 阅读26分钟

html基础面试题302

1.如何理解HTML语义化?

两端代码比较:

 <div>标题</div>
    <div>
        <div>一段文字</div>
        <div>
            <div>列表1</div>
            <div>列表2</div>
        </div>
    </div>
}
  <h1>标题</h1>
    <div>
        <p>一段文字</p>
        <ul>
            <li>列表1</li>
            <li>列表2</li>
        </ul>
    </div>
}
  • 让人更容易读懂(增加代码可读性)
  • 让搜索引擎更容易读懂(SEO)

2.哪些HTML标签是块级元素,哪些是内联元素?

  • display:block/table;有 div h1 h2 table ul ol p 等
  • display:inline/inline-block;有span img input button 等

css常见面试题

css布局

1.盒子模型的宽度如何计算?

<!--如下代码,请问div1的offsetWidth是多大?-->
    <style>
        #box{
            width: 100px;
            padding: 10px;
            border: 1px solid #ccc;
            padding:10px;
            margin:10px;
        }
    </style>
    <div id="box"></div>

offsetWidth=(内容宽度 + 内边距 + 边框),无外边距
答案:122px
box-sizing: border-box/ content-box;

2.margin纵向重叠的问题?

    <p>AAA</p>
    <p></p>
    <p></p>
    <p></p>
    <p>BBB</p>
    <!--如下代码,AAA和BBB之间的距离是多大?-->
    <style>
        p{
            font-size: 16px;
            line-height: 1;
            margin-top: 15px;
            margin-bottom: 15px;
        }
    </style>
  • 相邻元素的margin-top和margin-bottom会发生重叠
  • 空白内容的p标签也会重叠 答案是:15px

3.margin负值的问题?

  • margin-top和margin-left负值,元素向上,向左移动
  • margin-right负值,右侧元素左移,自身不受影响
  • margin-bottom负值,下方元素上移,自身不受影响

4.BFC理解和应用?

  • Block format context,块级格式化上下文
  • 一块独立渲染区域,内部元素的渲染不会影响边界以外的元素 形成BFC的常见条件:
  • float不是none
  • position是absolute 或fixed
  • overflow不是visible
  • display是flex inline-block等 BFC常见应用:
  • 清除浮动
// 如果img 添加float:left;会形成bfc 使图片脱离文档流; 
// 加上bfc(oveflow:hidden),可以实现bfc
<div class="container bfc">
        <img src="./logo.png" alt="">
        <p>一段文字</p>
    </div>
    <style>
        .container img {
            float:left; /* 形成bfc */
        }
        .bfc {
            overflow: hidden;  /* 触发元素BFC */
        }
    </style>

5.float 布局的问题,以及clearfix?

圣杯布局和双飞翼布局的目的:

  • 三栏布局,中间一栏最先加载和渲染(内容最重要)
  • 两侧内容固定,中间内容随着宽度自适应
  • 一般用于pc 圣杯布局和双飞翼布局的技术总结:
  • 使用float布局
  • 两侧使用margin负值,以便和中间内容横向重叠
  • 防止中间内容被两侧覆盖,一个用padding一个用margin
// 圣杯布局
<style>
        .container {
            padding-left: 200px;
            padding-right: 150px;
        }
        .center{
            width: 100%;
            background: #ccc;
        }
        .left{
            position: relative;
            width: 200px;
            margin-left: -100%;
            background: yellow;
            right: 200px;
        }
        .right
        {
            width: 150px;
            background: pink;
            margin-right: -150px;
            
        }
        .column{
            float: left;
        }
    </style>
    <div class="header"></div>
    <div class="container">
        <div class="center column">this is center</div>
        <div class="left column">this is left</div>
        <div class="right column">this is right</div>
    </div>
    <div class="footer"></div>
// 双飞翼布局
<style>
        .main {
           width: 100%;
           height: 200px;
           background-color: #ccc;
        }
        .main-warp{
            margin-left: 200px;
            margin-right: 150px;
        }
        .left{
            width: 200px; 
            height: 200px;;
            background: yellow;
            margin-left: -100%;
        }
        .right
        {
            width: 150px;
            background: pink;
            height: 200px;
            margin-left: -150px;
        }
        .col{
            float: left;
        }
        /* 手写clear fix */
        .clearfix:after{
            content:"";
            display: table;
            clear: both;
        }
        .clearfix {
           *zoom:1   /* 兼容IE低版本 */
        }
    </style>
    <div class="container clearfix">
        <div class="main col ">
            <div class="main-warp ">this is main</div>
        </div>
        <div class="left col">this is left</div>
        <div class="right col">this is right</div>
    </div>

6.flex布局的问题?

7.css定位absolute和resolve分别依据什么定位?

  • resolve依据自身定位,对外界无影响
  • absolute依据最近一层元素定位 定位元素: absolute fixed resolve body

8.居中对齐有哪些实现方式?

水平居中:

  • inline元素: text-align:center
  • block元素:margin: auto
  • absolute元素: left:50%; margin-left 负值 垂直居中:
  • inline元素: line-height的值等于height值
  • absolute元素: top:50%; margin-top 负值
  • absolute元素: transform(-50%, -50%)
  • absolute元素:left,right,top,bottom=0 + margin:auto;
// bsolute元素: transform(-50%, -50%)
 <style>
       .container{
           width: 500px;
           height: 300px;
           border:1px solid #ccc;
           position: relative;
       }
       .item{
           width: 200px;
           height: 100px;
           line-height: 100px;
           background-color: #ccc;
           text-align: center;
       }
       .item-1{
        position: absolute;
           top: 50%;
           left: 50%;
           transform: translate(-50%, -50%);
       }
    </style>
    <div class="container clearfix">
        <div class="item item-1">this is item</div>
    </div>
// - absolute元素:left,right,top,bottom=0 + margin:auto;
<style>
       .container{
           width: 500px;
           height: 300px;
           border:1px solid #ccc;
           position: relative;
       }
       .item{
           width: 200px;
           height: 100px;
           line-height: 100px;
           background-color: #ccc;
           text-align: center;
       }
       .item-1{
           position: absolute;
           top: 0;
           left: 0;
           right: 0;
           bottom: 0;
           margin: auto;
       }
    </style>
    <div class="container clearfix">
        <div class="item item-1">this is item</div>
    </div>

效果:

1645412321(1).jpg

9.line-height 如何继承?

  • 写具体数值,如30px, 则继承该值
  • 写比例,如 2/1.5, 则继承该值
  • 写百分比,如200%, 则继承算出来的值(考点)

10.css响应式

(1)rem是什么?

rem: 是一个长度单位

  • px:绝对长度单位,最常用
  • em:相对长度单位,相对于父元素,不常用
  • rem:相对长度单位,相对于根元素,常用于响应式
    <style>
     html{
         font-size: 100px;
     }
     div{
         font-size: 0.16rem; /* 0.16rem = 16px */
     }
    </style>
    <p style="font-size: 0.1rem;">rem1</p>
    <p style="font-size: 0.2rem;">rem2</p>
    <p style="font-size: 0.18rem;">rem3</p>
    <div>rem4</div>
    <div>rem5</div>
    <div>rem6</div>

(2)响应式布局的常用方案?

  • media-query, 根据不同的屏幕宽度设置根元素的font-size
  • rem,基于根元素的相对单位
  <style>
        @media only screen and (max-width:374px){
            /* iphone5 或者更小的尺寸,以iPhone5 的跨度(320px)比例设置 fonts-size */
            html{
                font-size: 86px;
            }
        }
        @media only screen and (min-width:375px) and (max-width: 431px){
            /* iphone6/7/8/x  */
            html{
                font-size: 100px;
            }
        }
        @media only screen and (min-width:414px){
            /* iphone6 或者更大尺寸,以iPhone6p 的跨度(414px)比例设置font-size */
            html{
                font-size: 110px;
            }
        }
        body{
            font-size: 0.16rem;
            /* 根元素html文字大小 * 0.16rem = 绝对长度 px */
        }
        .div1{
            width: 1rem;
        }
    </style>
    <div class="div1">this is div1</div>

(3)响应式 vw/vh ?

  • rem弊端
  • 网页视口尺寸
  • vw/vh rem弊端: “阶梯” 性
    @media only screen and (max-width:374px){
            /* iphone5 或者更小的尺寸,以iPhone5 的跨度(320px)比例设置 fonts-size */
            html{
                font-size: 86px;
            }
        }
        @media only screen and (min-width:375px) and (max-width: 431px){
            /* iphone6/7/8/x  */
            html{
                font-size: 100px;
            }
        }
        @media only screen and (min-width:414px){
            /* iphone6 或者更大尺寸,以iPhone6p 的跨度(414px)比例设置font-size */
            html{
                font-size: 110px;
            }
        }

网页视口尺寸: window.screen.height// 屏幕视口高度 window.innerHeight // 网页视口高度 document.body.clientHeight // body 高度

vw/vh: vh 网页视口高度的 1/100 vw 网页视口宽度的 1/100 vmax 取两者中间最大值,vmin 取两者之间最小值

   window.innerWidth === 100vh
   window.innerHeight === 100vw

10. css3动画?

Javascript面试题

变量类型和计算

1.typeof 能判断那些类型?

  • 识别所有的值类型
  • 识别函数
  • 判断是否是引用类型(不可再细分)
判断值类型:
const a;   // typeof undefined 
const b = 'abc'; // typeof string  
const c = 10; // typeof number
const d = true;  // typeof boolean  
const f = Symbol('5);  // typeof Symbol 

判断函数:
typeof console.log() // function 
typeof function() {}  // function
// 能识别应用类型 (不能再继续识别)
typeof  null; // Object
typeof [12,23] // Object
typeof {} // Object

2.何时使用 === 何时使用== ?

除了null之外,其他一律都用 ===,例如

const obj = { x:100 };
if(obj.a == null) {}
// 相当于:
// if(obj.a === null || obj.a === undefined) {}

3. if语句与逻辑运算符

  • truly变量 !!a === true 的变量
  • falsely变量 !!b === false 的变量
 !!0 === false
 !! undefined === false
 !! false === false 
 !! null === false
 !! '' === false
 !! NaN === false
 
 !! {} === true
 !! [] === true
 
// truly类变量:
const a = true;
const a = 100;
if(a) {
  ...
}
// falsly类变量:
const b = '';
const b = null;
if(b) {
  ...
}
// 逻辑判断规则
console.log( 0 && 10 )  // 0
console.log( 10 || 0 )  // 10
console.log(!window.abc) // true

4.值类型和引用类型的区别?

引用值类型的赋值可能会存在干扰

const obj = {
    a: 1
}
const obj1 = obj;
obj1.a = 2;
console.log(obj.a)  // 2

5.手写深拷贝?

function deepClone(obj = {}){
    if(typeof obj != 'object' || typeof obj == null) {
        // obj是null,或者不是object直接返回
        return obj
    }
    //  初始化返回结果
    let result;
    if(obj instanceof Array) {
      result = []
    } else {
      result = {}
    }
    for(let key in obj) {
      // 保证key不是原型的属性
      if(obj.hasOwnProperty(key)) {
        // 递归调用!!!
        result[key] = deepClone(obj[key])
      }
    }
    return result
}

6.值类型和引用类型?

值类型:
let a = 20;
let b = a;
b = 10;
console.log(a) // 20

引用类型:

let a = { age: 20 } let b = a; b.age = 21; console.log(a.age) // 21

值类型: 存储在栈中
| 栈 |  |
| --- | --- |
|key  |  value |
|a  |  100 |
|b |  200 |

| 栈 |  |
| --- | --- |
|key |  value |
|a  |  内存地址1 |
|b |  内存地址2 |

引用值类型:
| 堆 |  |
| --- | --- |
|key  |  value |
|内存地址1 |  {age: 20} |
|key |  val |

| 堆 |  |
| --- | --- |
|key  |  value |
|内存地址2 |  {age: 21} |
|key |  val |

使用引用类型和值类型的原因:
- 值类型存储空间小,赋值不会对内存造成影响。
- 引用值内存地址太大,不好管理
- 引用直接赋值会非常慢,基于内存空间,计算机性能进行区分。

常见的值类型:

const a = undefined;
const b = 'abc';
const c = 10;
const d = true;
const f = Symbol('5);

常见的引用类型:

const a = { x: undfined };
const b = [1,2,3,4];
const c = null;  // 特殊引用值类型,指针指向空地址
// 特殊的引用类型,但不用于存储数据,所以没有“拷贝,赋值函数”
function() fn {}  // function

6.变量计算-类型转换?

  • 字符串拼接
  • ==
  • if语句和逻辑运算
//字符串拼接
const a = 100 + 10; // 110
const b = 100 + '10'; // 10010
const c = true + '10'; // true10

// == 运算符
100 == '100' // true
0 == ''  // true
0 == false // true
false == ''  // true
null == undefined // true

7.typeof 和 instanceof区别?

  • typeof 会返回一个运算数的基本类型,instanceof 返回的是布尔值
  • instanceof 可以准确判断引用数据类型,但是不能正确判断基本数据类型
  • typeof 虽然可以判断基本数据类型(null 除外),但是无法判断引用数据类型(function 除外) 扩展:

Object.prototype.toString.call()

  • typeofinstanceof都有一定的弊端,并不能满足所有场景的需求。如果需要通用检测数据类型,可以使用Object.prototype.toString.call()方法:
Object.prototype.toString.call({}); // "[object Object]" 
Object.prototype.toString.call([]); // "[object Array]" 
Object.prototype.toString.call(666); // "[object Number]" 
Object.prototype.toString.call('xxx'); // "[object String]"

扩展封装:

function getType(value) {
    let type = typeof value;
    console.log(type)
    if(type !== 'object') {
        // 如果是基本数据类型,直接返回
        return type
    }
    return Object.prototype.toString.call(value).replace(/\[object (\S+)]$/,'$1')
}
getType({name: 123})  // object

原型和原型链

1.如何判断一个变量是不是数组?

a instanceof Array

2.手写jquery,考虑插件和扩展性?

/*
 * jQuery demo
 */
class jQuery {
  constructor(selector) {
      const result = document.querySelectorAll(selector);
      const length = result.length;
      for(let i = 0; i < length; i++ ) {
        this[i] = result[i];
      }
      this.length = length;
      this.selector = selector;
  }
  get(index) {
    return this[index]
  }
  each(fn) {
    for(let i = 0; i < this.length; i++) {
      const elem = this[i];
      fn(elem)
    }
  }
  on(type, fn) {
    return this.each(elem => {
      elem.addEventListener(type, fn, false)
    })
  }
  // 扩展更多dom操作
}
// 扩展
jQuery.prototype.dailog = function(info) {
  alert(info)
}

// 复用
class MyjQuery extends jQuery{
  constructor(selector) {
    super(selector);
  }
  // 扩展自己的插件
  addClass(classname) {
  }
}
// 使用插件
const $p = new jQuery('div');
$p.get(1)
$p.each(elem => console.log(elem.nodeName));
$p.on('click', () => alert('clicked'))

3.class的原型本质,怎么理解?

  • 原型和原型链的图示
  • 属性和方法的执行规则

知识点:

4.class继承

class Student {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayHi() {
        console.log(this.name ,this.age);
    }
}
const student1 = new Student('mary', 13);
student1.sayHi();

继承:

  • extends
  • super
  • 扩展或重写方法

5.instanceof 类型判断

xiaoluo instanceof Student  // true
xiaoluo instanceof People  // true
xiaoguo instanceof Object  // true
[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
  • 判断继承
  • 判断数组类型
  • 判断对象类型

.6原型和原型链

原型

1646552672(1).jpg 原型关系:

  • 每个class都有显示原型prototype
  • 每个实例都有隐式原型__proto__
  • 实例的__proto__指向对应的class的prototype 原型的执行规则: 获取属性xiaoluo.name 或执行方法xiaoluo.sayhi() 时 先在自属性和方法寻找 如果找不到则自动去__proto__中查找
原型链

1646553608(1).jpg

console.log(Student.prototype.__proto__)
console.log(People.prototype)
console.log(People.prototype === Student.prototype.__proto__)

hasOwnProperty() // 判断是自身原型 1646553886(1).jpg instanceof原理:

  • 顺着原型链上查找,对应的到class的prototype(显示原型),那么intanceof成立。
xiaoluo instanceof Student  // true
xiaoluo instanceof People  // true
xiaoguo instanceof Object  // true

作用域和闭包

1. this的不同应用场景,如何取值?

  • 作为普通函数
  • 使用call apply bind
  • 作为对象方法调用
  • 在class方法中调用
  • 箭头函数

2. 手写bind函数?

function fn1(a, b, c) {
  console.log('this', this.x);
  console.log(a, b, c);
  return 'this is fn1';
}
const fn2 = fn1.bind({x: 100}, 10, 20, 53);
const res = fn2();
console.log(res);

// 模拟bind
Function.prototype.MyBind = function() {
   // 将参数插接为数组
   const args = Array.prototype.slice.call(arguments);
  
  // 获取this (数组第一项)
  const t = args.shift();
  
  // this指向 fn1.bind(...) 中的fn1
  const self = this;
  
  // 返回一个函数
  return function() {
     return self.apply(t, args)
  }
}

const fn2 = fn1.MyBind({x: 100}, 10, 20, 53);
const res = fn2();
console.log(res);

3. 实际开发中闭包的应用场景,举例说明?

  • 隐藏数据
  • cache工具
// 闭包隐藏数据,只提供api 
function createCache() {
  const data = {}; // 闭包中的数据,被隐藏,不被外接访问。
  return {
    set: function(key, val) {
       return data[key] = val
    },
    get(key) {
      return data[key]
    }
  }
}
const c = createCache();
c.set('name', 'bob');
console.log(c.get('name'))
// 外部无法直接访问data作用域中的数据

4. 创建 10 个 a标签,点击时候弹出对应的序号?

1646983985(1).jpg

知识点:

5.作用域和自由变量

作用域: 1646556644.jpg

  • 如果所示,作用域就是控制变量访问的范围。
  • 全局作用域
  • 局部作用域
  • 块级作用域(ES6 新增)
es6块作用域
if(true) {
    let x = 100
}
console.log(x) // 会报错

自由变量: 一个变量在当前作用域没有定义,但被使用了,会向上级作用域,一层一层一次寻找,直到找到为止 如果到全局作用域都没找到,则报错 xxx is not defined

6.闭包

作用域应用的特殊情况,有两种表现:

  • 函数作为参数被传递
  • 函数作为返回值被返回
// 函数作为返回值
function create() {
     let a = 100;
     return function() {
         console.log(a)
     }
}
let fn = create();
let a = 200;
fn()
// 函数作为参数
function print(fn) {
     let a = 100;
     fn()
}

let a = 200;
function fn() {
     console.log(a)
}
print(fn);

7.this

this取值在函数执行的时候决定的

  • 作为普通函数
  • 使用call apply bind
  • 作为对象方法调用
  • 在class方法中调用
  • 箭头函数
function f1() {
    console.log(this) 
}
f1();  // window

f1.call({x: 100 }) // {x: 100 }

const f2 = f1.bind({x: 200});
f2()   // {x: 200 }
const zhangsan = {
    name:"张三",
    sayhi:function() {
        // this当前对象
        console.log(this)
    },
    wait() {
        setTimeout(function() {
           // this === window
            console.log(this)
        }, 100)
    }
}


const zhangsan = {
    name:"张三",
    sayhi:function() {
        // this当前对象
        console.log(this)
    },
    wait() {
        setTimeout(() =>  {
            // 箭头函数取值,取上层作用域的值
            // this当前对象
            console.log(this)
        }, 100)
    }
}
class People{
    constructor(name) {
        this.name = name ;
    }
    say() {
        console.log(this.name)
    }
}
const p1 = new People('bobo');
p1.say(); // this指向'bobo'对象

异步和单线程

1.同步和异步的区别是什么?

  • 异步是基于js单线程语言
  • 异步不会阻塞代码执行
  • 同步回阻塞代码执行

2.手写promise加载一张图片?

const url = 'xxx.png';
function loadImg(src) {
    return new Promise((resolve,reject) => {
        const img = document.createElement('img');
        img.onload = () => {
            resolve(img)
        }
        img.onerror = () => {
            reject(new Error(`图片加载失败) ${src}`)
        }
        img.src = src;
    })
}
loadImg(url).then(img => {
    console.log(img.width);
    return img
}),then(img => {
    console.log(img.height);
}).catch((error) => console.log(error)

3.前端使用异步的场景有哪些?

  • 网络请求,如ajax 图片加
ajax 请求
console.log('start)
$.get('./data.json', function(res) {
    console.log(res)
})
console.log('end')
图片加载
console.log('start');
let img = document.createElement('img');
img.onload = funtion() {
       console.log('loaded')
}
img.src = 'xxx'
console.log('end');
  • 定时任务,如setTimeout
// 定时任务
console.log(100)
setTimeOut(function() {
    console.log(200)
}, 1000)
console.log(300);

4.一下代码什么顺序打印出来?

13542

1647146202(1).jpg

知识点:

4.单线程和异步

  • js是单线程语言,只能同时做一件事儿
  • 浏览器和nodejs已支持js启动进程,如web worker
  • js和dom 渲染共同一个线程,因为js可修改dom结构
  • 遇到等待(网络请求,定时任务)不能卡主
  • 需要异步
  • 回调callback函数形式 异步和同步:
  • 基于js是单线程语言本质
  • 异步不会阻塞代码执行
  • 同步回阻塞代码执行
// 异步 (callback 回调函数)
console.log(100)
setTimeOut(function() {
    console.log(200)
}, 1000)
console.log(300);

// 同步
console.log(100)
alert(200)
console.log(300)

5.应用场景

  • 网络请求,如ajax 图片加载
  • 定时任务,如setTimeout

6.callback hell 和promise

promise 解决 callback hell

callback hell 1647145052(1).jpg

promise 1647145148(1).jpg

管道串联形式展示回调嵌套 1647145231.jpg

异步 - 进阶

  • event-loop
  • pormise 进阶
  • async/await
  • 微任务/宏任务

1.请描述evet-loop (事件循环/事件轮询)的机制,可画图

以几点分析机制: (1)自行回顾eventloop的过程 (2) 和dom渲染的关系 (3)微任务和宏任务在event loop过程中的不同处理

  • js是单线程运行的
  • 异步要基于回调来实现
  • evet-loop 就是异步回调的实现原理 js如何执行?
  • 从前到后,一行一行执行
  • 如果某一行执行报错,则停止下面代码的执行
  • 先把同步代码执行完,再执行异步

1647159686(1).jpg event loop 过程:

  • 同步代码,一行一行放在Call Stack(调用栈) 执行
  • 遇到异步,会先“记录”下,等待时机(定时、网络请求等)
  • 时机到了,就移动到Callback Queue (回调队列)
  • 如 Call Stack为空(即同步带吗执行完)Event Loop开始工作
  • 轮询查找Callback Queue, 如有则移动到call stack执行
  • 然后继续轮询查找(永动机一样)

未标题-1.png

Dom 事件和event loop

1647162319(1).jpg

  • 先将click内回调函数放入 web apis中
  • 当点击时,启动event loop执行,放入callback queue 中,再放入call Stack中执行该回调内函数 DOM事件 和event loop
  • js是单线程的
  • 异步(settimeout ajax等)使用回调,基于event loop
  • DOM事件也使用回调,基于event loop,但是dom事件不是异步

2.什么是宏任务和微任务,两者有什么区别?

  • 宏任务: setTimeout setInterval Ajax dom事件
  • 微任务: Promise async/awiat
  • 微任务执行时机比宏任务早
  • 宏任务在dom渲染之后触发,微任务在dom渲染之前触发

3.Promise 有那几种状态?如何变化?

三种状态:

  • pending resolved rejected
  • pending --> resolved 或 pending --> rejected
  • 变化不可逆 状态的表现和变化
  • pending状态,不会处罚then 和catch
  • resolved状态,会触发后序的then回调函数
  • rejected状态,会触发后序的catch回调函数
const p1 = new Promise(() => {});
console.log('p1',p1);  // p1 Promise {<pending>}

const p2 = Promise.resolve('100');
console.log('p2',p2)  //p2 Promise {<fulfilled>: '100'}

const p3 = Promise.reject('100');
console.log('p3',p3)  //p3 Promise {<rejected>: '100'}

then和catch对状态的影响

  • then正常返回resolved, 里面有报错则返回rejected
  • catch正常返回resolved, 里面有报错则返回rejected
   // then正常返回resolved, 里面有报错则返回rejected
        const p1 = Promise.resolve().then(() => {
            return 100
        });
        console.log('p1', p1)  // fulfilled 触发then回调
        p1.then(() => {
            console.log('p1 then')  // 打印
        }).catch(() => {
            console.log('p1 catch')
        })


        // then正常返回resolved, 里面有报错则返回rejected
        const p2 = Promise.resolve().then(() => {
            throw new Error('err')
        });
        p2.then(() => {
            console.log('p2 then')
        }).catch(() => {
            console.log('p2 catch')  // 打印
        })
        console.log('p2', p2)  // rejected  触发catch回调

        const p3 = Promise.reject('my error p3').catch((err) => {
            console.log(err)
        })
        console.log('p3',p3) // fulfilled 注意!  触发then 回调
        p3.then(() => {
            console.log('p3 then')  // 打印
        }).catch(() => {
            console.log('p3 catch')
        })

        const p4 = Promise.reject('my error p4').catch((err) => {
            throw new Error('errerr')
        })
        console.log('p4',p4)  // rejected 注意!  触发catch回调
        p4.then(() => {
            console.log('p4 then')
        }).catch(() => {
            console.log('p4 catch')   // 打印
        })  // 返回 fulfilled 的promise

4.场景题 - promise then和 catch连接的问题?

1647158720(1).jpg

结果:1 3

1647158732(1).jpg

结果:1 2 3

1647158744(1).jpg

结果:1 2

5.场景题 - async/await 语法

async/await 和 promise的关系:

  • 和Promise 并不互斥
  • 反而,两者相辅相成
  • 执行async函数,返回的是Promise对象
  • await相当于Promise的then
  • try...catch 可捕获异常,代替了Promise的catch

异步的本质

  • async/await 是消灭异步回调的终极武器
  • js还是单线程,但得是有异步,还得是基于event loop
  • async/await 只是一个语法糖
async function async1() {
    console.log('async1 start'); // 2
    await async2();  // undefined
    // await 的后面,都可以看做是callback 里的内容,即异步
    // 类似event loop,settimeout(callback1)
    // 类似 settimeout(function() {console.log('async1 end'})
    // Promise.resolve().then(() => console.log('async1 end')
    console.log('async1 end');  //5
}

async function async2() {
    console.log('async2) // 3
}

console.log('script starts') // 1
async1()
console.log('script end') //4 同步代码执行完,(event loop 启动)执行异步代码

1647158894.jpg 结果:a = promise fulfilled; b = 100

1647158894.png

结果:start; a 100; b 200; Uncaught (in promise) 300

6. 场景题 - promise 和settimeout 的顺序

1647158994(1).jpg

结果: 100; 400;300;200

7. 场景题 - 外加 async/await 的顺序问题

1647159090(1).jpg

1647159098(1).png

结果:
script start
test.html:56 async1 start
test.html:61 async2
test.html:69 promise1
test.html:74 script end
test.html:58 async1 end
test.html:72 prmise2
test.html:65 setTimeout

知识点:

1.for...of

  • for...in(以及forEach for 是常规的同步遍历
  • for...of常用于异步的遍历
        function muti(num) {
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(num * num)
                },1000)
            })
        }
        const nums = [1, 2, 3];
        nums.forEach(async (item) => {
            const res = await muti(item);
            console.log(res)
        })
        // 执行结果: 一秒后一次性打印出 1 3 9
        
        // 如何依次每隔1秒后打印 1 3 9?
        (async function() {
        for (const item of nums) {
            const res = await muti(item);
            console.log(res)
        }
       })()

2.宏任务macroTask 与微任务microTask

  • 什么是宏任务,什么是微任务
  1. 宏任务: setTimeout setInterval Ajax dom事件
  2. 微任务: Promise async/awiat
  3. 微任务执行时机比宏任务早
  • event loop 和DOM渲染
  1. 再次回归一遍event loop的过程
  2. js是单线程的,而且和dom渲染共用一个线程
  3. js执行的时候,得留一些时机供dom渲染

1647763748(1).jpg evet loop和dom渲染过程:

  • 每次callstack清空(及每次轮询结束),即同步任务执行完
  • 都是dom重新渲染的机会,dom结构如果有改变则重新渲染
  • 然后再触发下一次 Event loop

微任务,宏任务,dom渲染的关系:

  • 微任务在dom渲染之前
  • 宏任务在dom渲染之后
   const $p1 = '<p>这是一段文字</p>';
        const $p2 = '<p>这是一段文字</p>';
        const $p3 = '<p>这是一段文字</p>';
        const container = document.getElementById('container');
        console.log(container)
        container.append($p1)
        container.append($p2)
        container.append($p3)
        console.log('length', container.childNodes.length)
        // 宏任务:Dom渲染后触发
        setTimeout(() => {
            alert('Dom渲染后触发SetTimeout')
        }, 0);
        // 微任务:Dom渲染前触发
        Promise.resolve('Dom渲染前触发,如Promise').then((res) => alert(res))
        alert('本次call stack结束,dom结构已更新,但尚未触发渲染')
        // alert会阻断js执行,也会阻断dom渲染,便于查看效果
        // 这就是js执行和dom 渲染关系

宏任务,微任务和dom渲染,在event loop的过程:

从event loop解释,为何微任务比宏任务执行要早?

1647768342(1).jpg

  • 微任务是es6语法规定的
  • 宏任务是浏览器规定的

1647768426(1).jpg

JS-Web-Api

1.题目一: DOM是那种数据结构

2.题目二:一DOM操作常用api

3.题目三:一次性插入多个DOM节点,考虑性能

4.题目四:attr和property的区别

5.题目五:一次性插入多个DOM节点,考虑性能

6.题目六:如何识别浏览器的类型

7.题目七:分析拆解url各个部分

8.题目八:绑定一个通用的事件绑定函数

function bindEvnt(elem, type, selector, fn) {
    if(fn === null) {
        fn = selector;
        selector = null;
    }
    elem.addEventListener(type, function(event) {
        const target = event.target;
        if(selector) {
            // 代理
            if(target.matches(selector)) {
                fn.call(target, event)
            } 
        } else {
            // 普通绑定
            fn.call(target, event)
        }
        alert(this.innerHTML);
    };
}
const btn1 = document.getElementByIBd('btn1');
bindEvent(btn1, 'click', 'a', function(event) {
    event.preventDefault();
    const target = e.target;
    if(target.nodeName === 'A') {
        alert(target.innerHTML)
    }
});

9.题目九:描述事件冒泡的流程

  • 基于dom树形结构
  • 事件会顺着触发元素网上冒泡
  • 应用场景:代理

10.题目十:无限下拉的图片列表,如何监听每个图片的点击?

  • 事件代理
  • 用e.target获取触发元素
  • 用matches来判断是否是触发元素

11.题目十一:手写一个简易的ajax

function ajax(url) {
    const p = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadyStateChange = function() {
            if(xhr.readyState === 4){
                if(xhr.status === 200) {
                    resolve(JSON.parse(xhr.responseTest))
                } else if(xhr.status === 404){
                    reject(new Error('404 not found))
                }
            }
        }
        xhr.send(null)
    })
    return p;
}

const url = '/data/test.json';
ajax(url)
.then(res => {
     console.log(res)
})

12.题目十二:跨域的常用实现方式

  • JSONP
  • CORS

13.题目十三:描述cookie loaclStorage sessionStorage?

  • 容量的区别
  • API易用性
  • 是否跟随http请求发送出去

知识点:

1.DOM (document object model)

DOM本质: html语言和html文件解析出来的一棵树(dom树)

DOM节点操作

var div1 - document.getElementById('div1'); // 元素
var divs = document,getElementByTagName('div'); //集合
var container = document.getElementByClassName('container'); // 元素
var pList = document.querySelectAll('p');// 集合

DOM的property / attribute

  • property属性:修改对象属性,不会体现到HTML结构中
  • attribute属性:修改html属性,会体现到html结构中(一定会触发dom重新渲染)
  • property / attribute都可能引发dom重新渲染 (nodeType: 0 文本节点 1 元素)
var pList = document.querySelectAll('p');// 集合
var p = pList[0];
console.log(p.style.width); // 获取样式
p.style.width = '10px'; // 修改样式
console.log(p.className);  // 获取className
p.className = 'p1';

// 获取nodeName 和 nodeType
console.log(p.nodeName); // p
console.log(p.nodeType); // 1

// 修改attribute
p.setAttribute('className','list')
p.setAttribute('data', 'data1')
p.setAttribute('style', 'font-size: "12px"')

DOM结构操作

// 新增/插入节点
const div1 = document.getElementById('div1');

// 添加新节点
const p1 = document.createElement('p');
p1.innertHTMl = '新增子元素';
div1.appendChild(p1); // 插入新节点元素

// 获取父元素
console.log(p.parentNode)

// 获取子元素
console.log(div1.childNodes)

// 过滤p标签
 const pNodes =Array.prototype.slice.call(div1.childNodes)
 .filter(child => {
   if(child.nodeType == 1 ) {
       return true;
   }
   return false;
})

// 删除节点
div1.removeChild(p1);

DOM性能

  • dom操作非常昂贵,避免频繁的dom操作
  • 对dom查询作缓存
// 不做缓存
for(var i = 0; i<document.getElementByTagName('p').length; i++) {
 // 每次循环都会计算length,频繁进行dom查询
}

// 缓存dom查询结果
const pList = document.getElementByTagName('p');
const length = pList.length;
for(var i = 0; i<length; i++) {
 // 缓存length,只进行一次dom查询
}
  • 频繁操作改为一次性操作

image.png

2.BOM(browser object model)

navigator

// navigator
const ua = navigator.userAgent;
const isChrome = ua.indexOf('chrome');
console.log(isChrome)

// screen
console.log(screen.width)
console.log(screen.height)

screen location

// 获取网址
location.href // https://baidu.com/try/try.php?name=sdfds#PART2
// 获取协议
location.protocl // https
// 获取主机名称和端口号
location.host //  baidu.com
// url上获取参数
location.search // ?name=sdfdsf
// URL 的锚部分
location.hash. // #PART2
// URL 的路径部分
location.pathname  //    /try/try.php
// 

history

// 回退
history.back()  
// 前进
history,forward()

3.事件绑定

事件绑定

// 通用的事件绑定函数
function bindEvnt(elem, type, fn) {
    elem.addEventListener(type,fn)
}
const btn1 = document.getElementByIBd('btn1');
bindEvent(btn1, 'click', function(event) {
    console.log(event.target) //  获取触发元素
    event.preventDefault(); // 阻止默认行为
});

事件冒泡

const btn1 = document.getElementByIBd('btn1');
bindEvent(btn1, 'click', function(event) {
    console.log(event.target) //  获取触发元素
    event.stopPropagation(); // 阻止事件冒泡
});

事件代理

  • 基于事件冒泡机制,将事件绑定到父元素上
  • 代码简介
  • 减少浏览器内存占用
  • 但是,不要滥用
const btn1 = document.getElementByIBd('btn1');
bindEvent(btn1, 'click', function(event) {
    event.preventDefault();
    const target = e.target;
    if(target.nodeName === 'A') {
        alert(target.innerHTML)
    }
});

4.ajax

XMLHttpRequest

const xhr = XMLHttpRequest();
xhr.open('GET','/api',true); // true 异步请求,false 同步请求
xhr.onreadystatechange = function() {
   // 这里的函数异步执行,可参考之前JS基础中的函数模块
   if(xhr.readyState == 4) {
       if(xhr.status === 200) {
           alert(xhr.responseTest);
       } else {
           console.log('其他情况')
       }
   }
}
xhr.send(null);

const xhr = XMLHttpRequest();
xhr.open('POST','/api',true);
xhr.onreadystatechange = function() {
   // 这里的函数异步执行,可参考之前JS基础中的函数模块
   if(xhr.readyState == 4) {
       if(xhr.status === 200) {
           alert(xhr.responseTest);
       } else {
           console.log('其他情况')
       }
   }
}
const postData = {
    userName: 'zhangsan',
    password: 'xxx'
};
xhr.send(postData)

状态码 xhr.readyState: (存有 XMLHttpRequest 的状态。从 0 到 4 发生变化)

  • 0 - 未初始化,还没有调用send()方法
  • 1 - 载入,已调用send()方法,正在发送请求
  • 2 - 载入完成,send()方法执行完成,已经接收到去全部响应内容
  • 3 - 交互,正在解析响应内容
  • 4 - 完成,响应内容解析完成,可以在客户端调用

xhr.state:

  • 2xx - 表示成功处理请求,如200
  • 3xx - 需要重定向,浏览器直接跳转,如301(永久重定向) 302(临时重定向)304(资源未改变)
  • 4xx - 客户端请求错误,如403 404
  • 5xx - 服务器端错误

跨域:同源策略

  • 同源策略 ajax请求时,浏览器要求当前页面和server必须同源(域名,协议,端口号三者必须一致)安全。
如:前端:http://a.com:8080    server: https//b.com/api/xx

加载图片css js可无视同源策略:

<img src="跨域的图片地址" />  // 图片可以服务器端做访问现在
<link href="跨域的css地址" />
<script src="跨域的js地址" > </script>

利用加载图片css js可无视同源策略:

  1. img可用于统计打点,可使用第三方统计服务器
  2. link可以使用cdn,cdn一般都是外域
  3. script 可以实现jsonp
  • 什么是跨域
  1. 所有的跨域,必须经过server端允许和配合
  2. 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
  3. JSONP
  4. CORS(服务器支持) 跨域的解决方案
  • JSONP
  1. script可绕过跨域限制
  2. 服务器可以任意拼接数据返回
  3. 所以script 就可以获得跨域的数据,只要服务端愿意返回 image.png
abc:[12,2]
window.abc = function(data) {
    console.log(data)
}
<script src="https://xxxxx?callback=abc"></script>

image.png

  • CORS(服务器支持)
// 第二个参数填写允许跨域的域名称,不建议直接写“*”
response.setHeader('Access-Control-Allow-Origin','https://locakhost:9090');
response.setHeader('Access-Control-Allow-Headers','X-Requested-With');
response.setHeader('Access-Control-Allow-methods','PUT,POST,GET,DELETE,OPTIONS');

// 接受跨域的cookie
response.setHeader('Access-Control-Allow-Credentials','true')
  • 常见的请求库
  1. jquery 的ajax image.png
  2. fetch api
  3. axios

5.存储

  • cookie
  1. 本身基于浏览器和server通讯,
  2. 被“借用”到本地存储来,
  3. 可以通过document.cookie='a=100,b=366'修改
  4. 每次修改,是追加和覆盖的过程 cookie缺点:
  5. 存储大小,最大只有4kb
  6. http请求时需要发送到服务器端,增加请求数据量
  7. 只能用document.cookie = '....'来修改,🇹太过简陋 localStorage和sessionStorage:
  8. HTML5专门为存储而设计,最大可存5M
  9. API简单易用 setItem getItem
  10. 不会随着http请求被发送出去
  11. locationStorage数据会永久存储,除非代码或手动删除
  12. sessionStorage数据只会存在当前会话,浏览器关闭则清空
location.setItem('a',200);
location.getItem('a);

HTTP面试题

1. http常用的状态码有哪些?

状态码分类:

  • 1xx 服务器收到请求
  • 2xx 请求成功,如200
  • 3xx 重定向,如302
  • 4xx 客户端错误,404
  • 5xx 服务端错误,50 常见状态码:
  • 200 成功
  • 301 永久重定向(配合location,浏览器自动处理)
  • 302 临时重定向(配合location,浏览器自动处理)
  • 304 资源未被修改
  • 404 资源未找到
  • 403 没有权限
  • 500 服务器错误
  • 504 网关超时 image.png 302状态配合location重定向

关于协议和规范:

  • 就是一个约定
  • 要求大家都跟着执行 不要违反规定,例如IE浏览器

2. http常用的methods有哪些?

传统的methods:

  • get获取服务器的数据
  • post向服务器提交数据
  • 简单的页面功能,就这两操作 现在的methods:
  • get获取数据
  • post新建数据
  • patch/put更新数据
  • delete删除数据

3. 什么是Restful Api?

  • 一种新的API设计方法(早已推广使用)
  • 传统API设计:把每个url当做一个功能
  • Restful API设计:把每个url当做一个唯一的资源 如何设计成一个资源?
  • 尽量不用url参数 传统API设计: /api/list?pageIndex=2

RestFul API设计: /api/list/2

  • 用method表示操作类型 传统的method操作:

post 请求 /api/create-blog

patch 请求 /api/update-blog?id=100

get 请求 /api/get-blog?id=100

RestFul的method操作:

post 请求 /api/blog

patch 请求 /api/blog/100

get 请求 /api/create/100

4. http常用的headers有哪些?

常见的Request Headers

  • Accept浏览器可接收的数据格式
  • Accept-Encoding浏览器可接收的压缩算法,如gzip
  • Accept-Language 浏览器可接收的语言,如zh-CN
  • Connection: keep-alive 一次TCP连接重复使用
  • cookie(同域请求浏览器会自动携带cookie)
  • Host (请求的域名是什么)
  • User-Agent(简称UA)浏览器信息
  • Content-type发送数据的格式,如application/json 常见的Response Headers
  • Content-type发送数据的格式,如application/json
  • Content-length 返回数据的大小,多少字节
  • Content-Encoding返回数据的压缩算法,如gzip
  • set-Cookie,修改客户端cookie 自定义header image.png 缓存相关的headers
  • Cache-Control max-age最大过期时间
    no-cache不缓存
    no-store不用强制缓存,也不用服务端缓存,直接返回数据 private允许最终用户缓存,电脑 手机 public允许中间代理,路由缓存
  • Expires 同在response headers中
    同为控制缓存过期
    已被cache-control代替
  • Last-Modified If-Modified-Since
  • Etag If-None-Match

5. 描述一下http缓存机制(重要)?

1. 关于缓存的介绍

  • 什么是缓存? 没有必要重新获取的,不重新获取,暂存一份,不浪费资源
  • 为什么要缓存? 通过缓存,减少网络请求的体积和数量。
  • 那些资源可以被缓存?如静态资源 img js css

2. http缓存策略(强缓存 + 协商缓存)

webpack打包,打包文件生成hash值,当文件修改生成新的hash时,浏览器缓存会更新 image.png

image.png

强缓存

  1. 浏览器第一次访问,请求资源时,服务端判定那些资源可以被缓存,会加上cache-Control image.png

image.png image.png

  1. 第二次访问浏览器,如果本地有缓存,则直接返回 image.png

本地缓存 image.png 3.第三次访问,如果缓存失效,会再次发起http请求

image.png

协商缓存

  • 服务器端缓存策略
  • 服务器判断客户端资源,是否和服务端资源一样
  • 一致则返回302,否则返回200和最新的资源

image.png

资源标识有哪些?

  1. 在Response Headers中,有两种
  2. Last-Modified资源的最后修改时间
  3. Etag资源的唯一表示(一个字符串,类似人类的指纹)

image.png

image.png

image.png

image.png

image.png

last-Modified 和Etag

  1. 会优先使用Etag
  2. Last-Modified只能精确到秒级
  3. 如果资源被重复生成,而内容不变,则Etag更精确

3. 刷新操作方式,对缓存的影响:

  • 正常操作:地址栏输入url,跳转连接,前进后退等 强制缓存有效,协商缓存有效
  • 手动刷新:F5, 点击刷新按钮,右击菜单刷新 强制缓存失效,协商缓存有效
  • 强制刷新: ctrl + f5 强制缓存失效,协商缓存失效

开发环境

git

image.png image.png

调试工具

抓包

  • 移动端h5页,查看网络请求,需要用抓包工具
  • windows一般用fiddler
  • max os 一般用charles 抓包过程:
  • 手机和电脑必须同一个局域网
  • 将手机代理到电脑上
  • 手机浏览网页,即可抓包
    抓包内容:
  • 查看网络请求
  • 网址代理
  • https

webpack babel

  • ES6 模块化,浏览器暂不支持
  • ES6 语法,浏览器并不完全支持
  • 压缩代码,整合代码,以让网页加载更快
初始化环境: npm init -y  
安装webpack : npm i webpack webpack-cli

linux常用命令

运行环境

运行环境即浏览器(server端有nodeJs)

下载网页代码,渲染出页面,期间会执行若干JS

保证代码在浏览器中:稳定且高效

网页的加载过程

题目1:从输入url到渲染出页面的整个过程?

  • 下载资源;各个资源类型,下载过程
  • 渲染页面:结合html css js 图片等

题目2:window.onload 和DOMContentLoaded的区别?

  • window.onload 资源全部加载完成才执行,包括图片
  • DOMContentLoaded ODM渲染完成即可,图片可能尚未下载

知识点:

1.加载资源的形式
  • html代码
  • 媒体文件,图片视频等
  • JavaScript css
2.加载资源过程
  • DNS解析:域名 -> IP地址
  • 浏览器根据IP地址向服务器发起http请求
  • 服务器处理http请求,并返回给浏览器
3.渲染页面的过程
  • 根据HTML代码生成DOM Tree
  • 根据css代码生成CSSOM
  • 将DOM Tree 和CSSOM整合形成Render Tree
  • 根据Render Tree 渲染页面
  • 遇到Script 则暂停渲染,优先加载并执行JS代码,完成再继续
  • 直至把Render Tree渲染完成 网页加载监听:

window.onload 和 DOMContentLoaded

window.addEventListenter('load',function() {
    // 页面全部资源加载完成才会执行,包括图片,视频等
})
window.addEventListenter('DOMContentLoaded',function() {
    // DOM 渲染完即可执行,此时图片,视频还可能没有加载完
})

性能优化:

  • 手写防抖,节流
  • 多使用内存,缓存或其他方法
  • 减少CUP计算量,减少网络加载耗时
  • 适用于所有编程的性能优化-----空间换时间
1.让加载更快
  • 减少资源体积:压缩代码
  • 减少访问次数:合并代码,SSR服务器渲染,缓存
  • 使用更快的网络: CDN

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

2.让渲染更快
  • css放在head,js放在body最下面
  • 尽早开始执行js,用DOMContentLoaded触发
  • 懒加载(图片懒加载,上滑加载更多)
  • 对DOMchaxun进行缓存
  • 频繁DOM操作,合并到一起插入DOM结构
  • 节流throttle 防抖 debounce 节流防抖 image.png
<input id="input1" />
const input1 = document.getElementById('input1');
let timer;
input1.addEventListener('keyup',function() {
  if(timer) {
     clearTimeout(timer)
  }
  timer = setTimeout(() => {
      console.log(input1.value)
      // 清空定时器
      timer = null;
  },500)
})
<input id="input1" />
const input1 = document.getElementById('input1');
/** 
* @desc 函数防抖 
* @param func 回调函数 
* @param wait 延迟执行毫秒数 
*/ 
function debounce(func, wait) { 
    let timeout; 
    return function () { 
        let context = this; 
        let args = arguments; 
        //如果timeout存在,先清除定时器(其实就是每次执行都清除定时器,判断是否存在只是为了严谨) 
        timeout?clearTimeout(timeout):null; 
        timeout = setTimeout(() => { 
            //是为了让 debounce 函数最终返回的函数 this 指向不变以及依旧能接受到 e 参数。 
            //不使用apply绑定this func执行时this是window 
            func.apply(context, args) 
        }, wait);
     } 
 } 
 document.body.onclick= debounce(function () { console.log(this) },1000)


input1.addEventListener('keyup',debounce(() => {
  console.log(input1.value)
}, 9000))

image.png

const div1 = document.getElementById('div1');

function throttle(fn, delay = 500) {
   let timer;
   return function() {
      if(timer) {
        return;
      }
     timer = setTimeout(() => {
         fn.apply(this, arguments);
         timer = null
     },delay)
   }
}

div1.addEventListener('click', throttle(() => {
  console.log(1)
}, 5000));

安全

常见web前端攻击方式有哪些?

  • XSS 跨站请求攻击

image.png

image.png

  • XSRF 跨站请求伪造