前端知识点总结(一)
Updated:
@TOC
一、ES6
1. let const 和var 的区别
a. let和const的区别
- 不存在变量提升
let 改变了语法行为,它所声明的变量一定要在声明后使用,否则就会报错 - 暂时性死区
如果区块中存在let 和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域,只要在声明之前就使用这些变量,就会报错
本质:只要进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现时,才可以获取和使用该变量 - 不允许重复声明
2. promise
a. promise是什么?
简单来说,就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法来说,promise是一个对象,从他可以获取异步操作的结果。
promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
b. promise的特点
- 对象的状态不受外界影响。
promise 对象代表一个异步操作,有以下3种状态:- pending(进行中)
- fulfilled(已成功)
- rejected(已失败)
只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
promise的汉语意思是“承诺”,表示其他手段无法改变
- 一旦状态改变就不会再变,任何时候都可以得到这个结果
promise对象的状态改变只有两种可能:- pending–>fulfilled(从进行中变为已成功)
- pending–>rejected(从进行中变为已失败)
只要这两种情况发生,状态就凝固了,不会再改变,一直保持这个结果,这时候就被称为resolved(已定型)。就算改变已经发生,再对promise 对象添加回调函数,也会立即得到这个结果。
这与事件(event)完全不同,如果错过了它,再去监听是得不到的。
c. promise 的作用
可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,promise 对象提供了统一的接口,使得控制异步操作更加容易。
d. promise 的缺点、
- 无法取消promise, 一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,promise 内部抛出的错误不会反应到外部
- 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
如果某些事件不断的反复发生,使用stream 模式nodejs.org/api/stream.html,是比部署promise更好的选择
e. promise基本用法
1 | var promise = new promise(function(resolve, reject){ |
promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve 和 reject。 他们是两个函数。由js提供,不用自己部署。
f. .then方法指定resolved 和 rejected 状态的回调函数
1 | promise.then(function(value){ |
then 方法可以接受两个回调函数作为参数。
- 第一个回调函数是 promise 对象的状态变为 resolved 时调用
- 第一个回调函数是 promise 对象的状态变为 rejected 时调用(这个函数是可选的,不一定要提供。)
两个函数都接受 promise 对象传出的值作为参数。
3. 箭头函数
允许使用箭头定义函数
1
2
3
4var f = v => v
var f = function(v) {
return v;
}使用圆括号代表参数部分
1
2
3
4
5
6
7
8
9var f = () => 5;
var f = function(){
return 5
}
var sum = (num1, num2) => num1 + num2
var sum = function(num1, num2){
return num1 + num2
}如果箭头函数的代码块多于一条语句,就要使用大括号将其括起来,并使用return 返回
1
2
3
4var sum = (num1, num2) => num1 + num2
var sum = function(num1, num2){
return num1 + num2
}如果箭头函数直接返回一个对象,必须在对象外面加上括号
1
var getTempItem = id => ({id: id,name:"Temp"})
箭头函数可以与变量解构结合使用
1
2
3
4const full = ({first, last}) => first + '' + last
function full(person){
return person.first + '' + person.last
}简化回调函数
1
2
3
4
5[1,2,3].map(function (x){
return x*x;
})
// 箭头函数
[1,2,3].map(x => x*x)
1 | //even |
注意事项
- 箭头函数体内的this 对象就是定义时所在的对象,而不是使用时所在的对象
this对象的指向是可变的,但在箭头函数中它是固定的
箭头函数可以让this 指向固定化,有利于封装回调函数
this指向固定化原因
this指向固定化并不是因为箭头函数内部由绑定this的机制,实际原因是箭头函数根本没有this,导致内部的this 就是外层代码块的this(正是因为没有this 所以不能用作构造函数)
由于箭头函数没有自己的this,当然不能用call(),apply(),bind()这些方法改变this 的指向1
2
3
4
5
6
7
8function foo(){
setTimeout(() =>{
console.log('id:', this.id);
}, 100)
}
var id = 21;
foo.call({id:42})
//id:42
如果是普通函数,执行时this 应该指向全局对象window,即应该输出21
箭头函数导致this 总是指向函数定义生效时所在的对象
箭头函数的缺点
- 不可以当做构造函数。也就是说,不可以使用new命令,否则就会抛出一个错误
- 不可以使用arguments 对象,该对象在函数体内不存在。如果要使用,可以使用rest 参数代替
- 不可以使用 yield 命令,因此箭头函数不能用作Generator 函数
二、vue
1. 计算属性
a. 为什么会有计算属性
减少模板中的复杂逻辑,容易维护模板
b. 如何使用计算属性
1 | <div id="example"> |
1 | var vm = new Vue({ |
结果1
2Original message: "Hello"
Computed reversed message: "olleH"
这里我们声明了一个计算属性 reversedMessage。我们提供的函数将用作属性 vm.reversedMessage 的 getter 函数:1
2
3console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
你可以打开浏览器的控制台,自行修改例子中的 vm。vm.reversedMessage 的值始终取决于 vm.message 的值。
你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
c. 计算属性缓存和方法(method)的对比
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
每当触发重新渲染时,调用方法将总会再次执行函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
d. 计算属性和侦听属性(watch)的对比
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。1
<div id="demo">{{ fullName }}</div>
watch:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
计算属性:1
2
3
4
5
6
7
8
9
10
11
12var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
e. 计算属性的setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
现在再运行 vm.fullName = ‘John Doe’ 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。
2. 自定义指令
a. 为什么会有自定义指令
需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
b. 怎么使用自定义指令?
例 : autofocus1
2
3
4
5
6
7
8// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
如果想注册局部指令,组件中也接受一个 directives 的选项:1
2
3
4
5
6
7
8directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus 属性,如下:1
<input v-focus>
3. 父子组件
原文:https://segmentfault.com/a/1190000014704088?utm_source=channel-hottest
a. 父组件通过 Prop向子组件传递数据
- 首先父组件通过components引入子组件
- 如果要传入子组件的值是动态的.可以将该值双向绑定在调用的子组件上
- 子组件只需要做一件事,那就是通过props接收
父组件:
子组件:
b. 子组件往父组件传值($emit)
可以定义一个事件来触发响应的$emit使父组件可以知道有事件改变,进而接收对应的参数
父组件:
子组件:
定义一个事件来触发:
三、http
1. get和post在url协议上的区别
Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。
GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
- GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456
POST方法是把提交的数据放在HTTP包的Body中. - GET提交的数据大小有限制(因为浏览器对URL的长度有限制),
而POST方法提交的数据没有限制. - GET方式需要使用Request.QueryString来取得变量的值,
而POST方式通过Request.Form来获取变量的值。 - GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
2. get请求和post请求的区别
- get
一般用来查询操作,url 地址有长度限制,请求的参数都是暴露在url地址当中,如果传递中文参数,需要自己进行编码操作,安全性较低 - post
请求方式主要用来提交数据,没有数据长度的限制,提交的数据内容存在于http 请求体中,数据不会暴露在url地址中
3. 跨域
1. 什么是跨域
跨域的概念:协议、域名、端口都相同才是同域,否则都是跨域
2. 为什么会有跨域
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
同源策略限制了以下行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 JS 对象无法获取
- Ajax请求发送不出去
出于安全考虑,服务器不允许ajax 跨域获取数据,但是可以跨域获取文件内容。
3. 常见的跨域场景
1 | http://www.nealyang.cn/index.html 调用 http://www.nealyang.cn/server.php 非跨域 |
4. 跨域的解决方案
原文:https://juejin.im/post/5a2f92c65188253e2470f16d
a. jsonp
- jsonp 是什么?
jsonp 并不是一种数据格式(而json是一种数据格式),jsonp 是用来解决跨域获取数据的一种解决方案。
jsonp跨域其实也是JavaScript设计模式中的一种代理模式。 - 怎么解决的?
在html页面中通过相应的标签从不同域名下加载静态资源文件是被浏览器允许的,所以我们可以通过这个“犯罪漏洞”来进行跨域。
通过标签的src 属性获取js 文件的js 脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,本质上使用的并不是ajax技术。
1 | //原生的实现方式 |
当然,jquery也支持jsonp的实现方式1
2
3
4
5
6
7
8
9$.ajax({
url:'http://www.nealyang.cn/login',
type:'GET',
dataType:'jsonp',//请求方式为jsonp
jsonpCallback:'callback',
data:{
"username":"Nealyang"
}
})
虽然这种方式非常好用,但是一个最大的缺陷是,只能够实现get请求
b. cors
- 简介
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。IE8+:IE8/9需要使用XDomainRequest对象来支持CORS。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
两种请求(浏览器对这两种请求方式是不一样的)
简单请求
请求方式为HEAD、POST 或者 GET
http头信息不超出一下字段:Accept、Accept-Language 、 Content-Language、 Last-Event-ID、 Content-Type(限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain)非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。