前端知识

348 阅读16分钟

简单的发布订阅者模式

 //  简单发布订阅者模式
    class EventEmitter {
        constructor () {
            this.events = {}
        }

        // 订阅事件
        onEvent (eventName, callback) {
            if (!this.events[eventName]) {
                this.events[eventName] = [callback]
            } else {
                this.events[eventName].push(callback)
            }
        }

        // 发布事件
        emitEvent (eventName) {
            this.events[eventName] && this.events[eventName].forEach(callback => callback())
        }

        // 移除订阅者
        removeEmitter (eventName, callback) {
            if (!this.events[eventName]) {
                return
            }

            this.events[eventName] = this.events[eventName].filter(cb => cb != callback)
        }

        // 执行一次订阅事件
        onceEvent (eventName, callback) {
            let fn = () => {
                callback()
                this.removeEmitter(eventName, fn)
            }

            this.onEvent(eventName, fn)
        }
    }

了解什么设计模式以及使用场景

单例模式

保证一个类只有一个实例,并提供一个全局访问点。
实现方法:先判断实例是否存在,不存在先创建后返回,存在则直接返回。

// 单例创建
    let CreateDev = function (sign) {
        this.sign = sign
    }
    
    let Singleton = (function () {
        let instace
        return function (sign) {
            if (!instace) {
                instace = new CreateDev(sign)
            }

            return instace
        }
    })()

 实际应用:模态框、以及弹框

工厂模式

工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

// 工厂模式
    function CreatePerson(name, age, sex) {
        let obj = new Object()
        obj.name = name
        obj.age = age
        obj.sex = sex
        obj.sayName = function () {
            return this.name
        }
        
        return obj
    }

发布订阅者模式

定义了一种依赖关系, 解决了主体对象与观察者之间功能的耦合

代理模式

由于一个对象不能直接应用另一个对象,所以需要通过代理对象其搭配中介作用  实际应用:跨域


http和https的区别

https的SSL加密是在传输层实现的。
(1)http和https的基本概念
http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
https: 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
https协议的主要作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性。
(2)http和https的区别?
http传输的数据都是未加密的,也就是明文的,网景公司设置了SSL协议来对http协议传输的数据进行加密处理,简单来说https协议是由http和ssl协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高。
主要的区别如下:
Https协议需要ca证书,费用较高。
http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
使用不同的链接方式,端口也不同,一般而言,http协议的端口为80,https的端口为443
http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
(3)https协议的工作原理
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
客户使用https url访问服务器,则要求web 服务器建立ssl链接。
web服务器接收到客户端的请求之后,会将网站的证书(证书中包含了公钥),返回或者说传输给客户端。
客户端和web服务器端开始协商SSL链接的安全等级,也就是加密等级。
客户端浏览器通过双方协商一致的安全等级,建立会话密钥,然后通过网站的公钥来加密会话密钥,并传送给网站。
web服务器通过自己的私钥解密出会话密钥。
web服务器通过会话密钥加密与客户端之间的通信。
(4)https协议的优点
使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。
(5)https协议的缺点
https握手阶段比较费时,会使页面加载时间延长50%,增加10%~20%的耗电。
https缓存不如http高效,会增加数据开销。
SSL证书也需要钱,功能越强大的证书费用越高。
SSL证书需要绑定IP,不能再同一个ip上绑定多个域名,ipv4资源支持不了这种消耗。


http1.1与2.0的区别

HTTP/2采用二进制格式而非文本格式
HTTP/2是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
使用报头压缩,HTTP/2降低了开销
HTTP/2让服务器可以将响应主动“推送”到客户端缓存中


async/await

这是一个用同步的思维来解决异步问题的方案,当前端接口调用需要等到接口返回值以后渲染页面时。

async:

async的用法,它作为一个关键字放到函数前面,用来表示此函数是一个异步函数, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行,async 函数返回的是一个promise 对象,可以使用then方法添加回调函数。

await:

await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果


ES6/ES7特性

ES6:

  • 模块化
  • 箭头函数
  • 函数参数默认值
  • 模板字符串
  • 解构赋值
  • 延展操作符
  • 对象属性简写
  • Promise
  • let和const

ES7:

  • 数组includes方法
  • a**b指数运算符

position的值有哪些?除了常用的四个,还有吗

  • absolute

生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

  • fixed

生成绝对定位的元素,相对于浏览器窗口进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

  • relative

生成相对定位的元素,相对于其正常位置进行定位。
因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。

  • static

默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。

  • inherit

规定应该从父元素继承 position 属性的值。


实现深拷贝的几种方式

  • 1、使用递归方式实现
function deepClone(obj) {
        let arr = Array.isArray(obj) ? [] : {}
        if (obj && typeof obj === 'object') {
            for (let k in obj) {
                if (obj[k] && typeof obj[k] === 'object') {
                    arr[k] = deepClone(obj[k])
                } else {
                    arr[k] = obj[k]
                }
            }
        }

        return arr
    }
  • 2、通过JSON对象实现
function deepClone2(obj) {
  let _obj = JSON.stringify(obj),
  return JSON.parse(_obj);
}
  • 3、通过Object.assign()实现
let obj = {name: '张三', age: 18}
let resObj = Object.assign({}, obj)

注意: 当对象只有一级属性为深拷贝;
当对象中有多级属性时,二级属性后就是浅拷贝


CSS中选择器的优先级

!important > 内联(1,0,0,0) > id: (0,1,0,0) > 类:(0,0,1,0) > 伪类/属性 > 元素:(0,0,0,1) > 通配符 > 继承


Doctype作用?严格模式与混杂模式-如何触发两种模式,区别他们有何意义?

<!DOCTYPE>声明位于文档中的最前面,处于<html>标签之前。告知浏览器的解析器用什么文档类型规范来解析这个文档。
严格模式的排版和JS运作模式是以该浏览器支持的最高标准运行。
混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。
<!DOCTYPE>不存在或格式不正确会导致文档以混杂模式呈现。


link和@import的区别

link属于XHTML标签,而@import是CSS提供的;
页面被加载时,link会被同时加载,而@import引用的CSS会等到页面被加载完后再加载;
@import只在IE5以上才能识别,而link是XHTML标签,无兼容问题;
link方式的样式的权重高于@import的权重


CSS选择符有哪些?哪些属性可以继承?优先级算法如何计算?CSS3新增伪类有哪些?

  • id选择器(#myid)
  • 类选择器(.myclassname)
  • 标签选择器(div,h1,p)
  • 相邻选择器(h1+p)
  • 子代选择器(ul > li)
  • 后代选择器(li a)
  • 通配符选择器(*)
  • 属性选择器(a[rel="external"])
  • 伪类选择器(a:hover, li:nth-child) 可继承: font-size、font-family、color、ul、li、dl、dt、dd CSS3新增伪类: p:first-of-type 选择属于其父元素的首个<p>元素的每个<p>元素。
    p:last-of-type 选择属于其父元素的最后<p>元素的每个<p>元素。
    p:only-of-type 选择属于其父元素唯一<p>元素的每个<p>元素。
    p:only-child 选择属于其父元素的唯一子元素的每个<p>元素。
    p:nth:child(2) 选择属于其父元素的第二个子元素的每个<p>元素。
    :enabled、:disabled 控制表单控件的禁用状态
    :checked 单选框或复选框被选中

为什么要初始化CSS样式

因为浏览器有兼容问题,不同的浏览器对有些标签的默认值是不同的,解决浏览器之间页面显示差异的问题。但是会对SEO有一定影响。


iframe有哪些缺点

iframe会阻塞主页面onload事件;
iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载;


js中的原型链

所有的函数都是Function的实例。在构造函数上都有一个原型属性 prototype,该属性也是一个对象;那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;而实例对象上有一个 proto 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用。

构造函数

主要用来在创建对象时初始化对象。每个构造函数的实例都将共享构造函数的初始值。

// 传统创建对象实例的方法
var person={
   name:'张女士',
   age:'80',
   gender:'女'
 };
console.log(person)

// 构造函数的方法
function Person(name,age,gender) {
this.name=name;
this.age=age;
this.gender=gender;
this.say=function () {
    alert(this.name)
  }
}
var person1=new Person('钟女士',80,'女');
var person2=new Person('张女士',80,'女');
console.log(person2)
console.log(person1)

原型

每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

原型模式

每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含特性类型的所有实例共享的属性和方法,即这个原型对象用来给实例共享属性和方法的。每一个实例内部都有一个指向原型对象的指针(__proto__)。

原型链图示

原型链

new操作符具体干了什么?

 var obj  = {};
 obj.__proto__ = Base.prototype;
 Base.call(obj);

第一行,我们创建了一个空对象obj
第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
第三行,我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”base”

继承

原型继承
	function Animal(name) {
           this.name = name
        }

        function Tiger(color) {
           this.color = color
        }

        // var triger = new Tiger('yellow')
        // console.log(triger.color)
        // console.log(triger.name)        //  undefined

        // Tiger.prototype = new Animal('老虎') // 第一种方式

        Object.prototype.name = '大老虎' // 第二种方式
        var triger = new Tiger('yellow')
        console.log(triger.color)
        console.log(triger.name)
ES5提供Object.create()方法实现继承
	// 兼容处理
        function create(obj) {
            if (Object.create) {
               return Object.create(obj)
            } else {
                function Foo() {}
                Foo.prototype = obj
                return new Foo()
            }
        }
拷贝继承
	var obj = {};
        obj.extend = function (obj) {
            for (var k in obj) {
                this[k] = obj[k]
            } 
        }
借用构造函数继承
	function Animation(name) {
            this.name = name
        }
        
        function Mouse(nickName) {
            Animation.call(this, '杰瑞')
            this.nickName = nickName
        }

        var mouse = new Mouse('老鼠')
        console.log(mouse.nickName)
        console.log(mouse.name)

存在的问题:可以解决原型继承当中传参问题,但是父类型当中的原型对象上的成员(属性和方法)不能被继承到

组合继承
	function Person(name) {
            this.name = name
        }
        
	Person.prototype.showName = function () {
            console.log(this.name)
        }

        function Student(name, age) {
            Person.call(this, name)
            this.age = age
        }

        Student.prototype = new Person()
        Student.prototype.constructor = Student
        Student.prototype.showAge = function () {
            console.log(this.age)
        }

        var stu = new Student('张三', 18)
        stu.showName()
        stu.showAge()

六种继承方式的优缺点

call的原理

  • 写法1
	Function.prototype.es3Call = function (context) {
            var content = context || window
            content.fn = this

            var args = []
            for (var i = 0, len = arguments.length; i < len; i++) {
                args.push('arguments['+ i +']')
            }

            var result = eval('content.fn('+args+')')
            delete  content.fn

            return result
        }
  • 写法2
	Function.prototype.es6Call = function (context) {
            var context = context || window
            context.fn = this
            let args = [...arguments].slice(1)

            let result = context.fn(...args)
            delete  context.fn

            return result
        }

call原理深入理解


跨域

同源策略

协议相同、域名相同、端口相同

  • 同源策略限制以下几种行为:

1、cookie、localStorage和indexDB无法读取;
2、DOM无法获得;
3、Ajax请求不能发送。

  • 跨域解决的办法

1、通过jsonp跨域
2、CORS
3、document.domain + iframe跨域
4、location.hash + iframe
5、window.name + iframe跨域
6、postMessage跨域
7、nginx代理跨域
8、nodejs中间件代理跨域
9、WebSocket协议跨域


语义化的理解

html语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析
在没有样式CSS情况下也以一种文档格式显示,并且容易阅读
搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于SEO
使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解


什么叫优雅降级和渐进增强

优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确定它们是否可以正常工作。为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效

渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能。当浏览器支持时,它们会自动呈现出来并发挥作用。


js的数据类型

Number、String、Boolean、Null、Undefined、object、symbol、bigInt 三大引用类型: object、Array、funtion


谈谈对于this的理解

this是js的一个关键字,随着函数的使用场合的不同,this的值会发生变化;
一个总原则:即this指的是调用函数的那个对象;
一般情况下,this是全局对象,可以作为方法调用。

深入理解this


js延迟加载的几种方式

defer、async、动态创建DOM方式、使用setTimeout延迟方法、让js最后加载


什么是ajax?ajax的交互模型?同步和异步的区别?如何解决跨域问题?

什么是ajax:

ajax是异步的 JavaScript 和 XML。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

交互模型(流程):

1、启动 获取XMLHttpRequest对象
2、open 打开url通道,并设置异步传输
3、send 发送数据到服务器
4、服务器接受数据并处理,处理完成后返回结果
5、客户端接收服务器端返回 onReadyStateChange

同步&&异步:

同步:脚本会停留并等待服务器发送回复然后再继续
异步:脚本允许页面继续其进程并处理可能的回复

跨域解决:

1、通过jsonp跨域
2、CORS
3、document.domain + iframe跨域
4、location.hash + iframe
5、window.name + iframe跨域
6、postMessage跨域
7、nginx代理跨域
8、nodejs中间件代理跨域
9、WebSocket协议跨域

ajax的缺点:

1、ajax不支持浏览器back按钮
2、安全问题 ajax暴露了与服务器交互的细节
3、对搜索引擎的支持比较弱
4、破坏了程序的异常机制
5、不容易调试

模块化

什么是模块化

将js分割成不同职责的js,解耦功能,用来解决全局变量污染、变量冲突、代码冗余、依赖关系难以维护等问题的一种js管理思想,这就是模块化的过程。

require和import的区别

reqiereimport
加载运行时加载(即动态加载)编译时加载(即静态加载)
导入导入整个模块对象,不能导入部分内容可以导入模块中的所有导出内容或者部分导出内容
导出module.export之后,导出的值就不能再变化(输出值的拷贝)export之后导出的值可以变化(输出值的映射)
书写位置可以写在代码任何地方执行必须写在文件的顶部
性能性能较低,因为require是在运行时才引入模块并且赋值给某个变量性能较高,因为import中的接口在编译时引入指定模块,所以性能较高

为什么要使用模块化

1、解决命名冲突
2、提高复用性
3、提高代码可维护性

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

1、浏览器地址栏输入url
2、浏览器会先查看浏览器缓存--系统缓存--路由缓存,如有存在缓存,就直接显示。如果没有,接着第三步
3、域名解析(DNS)获取相应的ip
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手
5、握手成功,浏览器向服务器发送http请求,请求数据包
6、服务器请求数据,将数据返回到浏览器
7、浏览器接收响应,读取页面内容,解析html源码,生成DOm树
8、解析css样式、浏览器渲染,js交互绑定多个域名,数量不限;

搜集其他相关知识

前端页面性能优化的几种方式
前端相关知识点1
HTML知识相关