文章目录
- 1.对原型、原型链的理解
- 2.原型修改、重写
- 3.原型链指向
- 4.对闭包的理解
- 5. 对作用域、作用域链的理解
- 6.对执行上下文的理解
- 7.对this对象的理解
- 8. call() 和 apply() 的区别?
- 9.异步编程的实现方式?
- 10.setTimeout、Promise、Async/Await 的区别
- 11.对Promise的理解
- 12.Promise的基本用法
- Promise解决了什么问题
1.对原型、原型链的理解
原型:是一个对象,是函数的一个属性prototype(任何函数都有),通过该函数实例化出来的对象都可以继承得到原型上的所有属性和方法。
原型链:访问实例对象的属性时,首先在自己身上查找,如果自身不存在,那么就去它的原型对象(prototype属性)上查找,这个原型对象又有自己的原型,直到找到Object原型(为null),以此形成的类似链条的结构就称为原型链。
- 对象的proto保存着该对象的构造函数的prototype
2.原型修改、重写
- 原型的修改,修改以后对象所有的实例都可以使用新增的方法
function Person(name) {this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
- 重写,用一个新的对象来替换原来的原型。
Person.prototype = {getName: function() {}
}
注意
:重写原型时,对象的构造函数可能会指向根构造函数Object
Person.prototype = {getName: function() {}
}
var p = new Person('hello')
p.constructor = Person
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
3.原型链指向
function Person(name) {this.name = name
}var p = new Person('John')
var p1 = new Person('Mike')console.log(p.__proto__) // Person.prototype
console.log(Person.prototype.__proto__) // Object.prototype
console.log(p.__proto__.__proto__) // Object.prototype
console.log(p.__proto__.constructor.prototype.__proto__) // Object.prototype
console.log(Person.prototype.constructor.prototype.__proto__) // Object.prototype
console.log(p1.__proto__.constructor) // Person
console.log(Person.prototype.constructor) // Person
4.对闭包的理解
概念:
闭包的含义是一个函数有权访问另一个函数作用域的函数(A函数中创建B函数,函数B可以以访问到函数A中的变量,函数B就是闭包)。
用途
:在函数外部能够访问到函数内部的变量;函数运行结束以后会保留对这个变量对象的引用,不会回收对象。
不足
:占用更多内存,会引起内存泄漏。
应用场景
:防抖节流–保存上一次运行的setTimeout(不用闭包会重新创建定时器,获取不到上一次定时器时间);函数作为返回值;vue的响应式原理;函数嵌套;
5. 对作用域、作用域链的理解
概念
:作用域–>变量或者是函数能作用的范围。
作用域链:当使用一个变量时,首先在当前作用域查找,如果没找到,就去它的上层作用域去查找,直到找到或者到了全局作用域,这样形成的链式查找称为作用域链。
作用域分为函数作用域,全局作用域以及块级作用域。
全局作用域:常常定义在函数外部,全局作用域变量可以在任意位置访问。
局部作用域(函数作域):定义在函数内部,只能在函数中使用的变量,作用范围是从函数开始到结尾。
块级作用域:ES6 提供 let & const 变量实现块级作用域。
块级作用域应用场景
:内部变量会覆盖外部变量(用来计数的循环变量泄漏为全局变量)。
作用
:作用域链的作用是保证对执行环境有权访问的所有变量的有序访问,通过作用域链,可以访问到外层环境的变量和函数。
6.对执行上下文的理解
执行上下文分为三种:
全局执行上下文:只有一个,程序首次运行时创建,它会在浏览器中创建一个全局对象(window对象),使this指向这个全局对象。
函数执行上下文:函数被调用时创建,每次调用都会为该函数创建一个新的执行上下文。
Eval 函数执行上下文。
执行上下文
:在执行一点JS代码之前,需要先解析代码。解析的时候会先创建一个全局执行上下文环境
,先把代码中即将执行的变量、函数声明都拿出来,变量先赋值为undefined,函数先声明好可使用。这一步执行完了,才开始正式的执行程序。执行上下文栈
:JavaScript引擎使用执行上下文栈来管理执行上下文。
7.对this对象的理解
概念
:this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。
指向
函数调用:指向全局对象window
方法调用:指向这个方法的对象
构造器调用:如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
apply 、 call 和 bind 调用:这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。
8. call() 和 apply() 的区别?
都是改变函数this指向的方法
- apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。
- call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。
9.异步编程的实现方式?
同步是指一个任务完成后才能执行另一个任务。
异步是把一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。排在异步任务后面的代码,不用等待异步任务结束会马上运行。
异步编程的方法(JS 异步编程进化史:callback -> promise -> generator -> async + await)
:
- 回调函数(回调函数是一个函数,它被作为参数传递给另一个函数(通常称为“主调函数”或“高层函数”)。当主调函数完成某些操作或满足特定条件后,它会调用这个回调函数。):容易造成回调地狱问题
- Promise:有时会造成多个 then 的链式调用
- 生成器Generators/ yield
- async/await:async 函数是 generator 和 promise 实现的一个自动执行的语法糖,它内部自带执行器,当函数内部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将会等待 promise 对象的状态变为 resolve 后再继续向下执行。
10.setTimeout、Promise、Async/Await 的区别
- setTimeout
console.log('script start') //1. 打印 script start
setTimeout(function(){console.log('settimeout') // 4. 打印 settimeout
}) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end') //3. 打印 script start
// 输出顺序:script start->script end->settimeout
- Promise : Promise本身是同步的立即执行函数,当在executor中执行resolve或者reject的时候, 此时是异步操作, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行
console.log('script start')
let promise1 = new Promise(function (resolve) {console.log('promise1')resolve()console.log('promise1 end')
}).then(function () {console.log('promise2')
})
setTimeout(function(){console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
- async/await:await的含义为等待,也就是 async 函数需要等待await后的函数执行完成并且有了返回结果(Promise对象)之后,才能继续执行下面的代码。
async function async1(){console.log('async1 start');await async2();console.log('async1 end')
}
async function async2(){console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 输出顺序:script start->async1 start->async2->script end->async1 end
11.对Promise的理解
Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调。
Promise的实例有三个状态:Pending(进行中),Resolved,Rejected
- Promise 是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。
- 实例的状态只能由 pending 转变 resolved 或者rejected 状态,并且状态一经改变,就凝固了,无法再被改变了。
- 在构造 Promise 的时候,构造函数内部的代码是立即执行的
12.Promise的基本用法
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
const promise = new Promise(function(resolve, reject) {// ... some codeif (/* 异步操作成功 */){resolve(value);} else {reject(error);}
});
- 一般情况下都会使用new Promise()来创建promise对象,但是也可以使用promise.resolve和promise.reject这两个方法
Promise.resolve(11).then(function(value){console.log(value); // 打印出11
});
方法
- then(),then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中第二个参数可以省略。返回值根据回调函数的结果
- catch() 该方法相当于then方法的第二个参数,指向reject的回调函数。
- all() 它接收一个数组,数组的每一项都是一个promise对象。当数组中所有的promise的状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected,那么all方法的状态就会变成rejected。返回的是一个数组,保存着每一个promise对象resolve执行时的值。失败返回最先失败的值
- race 接受的参数是一个每项都是promise的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。
- finally 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
Promise解决了什么问题
使用ajax发一个A请求后,成功后拿到数据,需要把数据传给B请求;那么需要如下编写代码:
let fs = require('fs')
fs.readFile('./a.txt','utf8',function(err,data){fs.readFile(data,'utf8',function(err,data){fs.readFile(data,'utf8',function(err,data){console.log(data)})})
})
- List item后一个请求需要依赖于前一个请求成功后,将数据往下传递,会导致多个ajax请求嵌套的情况,代码不够直观。
- 如果前后两个请求不需要传递参数的情况下,那么后一个请求也需要前一个请求成功后再执行下一步操作,这种情况下,那么也需要如上编写代码,导致代码不够直观。