updating...

CSS

1、三栏布局问题(左右固定宽度 中间自适应)

flex
.container { display: flex; } .left, .right { width: 200px } .middle { flex: 1; } 优点:比较完美 移动端首选; 缺点:不兼容 ie9 及以下;
grid
.container { display: grid; grid-template-columns: 200px auto 200px; } 优点:简单强大 解决二维布局问题; 缺点:不兼容 ie9 及以下,很多国产手机浏览器有兼容问题;
float + margin
.container { overflow: hidden; } .left { float:left; height:100%; width:200px; } .right { float:right; height:100%; width:200px; } .middle{ height:100%; margin:0 200px; } 优点:快捷 简单 兼容性较好; 缺点: 有局限性 脱离文档流 需要清除浮动等;

2、CSS 盒模型

margin-area: 外边距区域;
border-area: 边框区域;
padding-area: 内边距区域;
content-area: 内容区域;

标准盒模型和 IE 盒模型:
标准盒模型: box-sizing 值为 content-box 时,在高度和宽度之外绘制内外边距以及边框;
IE盒模型:box-sizing 值为 border-box 时,内边距和边框在已设置的宽高内绘制;


3、BFC

BFC(Block Formatting Context)块级格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。

形成条件:

  • 浮动元素,float 除 none 以外的值;
  • 定位元素,position(absolute,fixed);
  • display 为以下其中之一的值 inline-block,table-cell,table-caption;
  • overflow 除了 visible 以外的值(hidden,auto,scroll);

特征:

  • 内部的 Box 会在垂直方向上一个接一个的放置;
  • 垂直方向上的距离由margin 决定;(解决外边距重叠问题)
  • bfc 的区域不会与 float 的元素区域重叠;(防止浮动文字环绕)
  • 计算 bfc 的高度时,浮动元素也参与计算;(清除浮动)
  • bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素;

4、外边距重叠

块的上外边距(margin-top)和下外边距(margin-bottom)有时合并(折叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为边距折叠

注意有设定float和position=absolute的元素不会产生外边距重叠行为。

相关文章:MDN 文档


DOM

1、DOM 事件级别

DOM 0级:

写法:el.οnclick=function(){}
DOM 0事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的。

DOM 2级

写法:el.addEventListener(event-name, callback, useCapture)
event-name: 事件名称,可以是标准的DOM事件;
callback: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event;
useCapture: 默认是false,代表事件句柄在冒泡阶段执行;

DOM 3级

写法和DOM2级一致 只是在DOM 2级事件的基础上添加了更多的事件类型
新增事件:

  • UI事件,当用户与页面上的元素交互时触发,如:load、scroll;
  • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus;
  • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup;
  • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel;
  • 文本事件,当在文档中输入文本时触发,如:textInput;
  • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress;
  • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart;
  • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified;

2、事件模型 事件流

事件模型: 捕获和冒泡;
事件流:

  • 捕获阶段:事件从 window 对象自上而下向目标节点传递阶段;
  • 目标阶段:目标节点处理对应事件;
  • 冒泡阶段:事件从目标节点向 window 对象自下而上传播阶段;

3、事件代理

由于在冒泡阶段事件从下而上传播,因此可以将子节点的监听函数放置在父节点上,统一处理子节点的事件。减少内存消耗,提高性能(不需要为每一个子元素绑定事件)。


4、Event 对象

阻止默认行为:

event.preventDefault()

阻止冒泡:
  • event.stopPropation 阻止事件冒泡到父元素
  • event.stopImmediatePropation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发
target 和 currentTarget:

currentTarget始终是监听事件者,而target是事件的真正发出者。


5、自定义事件

// 创建事件:
// event 不能传参
let event = new Event('eventName')
// CustomEvent是可以传递参数的
let customEvent = new CustomEvent('eventName',  {})
// 监听事件
/*
*  addEventListener(event, function, useCapture)
*  useCapture 指定事件是否 在捕获或冒泡阶段执行;
*      true - 事件在捕获阶段执行
*      false- 默认,事件在冒泡阶段执行
*/
dom.addEventListener('eventName', function (e) {...}, false)

// 触发事件
dom. dispatchEvent('eventName')


JavaScript

1、JavaScript 单线程

js 作为浏览器脚本语言,其主要用途是与用户互动,以及操作DOM。如果存在多个线程就会有很复杂的同步问题,例如:一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

2、JavaScript 同步任务与异步任务

由于 js 单线程的特点,每次只能执行单个任务。如果前序任务始终没有结束,后序的任务只能等待,效率较低。所以增加了同步任务和异步任务的区分。

  • 同步任务:在主线程上排队执行的任务,需要按顺序一一执行;
  • 异步任务:不进入主线程而是进入任务队列,只有通知主线程任务可以被执行时,才会加入主线程执行;

3、Event-Loop 事件轮询:

Javascript 的“线程”有一种机制:在每次调用 JS 引擎时,可以随着时间的推移执行你的程序的多个代码块儿,这称为“事件轮询(Event Loop)。

JavaScript 实现异步的具体方式:
  • 同步代码直接执行
  • 异步函数放置到异步队列中
  • 同步代码执行完毕,异步队列轮询执行

宏任务与微任务

宏任务:

分类:

函数 浏览器 node
I/O
setTimeout
setInterval
setImmediate
requestAnimationFrame

特性:

  • 宏任务所在的队列就是宏任务队列;
  • 第一个宏任务队列中只有一个任务:执行主线程上的JS代码;如果遇到上方表格中的异步任务,会创建出一个新的宏任务队列,存放这些异步函数执行完成后的回调函数;
  • 宏任务中可以创建微任务,但是在宏任务中创建的微任务不会影响当前宏任务的执行;
  • 当一个宏任务队列中的任务全部执行完后,会查看是否有微任务队列,如果有就会优先执行微任务队列中的所有任务,如果没有就查看是否有宏任务队列;
微任务:

分类:

函数 浏览器 node
process.nextTick
mutionObserver
promise.then/catch/finally

mutionObserver:

  • 用来监视 DOM 变动
  • 等待所有脚本任务完成后,才会运行,即采用异步方式
  • 把 DOM 变动记录封装成一个数组进行处理,而不是一条条地个别处理 DOM 变动
  • 即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动
经典面试题
console.log(1);

setTimeout(()=>{
    console.log(2);
    new Promise((resolve,reject)=>{
    console.log(3);
    resolve()
}).then(res=>{
    console.log(4);
})
})

new Promise((resolve,reject)=>{
    resolve()
}).then(res=>{
    console.log(5);
}).then(res=>{
    console.log(6);

})

new Promise((resolve,reject)=>{
    console.log(7);
    resolve()
}).then(res=>{
    console.log(8);
}).then(res=>{
    console.log(9);

})

setTimeout(()=>{
    console.log(10);
    new Promise((resolve,reject)=>{
    console.log(11);
    resolve()
}).then(res=>{
    console.log(12);
})
})

console.log(13);

输出结果:
依次 1、7、13、5、8、6、9、2、3、4、10、11、12

4、创建对象:

  • 字面量方式(简单,运行速度更快)
let obj = { test: a}
  • 构造函数
function Test () {
    this.test =  a
}
let obj = new Test()
  • Object.create(proto, [propertiesObject])
//Object.create()方法创建的对象时,属性是在原型下面的
let obj = Object.creat({test: a})

5、原型链:

原型链和原型对象是js的核心,原型链保证函数或对象中的方法、属性可以让向下传递,js通过原型链才得以实现函数或对象的继承

prototype 和 constructor:

prototype 指向函数的原型对象,只有函数才拥有该属性。
constructor 指向原型对象的构造函数。


_proto_:

每个对象都有 proto,指向了创建该对象的构造函数原型。由于js中是没有类的概念,而为了实现继承,通过 proto 将对象和原型联系起来组成原型链,就可以让对象访问到不属于自己的属性。

Foo、Function 和 Object 都是函数,它们的 proto 都指向 Function.prototype.

原型对象 _proto_都指向了 Object.prototype,js原型链最终指向的是 Object 原型对象。


总结

实例的 _proto_ 指向原型对象的 prototype,实例远行对象的 _proto_ 是 Object 的原型对象(null 除外)


image.png

举例:

  • instanceof 原理

  • new运算符原理
    1、创建一个新对象;
    2、将空对象的 _proto_ 指向构造函的 prototype;
    3、使用apply调用构造器函数,属性和方法被添加到 this 引用的对象中;
    4、如果构造函数中没有返回其它对象,那么返回 this,即创建的这个的新对象,否则,返回构造函数中返回的对象;
function _new(func) {
    // 第一步 创建新对象
    let obj= {};
    // 第二步 空对象的_proto_指向了构造函数的prototype成员对象
    obj.__proto__ = func.prototype;//
    // 一二步合并就相当于 let obj=Object.create(func.prototype)

    // 第三步 使用apply调用构造器函数,属性和方法被添加到 this 引用的对象中
    let result = func.apply(obj);
    if (result && (typeof (result) == "object" || typeof (result) == "function")) {
    // 如果构造函数执行的结果返回的是一个对象,那么返回这个对象
        return result;
    }
    // 如果构造函数返回的不是一个对象,返回创建的新对象
    return obj;
}

5、继承实现:

声明父类:

function Father(name) {
      this.name = name || "father";
      this.sayName = function() {
        console.log(this.name);
      }
      this.color = ["red", "blue"]
}

Father.prototype.age = 18;
Father.prototype.sayAge = function() {
      console.log(this.age)    
}
1) 原型链继承
function Son(name) {
    this.name = name || 'son'
}

Son.prototype = new Father()

优点:

  • 简单易于实现;
  • 父类新增的属性和方法,子类都可以访问到;

缺点:

  • 无法实现多继承,因为原型一次只能被一个实例更改;
  • 来自原型对象的所有属性被所有实例共享;
  • 创建子类实例时,无法向父构造函数传参;
2)构造继承:复制父类的实例属性给子类
function Son(name) {
    Father.call(this, '父级需要的参数')
    this.name = name
}

let s = new Son("son");
console.log(s.name); // son
//s.sayAge(); // 抛出错误(无法继承父类原型方法)
 s.sayName(); // son
console.log(s.age); // undefined (无法继承父类原型属性)
console.log(s instanceof Father); // false
console.log(s instanceof Son); // true

优点:

  • 解决了原型链继承中子类实例共享父类引用属性的问题;
  • 创建子类实例时,可以向父类传递参数;
  • 可以实现多继承(call多个父类对象);

缺点:

  • 实例并不是父类的实例,只是子类的实例;
  • 只能继承父类实例的属性和方法,不能继承其原型上的属性和方法;
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能;
3)原型链、构造函数组合继承

使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。

function Son(name) {
   // 第一次调用父类构造器 子类实例增加父类实例
    Father.call(this, "我是传给父类的参数");
    this.name = name || "son";
}
// 经过new运算符 第二次调用父类构造器 子类原型也增加了父类实例
Son.prototype = new Father();

let s = new Son("son");
console.log(s.name); // son
s.sayAge(); // 18
s.sayName(); // son
console.log(s.age); // 18
console.log(s instanceof Father); // true
console.log(s instanceof Son); // true
console.log(s.constructor === Father); // true
console.log(s.constructor === Son); // false

优点:

  • 弥补了构造继承的缺点,现在既可以继承实例的属性和方法,也可以继承原型的属性和方法;
  • 既是子类的实例,也是父类的实例;
  • 可以向父类传递参数;
  • 函数可以复用;

缺点:

  • 调用了两次父类构造函数,生成了两份实例;
  • constructor指向问题;
4)*寄生组合继承:

通过寄生方式,砍掉父类的实例属性,避免了组合继承生成两份实例的缺点;

function Son (name) {
    let f = Father.call(this, '传递给父级的参数')
    f.name = name || 'son'
}

# 借用Object.create()方法
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son

# 自己动手创建一个中间类
// (function() {
//   let NoneFun = function() {};
//   NoneFun.prototype = Father.prototype;
//   Son.prototype = new NoneFun();
//   Son.prototype.constructor = Son;
// })();

let s = new Son("son");
console.log(s.name); // son
s.sayAge(); // 18
s.sayName(); // son
console.log(s.age); // 18
console.log(s instanceof Father); // true
console.log(s instanceof Son); // true
console.log(s.constructor === Father); // false
console.log(s.constructor === Son); // true

优点:

  • js实现继承首选方式;

缺点:

  • 实现较复杂(可通过Object.create简化);
5)实例继承:为父类实例添加新特征,作为子类实例返回
function Son (name) {
    let f = new Father('传递给父级的参数')
    f.name = name || 'son'
    return f
}

let s = new Son("son"); //或者直接调用子类构造函数 let s = Son("son");
console.log(s.name); // son
s.sayAge(); // 18
s.sayName(); // son
console.log(s.age); // 18
console.log(s instanceof Father); // true
console.log(s instanceof Son); // false
console.log(s.constructor === Father); // true
console.log(s.constructor === Son); // false

优点:

  • 不限制调用方式,不管是new 的方式声明子类还是通过直接调用函数方法声明,返回的对象具有相同的效果;

缺点:

  • 实例是父类的实例,不是子类的实例;
  • 不支持多继承;
6)拷贝继承:对父类实例中的的方法与属性拷贝给子类的原型
function Son (name) {
    let f = new Father('要传给父级的数据')
    for (let k in f) {
        Son.prototype[k] = f[k]
    }
    Son.prototype.name = name
}

let s = new Son("son");
console.log(s.name); // son
s.sayAge(); // 18
s.sayName(); // son
console.log(s.age); // 18
console.log(s instanceof Father); // false
console.log(s instanceof Son); // true
console.log(s.constructor === Father); // false
console.log(s.constructor === Son); // true

优点:

  • 支持多继承;

缺点:

  • 效率低,性能差,占用内存高(因为需要拷贝父类属性);
  • 无法获取父类不可枚举的方法(不可枚举的方法,不能使用for-in访问到);
7)ES6 Class 继承
class Son extends Father {
constructor(name) {
    super(name);
        this.name = name || "son";
      }
 }

let s = new Son("son");
console.log(s.name); // son
s.sayAge(); // 18
s.sayName(); // son
console.log(s.age); // 18
console.log(s instanceof Father); // true
console.log(s instanceof Son); // true
console.log(s.constructor === Father); // false
console.log(s.constructor === Son); // true

6、节流和防抖

节流:一定时间内执行的操作只执行一次。

应用场景:

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次);
  • 监听滚动事件,比如是否滑到底部自动加载更多(懒加载);
function throttle (fn, timer) {
    let canRun = true
    return function () {
        if ( !canRun ) return 
        canRun = false
        setTimeout(() => {
            fn().apply(this, arguments)
            canRun = true
        }, timer)
    }
}
防抖:动作停止后的时间超过设定的时间时执行一次函数。注意:这里的动作停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。如果你一直在触发这个函数并且两次触发间隔小于设定时间,则函数一直不会执行.

应用场景:

  • 搜索栏用户输入结束后,请求联想数据;
  • window resize时,页面不断调整会不断触犯;
function debance (fn, delayTime) {
    let timer = null
    return function () {
        if (timer) {
            clearTimeout(timer)      
        } 
        timer = setTimeout(() => {
            fn.call(this, arguments)
        },  delayTime)
    }
}

HTTP 相关


框架 Framework

1、SSR 框架的选择, Nuxt、Next、Nest?

Next:性能居中,lighthouse 测试报告中比其他两者低。
优势:

  • 默认情况每一个组件都是服务端渲染;
  • 自动代码拆分,加快页面加载速度;

缺点:

  • 数据会在客户端和服务器重复加载;

Nuxt:性能为三者中最低,lighthouse 测试报告中的大多项都是领先者。
优点:

  • 主要范围是UI渲染,同时抽象出客户端/服务器分布;
  • 项目结构清晰;
  • 路由级别的异步数据获取;

缺点:

  • 周边资源较少;
  • 高流量可能会给服务器带来压力;

Nest:性能是三者中最好的,lighthouse 测试报告得分较低。
优点:

  • 基于TypeScript的Web框架,可以进行严格的类型定义;
  • 自动生成Swagger文档;
  • 为开发人员提供更少的上下文切换。从Angular代码到Nest的过渡相对容易;

缺点:

  • 缺少文档;
  • 与其他框架相比,Nest的社区规模较小;

参考文章:原文链接

你可能感兴趣的:(updating...)