JS硬核

126 阅读8分钟

Promise

Promise是异步编程的解决方案,比回调函数和事件更合理且更强大。可以理解为容器,里面保存着某个未来才会结束的事件和结果。

Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),该状态不受外界影响。状态可以从pending变为fulfilled,或者从pending变为rejected。一旦状态改变,就不会再变。

ES6规定,Promise对象是一个构造函数,用来生成Promise实例,它接受一个函数作为参数,该函数的两个函数参数分别是resolve和reject,resolve的作用是将Promise对象的状态从未完成变为成功,reject函数的作用是将Promise对象的状态从未完成变为失败。

方法

· Promise.all()用于将多个Promise实例包装成一个新的Promise实例(全部完成才算完成)

· Promise.race()同样将多个Promise实例包装成一个新的Promise实例(race取最快的结果)

· Promise.any()

· Promise.cath()

· Promise.finally()不管结果如何都要执行的操作

使用场景

同时拉取多个接口:Promise.all(),接口重试实现:Promise.race()

ES6

1. var let const区别

var的声明的变量会挂载在window上,而let和const不会。

let和const不存在变量提升,形成块级作用域

2. 箭头函数(this指向定义时所在的对象,而不是使用时所在的对象)

3. 数组新增的方法(map映射、reduce汇总、filter过滤、forEach迭代)

4. 解构赋值

5. 模板字符串

6. 扩展运算符

7. Symbol 是用来创建唯一性变量的(可以用作对象的key、可以使用Symbol   定义类的私有属性和方法)

8. Set(数组去重,只有键值没有键名)、Map(数据存储,键值对集合)

闭包(closure)

定义

有权访问另一个函数作用域中变量的函数。 ----JavaScript高级程序设计

闭包形成的条件

1.函数嵌套

2.内部函数引用外部函数的局部变量

闭包使用场景

1.return回一个函数

2.函数作为参数

3.循环赋值

闭包的作用

1.保护函数的私有变量不受外部干扰,形成不销毁的栈内存

2.保存,把一些函数内的值保存下来。闭包可以实现方法和属性的私有化。

闭包的优点

1.避免全局变量的污染

2.延长局部变量的生命周期

作用域和作用域链

作用域

简单来说,作用域是指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限。

作用域链

当可执行代码内部访问变量时,会先查找当前作用域下有无该变量,有则立即返回,没有的话则会去父级作用域中查找...一直找到全局作用域。我们把这种作用域的嵌套机制称为作用域链。

作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。如果上下文是函数,则其活动对象用作变量对象。活动对象最初只有一个定义变量:arguments。作用域中的下一个变量对象来自包含上下文,再下一个对象来自下一个包含上下文,以此类推直到全局上下文;全局上下文的变量对象始终是作用域链的最后一个变量。

with语句:会向作用域链前端添加指定对象。

with ( object ){
statement,
method

}
with语句将object添加到作用域链的头部,然后执行函数体内部代码,最后把作用域链恢复到原始状态。

原型和原型链

原型理解

JavaScript 是基于原型的语言,原型类似于经典面向对象语言当中的类,我们可以利用 JavaScript 原型让我们使用一种类风格的面向对象和继承技术进行编码。但是和传统面向对象语言不同,JavaScript 通过原型来继承和实例化的时候,并不会像传统面向对象语言那样将类的行为复制到实例或者子类当中去,而是将多个对象进行关联来实现。

原型实现

JavaScript 当中的所有函数在初始化的时候都有一个 prototype 属性,该属性指向的就是通过调用构造函数创建的实例对象的原型,使用原型对象的好处是我们可以预定义属性,方法。这些属性和方法会被实例对象所共享。

构造函数.prototype.proto ****等于 Object.prototype

Object.prototype.proto 等于顶层原型 null

构造函数.proto 等于 Function.prototype

构造函数.proto.proto 等于 Object.prototype

原型链

相互关联的原型对象的链接被称为原型链, 当我们读取实例属性或者方法的时候, 会通过[[prototype]]查找即沿着原型链进行委托查找,一直找到最顶层为止。

Instanceof:判断一个实例是否属于某构造函数

缺点:  instanceof 底层原理是检测构造函数的 prototype 属性是否出现在某个实例的原型链上,如果实例的原型链发生变化,则无法做出正确判断。

constructor :实例的构造函数属性 constructor 指向构造函数本身。

缺点:  如果 arr 的 constructor 被修改,则无法做出正确判断

Delete:删除对象的某个属性

判断this指向

this的绑定规则有四种:默认绑定,隐式绑定,显式绑定,new绑定.

1. 函数是否在 new 中调用(new绑定),如果是,那么 this 绑定的是new中新创建的对象。

2. 函数是否通过 call,apply 调用,或者使用了 bind (显式绑定),如果是,那么this绑定的就是指定的对象。

3. 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this 绑定的是那个上下文对象。一般是 obj.foo()。谁调用就指向谁。

4. 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到 undefined,否则绑定到全局对象。

5. 如果把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind, 这些值在调用时会被忽略,实际应用的是默认绑定规则。

6. 箭头函数没有自己的 this, 它的this继承于上一层代码块的this。

Call()方法: 调用另一个对象的方法,call()方法分别接受参数。

Apply()方法: 调用另一个对象的方法,apply() 方法接受数组形式的参数。

  1. call 、 apply 、bind 均能改变this 指向

  2. bind每次执行产生一个新函数,call、apply 不会

3. call ,bind 接收多个参数绑定到函数,参数单一传入,apply 接收方式为数组

跨域

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。

解决办法

1.CORS(跨域资源共享 Cross-origin resource sharing),它允许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它需要浏览器和服务器的同时支持。

2.JSONP(只能支持get请求):当需要跨域请求时,不使用AJAX,转而生成一个script元素去请求服务器,由于浏览器并不阻止script元素的请求,这样请求可以到达服务器。服务器拿到请求后,响应一段JS代码,这段代码实际上是一个函数调用,调用的是客户端预先生成好的函数,并把浏览器需要的数据作为参数传递到函数中,从而间接的把数据传递给客户端。

(1)、准备好一个函数,相对于AJAX的回调函数

(2)、生成一个script元素跨域访问服务器地址

(3)、服务器响应一段JS函数调用,把数据作为参数传递

3.配置代理:跨域在Vue cli中要想实现跨域请求,需要配置一些内容。首先在axiosdemo项目目录中创建一个vue.config.js文件,该文件是Vue脚手架项目的配置文件,在这个文件中设置反向代理。

图片1.png

单例(Singleton)

1.单例模式顾名思义保证一个类仅有一个实例,并且提供一个访问它的全局访问点

2.单例的好处是可以减少不必要的开销例如页面需要展示一个弹框,那么这个弹框只在首次的时候会进行创建,之后在进行点击的时候使用的都是之前创建好的

3.像Vue框架中生使用的new Vue就应用了单例模式

优点

单例模式因为是只有一个实例避免了重复的创建销毁占用内存,经常应用在一个弹框或者对于一个用户配置一个购物车的情况,或者是全局状态管理等类似现在流行的vuex/mobx等

缺点

在动态对象的扩展上比较差

深拷贝和浅拷贝

简单的深拷贝

JSON.parse(JSON.stringifj(obj))

浅拷贝

1. Array.from() 可以很容易的实现数组的浅拷贝

2. Array.concat() 、Array.slice()都可以实现数组浅拷贝

3. Object.assign() 实现对象的浅拷贝