chenfei-hnu / Blog

个人整理的跟前端相关的文档 ( This is some front-end development related documentation )
9 stars 2 forks source link

前端其他知识总结 #17

Open chenfei-hnu opened 5 years ago

chenfei-hnu commented 5 years ago

1. 类型区分

Object.prototype.toString.apply 用于区分基本数据类型及原生引用类型,获取的是该对象内部属性[[Class]]值 低版本IE可能存在部分返回其他类型也返回[object Object]的情况 [object Object]自定义对象 [object Array]数组 [object String]字符串 [object Number]数字 [object Boolean]布尔值 [object Function]函数 [object Date]日期 [object RegExp]正则表达式 [object Arguments]Arguments对象 [object Error]原生Error对象 [object Map]es6原生Map对象 [object Set]es6原生Set对象

[object JSON]JSON对象 [object Math]Math对象

[object Null]null [object Undefined]undefined

Function Array等Object子类都有重写toString方法

typeof 只能区分基本数据类型,特殊的 null会被判断为object,可以判断函数为function number、string、undefined、boolean、null、symbol

使用instanceof 判断对象是否是类的实例 new Date() instanceof Date

function isArray(obj) {
    return "[object Array]" === Object.prototype.toString.apply(obj)
}

function isObject(obj) {
    return (!!obj && "object" === typeof obj) || || typeof obj === "function"
}

function isNumber(obj) {
    return "number" == typeof t && obj === obj //考虑NaN的情况
}

——————————————————————

2.数组去重

使用Set去重[...new Set(arr)]

特殊判断NaN及对象,使用临时对象将类型+值作为键值判断是否存在

Array.prototype.uniq = function () {
    if (!this.length || this.length == 0) return this;
    var res = [], key, hasNaN = false, temp = {};
    for (var i = 0 ; i < this.length; i++) {
        if (typeof this[i] === 'object') {
            res.push(this[i]);
        } else if (this[i] != this[i]) { // 如果当前遍历元素是NaN
            if (!hasNaN) {
                res.push(this[i]);
                hasNaN = true;
            }
        } else {
            key = typeof(this[i]) + this[i];
            if (!temp[key]) {
                res.push(this[i]);
                temp[key] = true;
            }
        }
    }
    return res;
}

使用Array.indexOf判断是否存在,其他只需要判断NaN即可

Array.prototype.uniq = function () {
    var res = [];
    var flag = true;
    this.forEach(function(x) {
        if (res.indexOf(x) == -1) {
            if (x != x) {
                if (flag) {
                    res.push(x);
                    flag = false;
                }
            } else {
                res.push(x);
            }
        }
    })
    return res;
}

——————————————————————

3.函数防抖和函数节流

函数防抖和函数节流都是防止某一时间频繁触发 函数防抖 - 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。 函数节流 - 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

防抖实现

function fn(callback,time){
    let timeout;
    return function(arguments){
        if(timeout){
            clearTimeout(timeout);
        }
        timeout=setTimeout(function(){
            handle(arguments);
        },time);
    }
}
function handle(arguments){
    console.log(new Date().getTime());
}

window.addEventListener("click",fn(handle,2000));

节流实现

function fn(callback,time){
    let lastTime;
    return function(arguments){
        if(!lastTime || (new Date().getTime()-lastTime)>time){
            lastTime=new Date().getTime();
            handle(arguments);
        }
    }
}
function handle(arguments){
    console.log(new Date().getTime());
}
window.addEventListener("click",fn(handle,2000));

——————————————————————

5.HTML语义化和SEO

html语义化让页面的内容结构更清晰,便于对浏览器渲染、搜索引擎解析 方便其他设备解析,即使在没有样式CSS情况下也以一种容易阅读的文档格式显示 便于其他开发人员阅读分块

合理的title、description、keywords 重要内容放在HTML最前面 编写符合W3C规范的语义化HTML代码 重要内容不要用js输出,爬虫不会执行js脚本 使用服务器渲染或者静态化渲染 提高网站加载渲染速度

aside 主要内容的附属信息,最典型的是侧边栏 section 代表文档中的主题分段或页面分组,是和页面其他内容具有关联的 article 在文档页面中自成一体的内容,可以形成独立文档

——————————————————————

7.iframe的缺点

搜索引擎的检索程序无法解读这种页面,不利于SEO iframe会阻塞主页面的onload事件 iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以阻塞主页面请求加载 如果需要使用iframe,最好是通过javascript动态给iframe添加src属性值,绕开以上两个问题

——————————————————————

8.Xhtml和html的区别

主要是XHTML可兼容各种终端的各大浏览器,便于浏览器编解析 XHTML 元素必须被正确地嵌套,闭合,区分大小写,文档必须拥有根元素

——————————————————————

9.严格模式和文档类型

use strict

严格模式是JavaScript中的一种限制性更强的变种模式


限制写法
1.多次定义某个属性
2.使用未定义的变量
3.删除变量、函数
4.无法使用标识符的未来保留字等

严格模式以该浏览器支持的最高标准运行 混杂模式根据浏览器对当前javascript代码的支持程度,采用向后兼容的方式来渲染页面

DOCTYPE声明位于文档中的最前面,一般常规写法以标准模式呈现,如果文档的DOCTYPE不存在或使用浏览器的私有模式写法,就使用混杂模式

——————————————————————

10.svg 和 canvas

svg绘制出来的每一个元素都是独立的DOM节点,便于进行事件监听,canvas输出的是一整幅画布,只能通过canvas的相关API进行内容处理 svg输出的图形是矢量图形,后期可以修改参数来自由放大缩小,不会失真和出现锯齿,canvas输出标量画布,缩放会出现失真,需要重新绘制

——————————————————————

11.Viewport

// width 设置viewport宽度,为一个正整数,或字符串‘device-width’ // device-width 设备宽度 // height 设置viewport高度,一般设置了宽度,会自动解析出高度,可以不用设置 // initial-scale 默认缩放比例(初始缩放比例),为一个数字,可以带小数 // minimum-scale 允许用户最小缩放比例,为一个数字,可以带小数 // maximum-scale 允许用户最大缩放比例,为一个数字,可以带小数 // user-scalable 是否允许手动缩放

——————————————————————

12.WEB字体

WEB字体是一种将图标图片转为字体显示的图片处理方式,它有轻量,文件体积小的特点 WEB字体不同分辨率的终端上进行清晰的显示,还可以随意设置大小和颜色,但不支持多色调

——————————————————————

13.meta


页面基础方面
<!DOCTYPE html>  <!--H5标准声明,使用 HTML5 doctype,不区分大小写-->
<head lang=”en”> <!--标准的 lang 属性写法-->
<meta charset=’utf-8′>    <!--声明文档使用的字符编码-->
<meta name=”viewport” content=”width=device-width,initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no”> <!--为移动设备添加 viewport-->

SEO信息方面
<meta name=”description” content=”不超过150个字符”/>       <!--页面描述-->
<meta name=”keywords” content=””/>     <!-- 页面关键词-->
<meta name=”author” content=”name, email@gmail.com”/>    <!--网页作者-->
<meta name=”robots” content=”index,follow”/>      <!--搜索引擎抓取-->

页面缓存方面
<meta http-equiv=”pragma” content=”no-cache”> <!设置页面不缓存-->
<meta http-equiv=”cache-control” content=”no-cache”>
<meta http-equiv=”expires” content=”0″>

其他的就是浏览器私有属性
<meta name=”apple-mobile-web-app-title” content=”标题”> <!--iOS 设备 begin-->
<meta name=”apple-mobile-web-app-capable” content=”yes”/>  <!--添加到主屏后的标题(iOS 6 新增)是否启用 WebApp 全屏模式,删除苹果默认的工具栏和菜单栏-->
<meta name=”apple-itunes-app” content=”app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL”>
<meta name=”apple-mobile-web-app-status-bar-style” content=”black”/><!--添加智能 App 广告条 Smart App Banner(iOS 6+ Safari)-->
<meta name=”format-detection” content=”telphone=no, email=no”/>  <!--设置苹果工具栏颜色-->

<meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″/>   <!--优先使用 IE 最新版本和 Chrome-->

<meta name=”renderer” content=”webkit”> <!-- 启用360浏览器的极速模式(webkit)-->

<meta http-equiv=”X-UA-Compatible” content=”IE=edge”>     <!--避免IE使用兼容模式-->

<meta http-equiv=”Cache-Control” content=”no-siteapp” />    <!--不让百度转码-->

<meta name=”HandheldFriendly” content=”true”>     <!--针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓-->

<meta name=”MobileOptimized” content=”320″>   <!--微软的老式浏览器-->

<meta name=”x5-orientation” content=”portrait”>    <!--QQ强制竖屏-->
<meta name=”x5-fullscreen” content=”true”>       <!--QQ强制全屏-->

<meta name=”full-screen” content=”yes”>              <!--UC强制全屏-->
<meta name=”screen-orientation” content=”portrait”>   <!--uc强制竖屏-->
<meta name=”browsermode” content=”application”>   <!--UC应用模式-->
<meta name=”x5-page-mode” content=”app”>   <!-- QQ应用模式-->

<meta name=”msapplication-tap-highlight” content=”no”>    <!--windows phone 点击无高亮-->

——————————————————————

14.src和href

请求src资源时会将其指向的资源下载并应用到文档内,替换当前元素,会阻塞页面的其他下载和渲染逻辑 href创建资源和当前元素的链接,并行下载资源并且不会影响浏览器对当前文档的处理

因此@import引用的CSS会等到页面被加载完再加载,link会同时被加载

——————————————————————

15.

Webp:WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式 图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间 在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小40%

Apng:是PNG的位图动画扩展 可以实现png格式的动态图片效果,直到日前得到 iOS safari 8的支持,有望代替GIF成为下一代动态图标准

——————————————————————

17.requestAnimationFrame

由于JavaScript的单线程机制的,所以对于一些JS动画时间处理方面不是很精确,requestAnimationFrame是为满足高性能动画的需求而提供的API,减少卡顿,提升流畅度 setTimeout和setInterval会影响浏览器绘制的频率,让浏览器绘制部分丢失,造成卡顿 requestAnimationFrame()无须设置调用间隔, 它自动紧跟浏览器的绘制的帧率进行渲染,内部实现还有一些其他的自动优化 还可以重写requestAnimationFrame方法,为低版本浏览器使用setTimeout实现动画

var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {// webkit和moz中函数名称兼容
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||    
                                    window[vendors[x] + 'CancelRequestAnimationFrame'];
}

if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
        var currTime = new Date().getTime();
        //为了使setTimteout的尽可能的接近每秒60帧的效果
        var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
        var id = window.setTimeout(function() {
            callback(currTime + timeToCall);
        }, timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    };
}
if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}
function animate() {
    requestAnimationFrame(animate);
    /动画操作代码/
}
animate();

——————————————————————

CCS中的模型

标准盒模型 box-sizing: content-box content padding border margin IE盒模型 box-sizing: border-box width = content + padding + border

定位方案(Positioning schemes)

清除浮动:主要用来解决父元素因为子级元素浮动引起的内部高度为0的问题 闭合浮动:使父元素高度被内部浮动元素撑开,减少浮动带来的影响

BFC 块级格式化上下文

BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素

触发条件

根元素或其它包含它的元素 溢出元素 overflow: hidden/scroll/auto/inherit 浮动 float: left/right/inherit 绝对定位元素 position: absolute/fixed 行内块 display: inline-block 弹性盒子 display: flex/inline-flex 表格单元格 display: table-cell 表格标题 display: table-caption

应用场景

闭合浮动及防止子元素间及父子元素margin重叠

IFC 行级格式化上下文 一个块级元素中仅包含内联级别元素

应用场景 是行级格式化上下文的元素水平垂直居中

FFC 弹性格式化上下文环境

当 display 的值为 flex 或 inline-flex 时,将生成弹性容器, 建立FFC

GFC 表格格式化上下文环境

当为一个元素设置display值为grid的时候,此元素将会获得一个独立的渲染区域

——————————————————————

块级元素和内联元素

块级元素:

前后有换行

可以设置宽高等属性,以及边距,参照盒子模型

内部可以包含其他块级元素,内联元素

宽度默认是父元素的宽度,高度可以设置或者由内容的高度决定

内联元素:

前后不换行

设置元素宽高无效,高度由line-height决定(不设置时由font-size计算得出),宽度由内容的多少决定 当宽度大于父元素的宽度时,内联元素会被折断到下一行,对于内联元素可以设置水平方向的padding,margin等

不能包含其他元素

——————————————————————

inline-block和float的比较

文档流:inline-block不会脱离文档流仍占据正常的位置,但是float的元素会脱离文档流 位置:inline-block根据在文档流中的位置觉得它位置,可以设置居中,float根据它所在的块级格式化上下文中,设置的top,left等属性决定位置 inline-block会将换行看成是空白节点,因此元素之间会出现间隔,使用负值margin,font-size:0解决 inline-block对其他元素基本无特殊影响,float元素会出现环绕

——————————————————————

css3新特性

新增各种css选择器

p:first-of-type:选择属于其父元素的首个

元素 p:last-of-type:选择属于其父元素的最后

元素 p:only-of-type:属于父元素的特定类型的唯一子元素 p:only-child:属于父元素的唯一子元素的每个

元素 p:nth-child(2):选择父元素的第二个子元素 ::after 在元素之前添加内容 ::before 在元素之后添加内容 :enabled 已启用 :disabled 控制表单为禁用状态,不可点击 :checked 单选框或复选框被选中

圆角 border-radius 多列布局 阴影和反射 文字特效text-shadow 线性渐变 CSS3动画 transition:元素在变化过程中的情况,包含transition-property、transition-duration、transition-timing-function、transition-delay。 transform:定义元素的变化结果,包含rotate、scale、skew、translate。 animation:动画定义了动作的每一帧(@keyframes)有什么效果,包括animation-name关键帧的名称,animation-duration动画时长、 animation-timing-function动画速度、animation-delay延迟时间、animation-iteration-count重复次数(无限次infinite)、animation-direction是否反向播放 关键帧直接覆盖css样式 @keyframes move { 0% { width: 100px; } 100% { width: 200px; } } content属性专门应用在 before/after伪元素上,用于来插入生成内容。最常见的应用是利用伪类清除浮动

css动画与js动画对比

CSS3有兼容性问题,而JS大多时候没有兼容性问题 css3动画性能通常高于JS动画,浏览器会对CSS3的动画做一些优化 CSS3比JS更简单,性能调优方向固定,但JS可以实现更复杂的动画效果 css3动画粒度粗,而JS的动画粒度控制可以很细,可以更加灵活

css3实现轮播图例子

.ani{
  width:480px;
  height:320px;
  margin:50px auto;
  overflow: hidden;
  box-shadow:0 0 5px rgba(0,0,0,1);
  background-size: cover;
  background-position: center;
  animation: loops 20s infinite;
}
@keyframes "loops" {
    0% {
        background:url(1.jpg) no-repeat;             
    }
    25% {
        background:url(2.jpg) no-repeat;
    }
    50% {
        background:url(3.jpg) no-repeat;
    }
    75% {
        background:url(4.jpg) no-repeat;
    }
    100% {
        background:url(5.jpg) no-repeat;
    }
}

——————————————————————

23.

sass/less,CSS预处理器,均具有变量、嵌套、继承等特性,语法稍有区别 可以方便地屏蔽浏览器私有语法差异 结构清晰,便于扩展 轻松实现多重继承

我们能够通过postCSS 这个平台,开发一些插件,来处理我们的CSS,比如autoprefixer

——————————————————————

24.水平居中和垂直居中

水平居中

元素为行内元素,设置父元素text-align:center 绝对定位中设置left:50%,margin-left为宽度一半的负值或者transform:translate(-50%,0%) 使用flex-box布局,指定justify-content属性为center 如果元素宽度固定,可以设置margin为auto

垂直居中 文本垂直居中设置line-height为height值 绝对定位中设置top:50%,margin-top值为高度一半的负值或者transform:translate(0%,-50%) 使用flex布局,设置为align-item:center,单行时候垂直居中使用align-items: center,align-content多行的时候如何进入竖直对齐

——————————————————————

27.jQuery源码有哪些写的好的地方

jquery源码封装在一个匿名函数的自执行环境中,有助于防止变量的全局污染,然后通过传入window对象参数

可以使window对象作为局部变量使用,更快的访问window对象

jquery实现的链式调用可以节约代码,所返回的都是同一个对象,可以提高代码效率

——————————————————————

28.

栈:原始数据类型(Undefined,Null,Boolean,Number、String) 堆:引用数据类型(对象、数组和函数)

原始数据类型直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储 引用数据类型存储在堆中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针

JS中向函数参数都是值传递的,函数作用域里面的参数变量不影响调用作用域的变量值

——————————————————————

30.

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 面向对象是把构成问题事务分解成各个对象,建立对象以功能来划分问题,描叙某个事物在整个解决问题的步骤中的行为

——————————————————————

31.Array.prototype.sort

让一个数组乱序
var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
    return Math.random() - 0.5;
})
console.log(arr);

sort实现
function sort(array,fn){
    var arr = new Array(array.length).fill('');
    for(let current of array){
        let index=0;
        for(let other of array){
            if(current !== other){  
                if(fn(current,other)>0){
                    index++;
                }
            }
        }  
        arr[index]=current;
    }
    return arr;
}
sort([10, 15, 2, 20, 5, 7],(a,b)=>{
    return a-b;
})

——————————————————————

32. window.onload和$(document).ready

window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。 $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕

$(document).ready用的较少是因为相关代码可以直接在页面底部写JS代码即有相同的效果

此外还有一个document.readyState只读属性,可以返回当前文档的准备状态 1.loading表示文档正在加载中 2.interactive表示文档已完成加载,文档已被解析,但图像、样式表和框架等子资源仍在加载 3.complete表示文档和所有子资源已完成加载。如果状态变成这个,表明load事件即将触发

——————————————————————

33全局函数

encodeURI() 把字符串编码为 URI
decodeURI() 解码某个编码的 URI

encodeURIComponent() 把字符串编码为 URI 组件
decodeURIComponent() 解码一个编码的 URI 组件

escape() 对字符串进行编码
unescape() 对由escape() 编码的字符串进行解码

eval() 把字符串它作为脚本代码来执行

isFinite() 检查某个值是否为有穷大的数
isNaN() 检查某个值是否是数字
Number() 把对象的值转换为数字
parseFloat() 解析一个字符串并返回一个浮点数
parseInt() 解析一个字符串并返回一个整数
String() 把对象的值转换为字符串

——————————————————————

组件化和模块化

组件化和模块化的价值都在于分治,提升开发效率,是前端工程化的一部分 组件是包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元 模块化侧重于功能或者数据的封装,露了通用方法给外部访问

——————————————————————

MVVM

Model: 业务逻辑相关的数据对象 View: 展现出来的视图界面 ViewModel: 作为视图的模型,以数据对象对基础,为视图渲染提供数据支撑

MVVM 框架中开发者只需完成包含 声明绑定 的视图模板,编写 ViewModel 中业务数据变更逻辑,视图是通过数据驱动的,数据一旦 改变就会相应的刷新对应的视图,视图如果改变,也会改变对应的数据,极大降低前端应用的操作复杂度、提升应用的开发效率,标志 特性是数据绑定 ,核心理念就是通过 声明式的数据绑定 来实现 View 层和其他层的分离,避免手动 DOM 操作

从MVC完全由代码控制的视图刷新演变

1.手动触发绑定 在页面需要改变时,手动触发检测,改变 model 数据,并扫描元素,对有特殊标记的元素进行修改

2.脏检测机制 针对手动绑定进行优化,只对修改到的数据进行更新元素

前端数据对象劫持 Object.defineProperty 对数据进行 get & set 监听,当数据有变时,自动执行 scan 扫描并更新元素

function defineGetAndSet(obj, propName) {
    Object.defineProperty(obj, propName, {
        get: function () {
            return this.bVal;
        },
        set: function (newVal) {
            this.bVal = newVal;
            scan();
        },
        enumerable: true,
        configurable: true
    });
}

——————————————————————

实现数据双向绑定

//< input id = "input" / >

const data = {
    input: ''
};
const dom = document.getElementById("input");

new Proxy(data, {//ES6 Proxy
    set: function (obj, key, value) {
        obj[key] = value;
        dom.value = value;
    }
});

Object.defineProperty(data, 'input', {//ES5 defineProperty
    set(value) {
        dom.value = value;
        this.value = value;
    }
});

//修改Model
data.input = '1';

//修改View
dom.onchange(function (e) {
    data.input = e.target.value;
});

提交修改

var state = function(initValue){
    var lastObj = {
        value:initValue
    }
    var lastvalue=initValue;
    var tempvalue=initValue;
    lastObj = new Proxy(lastObj,{
        set:(obj,prop,curValue)=>{
            if(lastvalue){
                tempvalue=curValue;         
            }else{
                obj.value=curValue;
                lastvalue=curValue;
            }

        }
    });
    return {
        value:lastObj,
        commit:()=>{
            lastvalue = null;
            lastObj.value = tempvalue;  
        }
    }
}
var {value,commit}=state(1);

——————————————————————

caller和callee的区别

caller返回一个函数的引用,表示调用了当前的函数的外层函数

functionName.caller

function inner(){
    console.log(inner.caller);
}
function outer(){
    inner()
}
outer()

callee返回函数本身的引用,它是arguments的一个属性,它可以用来递归匿名函数

arguments.callee

(function (obj) {
    console.log(arguments.callee)
})(window);

——————————————————————

媒体查询

允许添加表达式用以确定媒体的环境情况,以此来应用不同的样式表,是响应式网站不可缺少的一部分

link标签使用媒体查询

媒体查询的声明就分为以下三个部分: 媒体类型screen all,逻辑操作符and not ,媒体特性 width height color

css代码中使用媒体查询 @media and (min-width:768px) { .lead { font-size: 21px } } 常见PC分辨率 1024768 1280800 1440900 19201200

——————————————————————

事件相关的几个兼容方法

addEventListener('click')/attachEvent('onclick')

removeEventListener/detachEvent

e.stopPropagation()/e.cancelBubble =true

e.preventDefault()/e.returnValue=false

——————————————————————

bind与函数柯里话

bind 用指定对象替换函数中this的同时,绑定传入函数的第一个参数,后续调用bind返回的函数,填入后续参数执行完成

Function.prototype.bind = function(scope,firstParam) {
    var fn = this;
    var firstParam = firstParam;
    return function() {
        fn.apply(scope,[firstParam,...arguments]);
    };
};
var getPath=function(root,filename){
    console.log(`${root+filename}`);
}
var getPath_new = getPath.bind({},'/root/');
getPath_new("file1");
getPath_new("file2");

柯里化是把接受多个参数的函数变换成接受一个单一参数的函数,在后续调用中接受后续的参数且返回结果的技术 作用 1. 参数复用;2. 提前返回;3. 延迟计算/运行

——————————————————————

JavaScript的基本规范

1.不要在同一行声明多个变量

2.请使用===/!==来比较true/false或者数值

3.不要使用全局函数

4.Switch语句必须带有default分支

5.If语句必须使用大括号

——————————————————————

内存泄漏

己动态分配的堆内存由于某种原因未释放或无法释放引发的各种问题。

全局变量

使用闭包

定时器未清除

避免策略

减少不必要的全局变量,及时进行垃圾回收

优化并测试程序逻辑

避免创建过多的对象

减少层级过多的引用

——————————————————————

路由原理

前端路由本质就是监听 URL 的变化,然后匹配路由规则,显示相应的页面,并且无须刷新

单页面使用的路由就只有两种实现方式

hash 模式
原理是url中hash部分的值改变的时候,浏览器不刷新页面,但是会触发hashchange事件
所以我们可以在hashchange事件中,根据新的hash值,手动更新页面组件

history 模式
HTML5中通过监听popstate事件,判断路由变化进行页面刷新

前端路由和服务端路由的区别 服务端路由:每跳转到不同的URL,都是重新访问服务端,然后服务端返回页面,页面也可以是服务 端获取数据,然后和模板组合,返回HTML,也可以是直接返回模板HTML,然后由前端JS再去请求数 据,使用前端模板和数据进行组合,生成想要的HTML。

前端路由:每跳转到不同的URL都是使用前端的锚点路由,实际上只是JS根据URL来操作DOM元素, 根据每个页面需要的去服务端请求数据,返回数据后和模板进行组合,当然模板有可能是请求服务端 返回的,这就是 SPA 单页程序。

vue-router实现原理
1.第一步是通过Vue.use(VueRouter)
将vue-router以插件的形式注入到vue实例中: vue的插件都要遵循对应的开发规则,都会有一个install
方法(参考:https://cn.vuejs.org/v2/guide/plugins.html )。
通过 Vue.mixin() 注册了一个 beforeCreate() 钩子函数,从而在之后所有的 Vue 组件实例创建时都会调
用该钩子函数。如果传入了 router 参数,则会执行vue-router的初始化逻辑(执行 vue-router 注入的 
beforeCreate 钩子函数)。
2.执行 router.init(vm)
3.执行 history.setupListeners(),注册事件监听
4.hash值发生变化时,执行了 this.transitionTo(...),在这个过程中,会进行地址匹配,得到一个对应
当前地址的 route,然后将其设置到对应的 vm.route 上
5.进行vm.route赋值就会触发感知路由变化主要是Vue的beforeCreate钩子函数采用了Vue的“数据
劫持”方式,对 vm.route 的赋值会被 Vue 拦截到,并且触发 Vue 组件的更新渲染流程
6.vm.route进行了数据与视图的双向绑定,发生变化后会触发视图更新,所以会触发router-view的
render()函数,这里使用的是vue的自定义渲染函数能力,从根组件中取出当前的路由对象(parent.$route),
然后取得该路由下对应的组件,然后交由该组件进行渲染

——————————————————————

设计模式

1.工厂模式 - 通过一个类create方法返回new的对象 - react createClass

2.单例模式 - 利用闭包仅返回一个变量对象

3.适配器模式,调用插件类的同名方法,并加上通用的逻辑 - 显示当前日期的方法内调用日期格式化的通用方法

4.装饰模式,不改变对象自身,为对象增加功能或限制 - redux使用connect使视图组件变为容器组件

5.代理模式,控制对对象的访问,不让外部直接访问到对象 - 事件委托

6.发布-订阅模式,一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知 -事件绑定

7.外观模式,提供了一个接口,隐藏了内部的逻辑 - IE兼容写法封装

——————————————————————

46. == 和 ===

==

1.首先会判断两者类型是否相同,相同的话就是比较

2.类型不相同的话,那么就会进行类型转换

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断

=== 就是判断两者类型和值是否相同

——————————————————————

页面访问的步骤

1.在浏览器地址栏输入URL

2.浏览器查看浏览器缓存,检查Cache-Control & Expires请求头决定是否直接使用浏览器缓存返回给客户端

3.浏览器解析URL,组装http/get请求报文

4.浏览器获取主机IP 浏览器缓存-本机缓存-hosts文件-路由器缓存-DNS服务器缓存-DNS递归查询

5.创建socket与目标IP进行3次握手建立TCP连接

6.浏览器在TCP连接建立发送请求

7.HTTPS请求,还会有TLS握手和证书交换的过程

    1.客户端发送一个随机值以及需要的协议和加密方式

    2.服务端收到客户端的随机值,自己也产生一个随机值,并根据客户端需求的协议和加密方式来使用对应的方式,并且发送自己的证书

    3.客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值,通过服务端证书的公钥去加密这个随机值并发送给服务端,
    如果服务端需要验证客户端证书的话会附带客户端的CA证书

    4.服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约
    定的加密方式生成密钥,接下来的通信就可以通过该密钥来进行对称加密的方式通信

8.服务器接收请求并解析,将请求转发到服务程序

9.服务程序检查请求头包含缓存信息,返回304等对应的状态码

10.服务器读取完整请求并准备响应,通过TCP连接发送回浏览器

11.浏览器接收响应,根据情况选择关闭TCP连接或保留重用

12.浏览器检查响应状态码并对应处理

13.如果资源可缓存,则对资源进行缓存

14.浏览器对响应进行解码,根据资源类型决定如何处理

15.解析HTML文档,构建DOM树,下载资源,构造CSSOM树,执行JS脚本

浏览器从网络或硬盘中获得HTML字节数据后会经过一个流程将字节解析为DOM树,先将HTML的原始字节数据转换为文件指定编码的字符,然后浏览器会根据HTML规范来将字符串转换成各种令牌标签,如html、body等。最终解析成一个树状的对象模型,就是dom树。
具体步骤
转码(Bytes -> Characters)—— 读取接收到的 HTML 二进制数据,按指定编码格式将字节转换为 HTML 字符串
Tokens 化(Characters -> Tokens)—— 解析 HTML,将 HTML 字符串转换为结构清晰的 Tokens,每个 Token 都有特殊的含义同时有自己的一套规则
构建 Nodes(Tokens -> Nodes)—— 每个 Node 都添加特定的属性(或属性访问器),通过指针能够确定 Node 的父、子、兄弟关系和所属 treeScope(例如:iframe 的 treeScope 与外层页面的 treeScope 不同)
构建 DOM 树(Nodes -> DOM Tree)—— 最重要的工作是建立起每个结点的父子兄弟关系
合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。

渲染进程将 HTML 内容转换为能够读懂DOM 树结构。
渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式。
创建布局树,并计算元素的布局信息。 
对布局树进行分层,并生成分层树。 
为每个图层生成绘制列表,并将其提交到合成线程。合成线程将图层分图块,并栅格化将图块转换成位图。 
合成线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示到显示器上。

16.JavaScript引擎解析过程如下:

    1.创建Document对象并解析HTML生成DOM树,将解析到的节点添加到文档
    2.加载CSS资源并解析生成CSS规则树,结合DOM树生成render树,进行页面渲染
    3.遇到<script>标签就会停下来,等到下载执行完再继续向下渲染,如果是异步脚本defer aysnc则进行异步下载,并继续渲染
    4.渲染过程中aysnc下载完毕则会立即执行该脚本,执行完毕后继续渲染
    5.文档渲染完毕后,等待资源文件下载完成后,载入所有资源及并执行defer异步脚本

——————————————————————

Sass

1.使用计算功能功能将变量表达式作为样式值

2.嵌套使父子之间的层级关系更清晰,各个模块下面的样式不互相影响

3.允许一个选择器继承另一个选择器的全部样式

——————————————————————

BEM

BEM提供了一个清晰的命名空间来说明自身的作用,包含块(block)、元素(element)、修饰符(modifier)

.block 代表了更高级别的抽象或组件

.block__element 代表.block的后代,用于形成一个完整的.block的整体

.block--modifier代表.block的不同状态或不同版本

通过命名了解,模块之间关联及作用,父子元素的层级关系,以及模块或元素的状态

——————————————————————

异常监控

通常的办法是使用 window.onerror 拦截报错

对于异步代码来说,可以使用 catch 的方式捕获错误

接口异常列举出出错的状态码

——————————————————————

性能监控

性能监控的步骤:前端埋点和上报、数据处理和数据分析 目的:获取用户行为以及跟踪产品在用户端的使用情况,并以监控数据为基础,指明产品优化的方向

http等请求的响应时间

静态资源整体下载时间

不同用户,不同机型和不同系统下的首屏加载时间

不同页面渲染时间

页面交互完成时间

埋点方式

代码埋点:以嵌入代码的形式在代码指定位置进行埋点

可视化埋点:利用一个系统来实现手动插入代码埋点的过程

无埋点:前端的任意一个事件都被绑定一个标识,所有的事件都别记录下来,通过定期上传记录文件,配合文件解析,解析出来我们想要的数据

整体步骤

1.明确一个产品需要监控和上报的数据

2.设计埋点方案

3.确定上报周期和上报数据类型

4.前端埋点系统的前后端通信加密

5.前端监控结果可视化

通过浏览器提供的 window.performance 接口,我们能够得到网页每个处理阶段的精确时间

——————————————————————

数据监控

知道用户来源的渠道,可以促进产品的推广,知道用户页面停留时间,可以针对停留较长的页面,增加广告推送等等

即页面浏览量或点击量,某个内容的不同IP地址的点击人数

用户在每一个页面的停留时间

用户通过什么入口来访问该网页

用户在相应的页面中触发的行为

——————————————————————

实现模块的几种方式

立即执行函数直接使用全局变量

立即执行函数导入全局变量

对象指向自执行函数返回的对象

——————————————————————

响应式布局

弹性网格布局flexible grid layout 采用百分比或者混合百分比、像素为单位,设计出更具灵活性的布局方式

媒体查询media queries 根据在特定环境下查询到的各种属性值,来决定应用什么样的样式

弹性图片flexible image 屏幕大于一定的宽度的时候,你可以展示一个固定大小的图片,屏幕很小的时候,就按百分比缩放

rem/em区别:rem是相对于html元素的font-size大小而言的,而em是相对于其父元素 视觉组件自适应可以使用等比例缩放等形式,但对于文本内容,还是使用固定像素较为合理,能够看到更多的内容而不是更大的内容 vw是viewport width的1%,而rem是html元素的font-size

1px等细节问题可以通过viewport缩放解决

——————————————————————

Docker和微服务

容器技术 直接运行在操作系统内核之上的用户空间 依赖于操作系统的特性,只能运行在相同或相似内核的操作系统 磁盘占用空间少,内存和CPU损耗小,相对虚拟机能提供更多的服务能力

Docker引擎能够将应用程序自动部署到容器,让容器更容易安装和管理 将开发应用程序与部署和生产环境分离,让应用程序具备可移植性,缩短产品的上线周期 分布式的应用程序模型,避免服务之间的互相影响

便于服务的开发,测试和部署 创建隔离的运行环境运行不同的服务,便于搭建各种测试环境验证服务的兼容性

微服务

单页面应用随着时间的推移以及应用功能的丰富,这些应用变得越来越庞大也越来越难以维护 微服务解决模块单独开发运行打包,以及公共依赖和组件复用的问题

应用程序的不同模块分布到不同的微服务器分离开发,形成微服务,互相之间通过API接口通信,使用网关集成暴露给外网,同时可以在网关处理限流,认证,异常处理等通用逻辑

——————————————————————

编译相关

一般编译型语言性能比解释型语言高,但是编译型语言需要先进行编译

解释型语言的好处是,部署到线上的是源代码,可以直接修改线上环境的代码

强类型语言由于类型在声明之后不允许改变,所以能实现编译时类型检查 动态语言和弱类型语言,则更灵活,实现相同功能的代码量通常更少或者更容易实现复杂功能,可读性可维护性方面不如静态语言和强类型语言

——————————————————————

Babel 原理

Babel 的三个主要处理步骤分别是: 解析(parse),转换 (transform),生成 (generate)

在解析过程中有两个阶段: 词法分析 和 语法分析 将代码解析成抽象语法树(AST) 词法分析 - 将函数表达式等都拆分成各个变量运算符的节点形式,转成token流 token流用来进行代码检查,语法高亮,模板语法判断 语法分析 - 将这些节点按照代码中的关系通过loc属性建立关联,形成树状结构即AST

转换过程 接收得到AST并通过babel-traverse对其进行 深度优先遍历,增删改这些节点,从而转换成实际需要的 AST

生成过程 将经过转换的AST通过babel-generator再转换成js代码,过程就是 深度优先遍历整个AST,使用节点处理器处 理语法树上的各个节点,然后构建可以表示转换后代码的字符串

Code -> AST (Parse) 代码解析 AST -> AST (Transform) 一种语法的AST转化成另一种语法的AST AST -> Code (Generate) AST生成代码

——————————————————————

JS浮点数精度问题

因为 JS 采用 IEEE 754双精度版本(64位) 第一位用来表示符号,接下去的 11 位用来表示指数,其他的位数用来表示有效位 二进制来表示小数时都是无限循环的,但由于双精度浮点数的小数部分最多支持 52 位,二进制转十进制的时候,需要截取时52位,将后面的零舍一入,导致可能出现浮点数精度问题 parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true

'#sum(1,sum(1,2))'

eval与new Function

直接调用eval在当前作用域执行字符串 间接调用eval或者使用window.eval在全局作用域执行字符串

new Function('x', 'y', 'return x+y'); 传多个参数的时候,最后一个参数为函数体,前面的参数都是函数的形参名,返回一个新的函数,函数作用域也是全局的

对输入进行限制及编码转义,注意动态执行语句的作用域,避免javascript读取关键信息,只允许加载同域下的资源

——————————————————————

解决github page 404问题

根目录添加404.html 文件顶部加上

---
permalink: /404.html
---

——————————————————————

浏览器拦截新打开窗口

规则 所有浏览器都不允许非用户操作引起的打开新窗口 所有浏览器都不允许在异步 ajax 请求中打开新窗口

解决方案 需要在异步 ajax 请求中打开新窗口的可以使用请求前打开新窗口,请求拿到结果后再修改窗口地址的方式。 需要在键盘回车事件中打开新窗口的推荐使用 form 表单包装并添加 button 的方式,回车触发默认的 submit 事件进行新窗口的打开。

——————————————————————

复制文本加上版权信息功能实现

let oDiv = document.querySelector('div');
oDiv.oncopy = function(e) { // 复制事件
  e.preventDefault();
  let copyMsg = window .getSelection() + '商业转载请注明出处。'; // window .getSelection() 表示选择的内容
  e.clipboardData.setData("Text", copyMsg); // 将复制信息添加到剪切板
}

——————————————————————

粘贴剪切板图片及预览上传

document.addEventListener('paste', function (event) {
    var items = event.clipboardData && event.clipboardData.items;
    var file = null;
    if (items && items.length) {
        // 检索剪切板items
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                file = items[i].getAsFile();
                break;
            }
        }
    }
    // 此时file就是剪切板中的图片文件
});
var reader = new FileReader()
reader.readAsDataURL(file);
reader.onload = function(event) {
    // event.target.result就是图片的Base64地址啦
}

——————————————————————

image-set

用来根据不同设备的屏幕密度或者分辨率显示不同的背景图片 background-image: image-set(url(zxx.png) 1x, url(zxx-2x.png) 2x, url(zxx-print.png) 600dpi); 分别设置再1倍屏,2倍屏及600分辨率设备上的背景图片 IE和Firefox都不支持,Chrome和Safari都支持,移动端可以使用

——————————————————————

滚动到指定位置兼容写法

原来 document.documentElement.scrollTop = 0; document.body.scrollTop = 0; 现在 document.scrollingElement.scrollTop = 0;

——————————————————————

浏览器原生的base64编码解码

编码 window.btoa(stringToEncode); 解码 window.atob(encodedData);

——————————————————————

Web Components

Web Components技术基于自定义元素,影子DOM,ES模块,HTML模版等可以把一组相关的HTML、JS代码和CSS风格打包成为一个自包含的组件,引入此组件后使用标签即可复用该组件

——————————————————————

cookie及登录态

cookie是浏览器的一种本地存储方式,一般用来帮助客户端和服务端通信的,常用来进行身份校验,结合服务端的session使用

登录态的产生步骤

在客户端登陆页面,用户执行登陆操作

此时,服务端会生成一个session,session中有对于用户的信息(如用户名、密码等)

然后会有一个sessionid(相当于是服务端的这个session对应的key)

然后服务端在登录页面中写入cookie,值就是:jsessionid=xxx

然后浏览器本地就有这个cookie了,以后访问同域名下的页面时,自动带上cookie,自动检验,在有效时间内无需二次登陆

——————————————————————

JS原生实现JSONP请求

var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);

// 回调执行函数
function onBack(res) {
    alert(JSON.stringify(res));
}

——————————————————————

JS实现深拷贝

function deepClone(data) {
    var t = type(data), o, i, ni;

    if(t === 'array') {
        o = [];
    }else if( t === 'object') {
        o = {};
    }else {
        return data;
    }

    if(t === 'array') {
        for (i = 0, ni = data.length; i < ni; i++) {
            o.push(deepClone(data[i]));
        }
        return o;
    }else if( t === 'object') {
        for( i in data) {
            o[i] = deepClone(data[i]);
        }
        return o;
    }
}

对于函数直接辅助,因为对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝

——————————————————————

高阶函数

高阶函数是指至少满足下列条件之一的函数 1:函数可以作为参数被传递 2:函数可以作为返回值输出 闭包函数,柯里化及数组自带的map、filter和reduce就是高阶函数

——————————————————————

垃圾回收和内存泄漏

手动回收策略,何时分配内存、何时销毁内存都是由代码控制的。 自动回收策略,产生的垃圾数据是由垃圾回收器来释放的,并不需要手动通过代码来释放。

垃圾回收方法 调用栈中的数据回收 JavaScript 堆中的数据回收 JavaScript 引擎会通过向下移动 ESP(记录当前执行状态的指针) 来销毁该函数保存在栈中的执行上下文。 V8的堆其实并不只是由老生代和新生代两部分构成。 1、新生代内存区:大多数的对象被分配在这里,这个区域很小但是垃圾回特别频繁; 2、老生代指针区:属于老生代,这里包含了大多数可能存在指向其他对象的指针的对象,大多数从新生代晋升的对象会被移动到这里; 3、老生代数据区:属于老生代,这里只保存原始数据对象,这些对象没有指向其他对象的指针; 4、大对象区:这里存放体积超越其他区大小的对象,每个对象有自己的内存,垃圾回收其不会移动大对象; 5、代码区:代码对象,也就是包含JIT之后指令的对象,会被分配在这里。唯一拥有执行权限的内存区; 6、Cell区、属性Cell区、Map区:存放Cell、属性Cell和Map,每个区域都是存放相同大小的元素,结构简单。

第一步是标记空间中活动对象和非活动对象。所谓活动对象就是还在使用的对象,非活动对象就是可以进行垃圾回收的对象。

第二步是回收非活动对象所占据的内存。其实就是在所有的标记完成之后,统一清理内存中所有被标记为可回收的对象。

第三步是做内存整理。 一般来说,频繁回收对象后,内存中就会存在大量不连续空间,我们把这些不连续的内存空间称为内存碎片。当内存中出现了大量的内存碎片之后,如果需要分配较大连续内存的时候,就有可能出现内存不足的情况。所以最后一步需要整理这些内存碎片。

在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。 为了执行效率,一般新生区的空间会被设置得比较小,也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域。为了解决这个问题,JavaScript 引擎采用了对象晋升策略,也就是经过两次垃圾回收依然还存活的对象,会被移动到老生区中。

老生代中用 标记 - 清除(Mark-Sweep)和 标记 - 整理(Mark-Compact)的算法来处理。标记阶段就是从一组根元素开始,递归遍历这组根元素(遍历调用栈),能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据.然后在遍历过程中标记,标记完成后就进行清除过程。

V8 采用了增量标记(Incremental Marking)算法,将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JavaScript 应用逻辑交替进行,直到标记阶段完成。 使用增量标记算法,可以把一个完整的垃圾回收任务拆分为很多小的任务,这些小的任务执行时间比较短,可以穿插在其他的 JavaScript 任务中间执行,这样当执行上述动画效果时,就不会让用户因为垃圾回收任务而感受到页面的卡顿了。

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。这也就是需要回收的对象。 循环引用会让计数器最小值为1,不会变为0。

缓存 队列消费不及时 全局变量 计时器中引用没有清除 闭包 事件监听

Antd Design中 将 Modal 挂载在 body 的API

ReactDOM.CreatePortal。最终我们发现 ReactDOM.createPortal 可以将组件放在 HTML 的任意 DOM 中,被 Portal 的组件行为和普通的 React 子节点行为一致,因为它仍然在 React Tree 中, 且与 DOM Tree 中的位置无关