前端基本功 - 常见概念(一) 点这里前端基本功 - 常见概念(二) 点这里前端基本功 - 常见概念(三) 点这里
1. 什么是原型链
当一个引用类型继承另一个引用类型的属性和方法时候就会产生一个原型链。(js 高级程序设计)
所有 引用类型 都有一个 __proto__ 属性的隐式原型
所有 函数 都有一个 prototype 属性的显式原型
所有 引用类型的 隐式原型,指向其构造函数的 显式原型
当试图得到一个属性或方法时,如果这个对象没有,那么会去他的__proto__(即它构造函数的 prototype)中查找
原型链 是针对构造函数的,比如我先创建了一个函数,然后通过一个变量 new 了这个函数,那么这个被 new 出来的函数就会继承创建出来的那个函数的属性,然后如果我访问 new 出来的这个函数的某个属性,但是我并没有在这个 new 出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。
2. 什么是闭包
有权访问另一个函数作用域中的变量函数。(js 高级程序设计)当一个函数存在对非自身作用域的变量的引用 就产生一个闭包有权访问另一个作用域的函数就是闭包
闭包三点作用:创建私有变量;延长变量生命周期;防止全局变量污染
3. 什么是作用域
就是函数和变量的可访问范围。
作用域 是针对变量的, 特点是: 先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。只有函数作用域和全局作用域(貌似还有个 eval 作用域),ES6 中新增块级作用域那是后话
函数外声明的变量为全局作用域,函数内可以使用函数内声明的变量为函数作用域,函数外不可以使用
作用域链:一个自由变量一直往上寻找(定义时的)父级作用域内的变量的过程。
自由变量:当前作用域没有定义的变量
作用域什么时候生成的?
页面加载 –> 创建 window 全局对象,并生成全局作用域 –> 然后生成执行上下文,预解析变量(变量提升),生成全局变量对象;$scope
补充:花括号内声明的变量为块级作用域,只能内部使用,减少全局污染
JavaScript 是静态作用域,在对变量进行查询时,变量值由函数定义时的位置决定,和执行时的所处的作用域无关。
4. 什么是构造函数
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。
5. 什么是面向对象
ECMAscript 开发的两种模式:
1. 面向过程: 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了 2. 面向对象(OOP): 面向对象是以功能来划分问题,而不是步骤
面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性的方法的对象。
但是 ECMAscript 中没有类的概念!prototype 是 javascript 实现与管理继承的一种机制,也是面向对象的设计思想, 可以借助 prototype 属性,可以访问原型内部的属性和方法。
通常使用构造函数,当构造函数被实列化后,所有的实例对象都可以访问构造函数的原型(prototype)成员,如果在原型中声明一个成员,所有的实列方法都可以共享它
面向对象编程的基本思想是使用对象,类,继承,封装等基本概念来进行程序设计,达到数据结构化,简单抽象的目的(为什么面向对象)
优点
易维护
采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的
– 易扩展
开发工作的重用性、继承性高,降低重复工作量。
缩短了开发周期
面向对象的三大特性:继承(子类继承父类,提高复用减少冗余),封装(数据的权限和保密),多态(同一接口的不同实现)面向对象离不开 类 和 实例 两个概念
6. 什么是响应式设计?响应式设计的基本原理是什么?
响应式网站设计 (Responsive Web design) 是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。基本原理: 是通过媒体查询检测不同的设备屏幕尺寸做处理。
页面头部必须有 meta 声明的 viewport。
<meta name=’viewport’content=”width=device-width, initial-scale=1. maximum-scale=1,user-scalable=no”>
7. 什么是高阶函数
函数可以作为参数传递
函数可以作为返回值输出
8. 什么是函数式编程?
是指通过复合纯函数来构建软件的过程,它避免了共享的状态、易变的数据、以及副作用。函数式编程是声明式而不是命令式,并且应用程序状态通过纯函数流转。
简单说,” 函数式编程 ” 是一种 ” 编程范式 ”(programming paradigm),也就是如何编写程序的方法论
它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是 ” 第一等公民 ”、只用 ” 表达式 ”
进一步了解
9.css 盒模型
盒模型 : margin、padding、border、content
标准盒模型 width = content 对应 css 属性 box-sizing:content-box
怪异盒模型 width = content + padding + border 对应 css 属性 box-sizing:border-box
10. 关于跨域
关于跨域,有两个误区:
✕ 动态请求就会有跨域的问题
✔ 跨域只存在于浏览器端,不存在于安卓 /ios/Node.js/python/ java 等其它环境
✕ 跨域就是请求发不出去了
✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。
同源策略具体限制些什么呢?
不能向工作在不同源的的服务请求数据(client to server)
但是 script 标签能够加载非同源的资源,不受同源策略的影响。
无法获取不同源的 document/cookie 等 BOM 和 DOM,可以说任何有关另外一个源的信息都无法得到(client to client)
跨域最常用的方法,应当属 CORS
如下图所示:
只要浏览器检测到响应头带上了 CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。
CORS 把请求分为两种,一种是简单请求,另一种是需要触发预检请求,这两者是相对的,怎样才算“不简单”?只要属于下面的其中一种就不是简单请求:(1)使用了除 GET/POST/HEAD 之外的请求方式,如 PUT/DELETE(2)使用了除 Content-Type/Accept 等几个常用的 http 头这个时候就认为需要先发个预检请求,预检请求使用 OPTIONS 方式去检查当前请求是否安全
代码里面只发了一个请求,但在控制台看到了两个请求,第一个是 OPTIONS,服务端返回:
详见阮一峰的跨域资源共享 CORS 详解
第二种常用的跨域的方法是 JSONP
JSONP 是利用了 script 标签能够跨域,如下代码所示:
function updateList (data) {
console.log(data);
}
$body.append(‘<script src=“http://otherdomain.com/request?callback=updateList”></script>’);
代码先定义一个全局函数,然后把这个函数名通过 callback 参数添加到 script 标签的 src,script 的 src 就是需要跨域的请求,然后这个请求返回可执行的 JS 文本:// script 响应返回的 js 内容为
updateList([{
name: ‘hello’
}]);
由于它是一个 js,并且已经定义了 upldateList 函数,所以能正常执行,并且跨域的数据通过传参得到。这就是 JSONP 的原理。
小结
跨域分为两种,一种是跨域请求,另一种访问跨域的页面,跨域请求可以通过 CORS/JSONP 等方法进行访问,跨域的页面主要通过 postMesssage 的方式。由于跨域请求不但能发出去还能带上 cookie,所以要规避跨站请求伪造攻击的风险,特别是涉及到钱的那种请求。
本节参考文章:我知道的跨域与安全
11.http/https
HTTP
超文本传输协议(HTTP)是用于传输诸如 HTML 的超媒体文档的应用层协议。它被设计用于 Web 浏览器和 Web 服务器之间的通信,但它也可以用于其他目的。HTTP 遵循经典的客户端 - 服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。HTTP 是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。
HTTP 是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。
举个最常见的例子,用户登陆。用户输入账号,密码,采用 HTTP 的话,只要在代理服务器上做点手脚就可以拿到你的密码了。
用户登陆 –> 代理服务器(做手脚)–> 实际授权服务器
在发送端对密码进行加密?没用的,虽然别人不知道你原始密码是多少,但能够拿到加密后的账号密码,照样能登陆。
HTTP 是应用层协议,位于 HTTP 协议之下是传输协议 TCP。TCP 负责传输,HTTP 则定义了数据如何进行包装。
HTTPS
HTTPS 相对于 HTTP 有哪些不同呢?其实就是在 HTTP 跟 TCP 中间加多了一层加密层 TLS/SSL。
神马是 TLS/SSL?
通俗的讲,TLS、SSL 其实是类似的东西,SSL 是个加密套件,负责对 HTTP 的数据进行加密。TLS 是 SSL 的升级版。现在提到 HTTPS,加密套件基本指的是 TLS。
传输加密的流程
原先是应用层将数据直接给到 TCP 进行传输,现在改成应用层将数据给到 TLS/SSL,将数据加密后,再给到 TCP 进行传输。
HTTPS 是如何加密数据的
对安全或密码学基础有了解的同学,应该知道常见的加密手段。一般来说,加密分为对称加密、非对称加密(也叫公开密钥加密)
HTTPS 与 HTTP 的一些区别
HTTPS 协议需要到 CA 申请证书,一般免费证书很少,需要交费。
HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,内容可能会被窃听。HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
HTTPS 可以有效的防止运营商劫持,解决了防劫持的一个大问题。
不验证通信方的身份,通信方的身份有可能遭遇伪装。
无法证明报文的完整性,报文有可能遭篡改。
使用 SPDY 加快你的网站速度
谷歌推行一种协议(HTTP 之下 SSL 之上[TCP]), 可以算是 HTTP2 的前身,SPDY 可以说是综合了 HTTPS 和 HTTP 两者优点于一体的传输协议,比如
压缩数据(HEADER)
多路复用
优先级(可以给请求设置优先级)
SPDY 构成图:
SPDY 位于 HTTP 之下,TCP 和 SSL 之上,这样可以轻松兼容老版本的 HTTP 协议(将 HTTP1.x 的内容封装成一种新的 frame 格式),同时可以使用已有的 SSL 功能。
HTTP2
HTTP2.0 可以说是 SPDY 的升级版(其实原本也是基于 SPDY 设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,主要是以下两点
HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE
http2 新特性
新的二进制格式(Binary Format),HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1 的组合。基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮。
多路复用(MultiPlexing),支持单个连接多次请求,即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
header 压缩,如上文中所言,对前面提到过 HTTP1.x 的 header 带有大量信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 header 大小,通讯双方各自 cache 一份 header fields 表,既避免了重复 header 的传输,又减小了需要传输的大小。
服务端推送(server push),同 SPDY 一样,HTTP2.0 也具有 server push 功能。目前,有大多数网站已经启用 HTTP2.0,例如 YouTuBe,淘宝网等网站,利用 chrome 控制台可以查看是否启用 H2:
chrome=>Network=>Name 栏右键 =>√Protocol
本节参考文章:简单比较 http https http2、HTTPS 科普扫盲帖
12.GET/POST
GET 在游览器回退会刷新,而 POST 会再次提交请求
GET 请求会被游览器主动缓存,而 POST 不会,除非手动设置
GET 请求参数会被完整的保留在游览器历史记录里,而 POST 中的参数不会被保留
GET 产生的 URL 地址可以被收藏,而 POST 不可以
GET 参数通过 URL 传递,而 POST 放在 Request body
GET 请求只能进行 URL 编码,而 POST 支持多种编码方式
GET 请求在 URL 中传递的参数是有长度限制的,而 POST 没有限制
GET 请求会把参数直接暴露在 URL 上,相比 POST 更安全
对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制
1. 请求参数:get 参数附在 URL 后面? 隔开,POST 参数放在包体中 2. 大小限制:GET 限制为 2048 字符,post 无限制 3. 安全问题:GET 参数暴露在 URL 中,不如 POST 安全 4. 浏览器历史记录:GET 可以记录,POST 无记录 5. 缓存:GET 可被缓存,post 无 6. 书签:GET 可被收藏为书签,post 不可 7. 数据类型:GET 只能 ASCII 码,post 无限制
13.MVC/MVVM
MVC
MVC 是一种设计模式,它将应用划分为 3 个部分:数据 (模型)、展示层(视图) 和用户交互层。结合一下下图,更能理解三者之间的关系。
换句话说,一个事件的发生是这样的过程
用户和应用交互
控制器的事件处理器被触发
控制器从模型中请求数据,并将其交给视图
视图将数据呈现给用户
MVVM
MVVM 是 Model-View-ViewModel 的缩写。mvvm 是一种设计思想。Model 层代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑;View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来,ViewModel 是一个同步 View 和 Model 的对象。
在 MVVM 架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行交互,Model 和 ViewModel 之间的交互是双向的,因此 View 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
在之前的 MVC 中我们提到一个控制器对应一个视图,控制器用状态机进行管理,如果项目足够大的时候,状态机的代码量就变得非常臃肿,难以维护。
性能问题,在 MVC 中我们大量的操作了 DOM,而大量操作 DOM 会让页面渲染性能降低,加载速度变慢,影响用户体验。
最后就是当 Model 频繁变化的时候,开发者就手动更新 View,那么数据的维护就变得困难。
为了减小工作量,节约时间,一个更适合前端开发的架构模式就显得非常重要,这时候 MVVM 模式在前端中的应用就应运而生。
mvvm 和 mvc 区别
mvc 和 mvvm 其实区别并不大。都是一种设计思想。主要就是 mvc 中 Controller 演变成 mvvm 中的 viewModel。mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到 View。
3 种方式实现 MVVM
defineProperty(VUE),脏检查(angular),原生 js 实现(发布订阅者模式)
在 Angular 中实现数据的观测使用的是脏检查,就是在用户进行可能改变 ViewModel 的操作的时候,对比以前老的 ViewModel 然后做出改变。
vue.js 则是采用 数据劫持 结合 发布者 - 订阅者模式 的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
本节参考文章:MVC/MVVM
14.axios 优点
同时支持浏览器端和服务端的请求
支持 promise
支持请求和和数据返回的拦截
转换请求返回数据,自动转换 JSON 数据
取消请求
客户端防止 xsrf 攻击
在 node 端支持设置代理
内部一些针对具体项目环境的二次封装
本节参考文章:axios 优点
15. 普通函数 / 箭头函数
1、当要求动态上下文的时候,就不能够使用箭头函数,箭头函数 this 的固定化
2、在使用 => 定义函数的时候,this 的指向是定义时所在的对象,而不是使用时所在的对象
3、不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误
4、不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 Rest 参数代替
5、不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数
class Animal {
constructor(){
this.type = ‘animal’
}
says(say) {
setTimeout(function () {
console.log(this.type + ‘says’ + say)
},1000)
}
}
var animal = new Animal()
animal.says(‘hi’) // undefined says hi
我们再来看看 => 的情况
class Animal() {
constructor() {
this.type = ‘animal’
}
says(say) {
setTimeout(() => {
console.log(this.type + ‘ says ‘ + say)
}, 1000)
}
}
var animal = new Animal()
animal.says(‘hi’) // animal says hi
本节参考文章:前端面试之 ES6 篇