function Person() {}
Person.prototype.name = ‘Zaxlct’;
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
//JS 在创建对象的时候,都有一个__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。
//每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性
// 对象 person1 有一个 __proto__属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype
console.log(person1.__proto__ == Person.prototype) //true
//所有函数对象的__proto__都指向Function.prototype
String.__proto__ === Function.prototype // true
String.constructor == Function //true
详解
- 原型继承
function Parent () { this.name = 'Parent' this.sex = 'boy'}function Child () { this.name = 'child'}// 将子类的原型对象指向父类的实例Child.prototype = new Parent()//优:继承了父类的模板,又继承了父类的原型对象//缺:1.无法实现多继承(因为已经指定了原型对象了)// 2.创建子类时,无法向父类构造函数传参数
- 构造函数继承
在子类构造函数内部使用call或apply
来调用父类构造函数,复制父类的实例属性给子类。
function Parent (name) { this.name = name}function Child () { //用.call 来改变 Parent 构造函数内的指向 Parent.call(this, 'child')}//优:解决了原型链继承中子类实例共享父类引用对象的问题,实现多继承,创建子类实例时,可以向父类传递参数//缺:构造继承只能继承父类的实例属性和方法,不能继承父类原型的属性和方法
- 组合继承组合继承就是将原型链继承与构造函数继承组合在一起。
- 使用原型链继承来保证子类能继承到父类原型中的属性和方法
- 使用构造继承来保证子类能继承到父类的实例属性和方法
- 寄生组合继承
- class继承
在class
中继承主要是依靠两个东西:
extends
super
class Parent { constructor (name) { this.name = name } getName () { console.log(this.name) }}class Child extends Parent { constructor (name) { super(name) this.sex = 'boy' }}
Event Loop 事件循环
同步与异步、宏任务和微任务分别是函数两个不同维度的描述。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入任务队列(task queue
)的任务,只有等主线程任务执行完毕,任务队列开始通知主线程,请求执行任务,该任务才会进入主线程执行。
当某个宏任务执行完后,会查看是否有微任务队列。如果有,先执行微任务队列中的所有任务;如果没有,在执行环境栈中会读取宏任务队列中排在最前的任务;执行宏任务的过程中,遇到微任务,依次加入微任务队列。栈空后,再次读取微任务队列里的任务,依次类推。
同步(Promise)>异步(微任务(process.nextTick ,Promises.then, Promise.catch ,resove,reject,MutationObserver)>宏任务(setTimeout,setInterval,setImmediate))
await阻塞 后面的代码执行,因此跳出async函数执行下一个微任务
Promise 与 Async/Await 区别
async/await是基于Promise实现的,看起来更像同步代码,
- 不需要写匿名函数处理Promise的resolve值
- 错误处理: Async/Await 让 try/catch 可以同时处理同步和异步错误。
- 条件语句也跟错误处理一样简洁一点
- 中间值处理(第一个方法返回值,用作第二个方法参数) 解决嵌套问题
- 调试方便
const makeRequest = () => { try { getJSON().then(result => { // JSON.parse可能会出错 const data = JSON.parse(result) console.log(data) }) // 取消注释,处理异步代码的错误 // .catch((err) => { // console.log(err) // }) } catch (err) { console.log(err) }}
使用aync/await
的话,catch能处理JSON.parse
错误:
const makeRequest = async () => { try { // this parse may fail const data = JSON.parse(await getJSON()) console.log(data) } catch (err) { console.log(err) }}
promise怎么实现链式调用跟返回不同的状态
实现链式调用:使用.then()
或者.catch()
方法之后会返回一个promise
对象,可以继续用.then()
方法调用,再次调用所获取的参数是上个then
方法return
的内容
- promise的三种状态是
fulfilled
(已成功)/pengding
(进行中)/rejected
(已拒绝) - 状态只能由 Pending –> Fulfilled 或者 Pending –> Rejected,且一但发生改变便不可二次修改;
- Promise 中使用
resolve
和reject
两个函数来更改状态; - then 方法内部做的事情就是状态判断:
- 如果状态是成功,调用成功回调函数
- 如果状态是失败,调用失败回调函数
函数柯里化
柯里化(Currying)
是把接收多个参数的原函数变换成接受一个单一参数(原来函数的第一个参数的函数)并返回一个新的函数,新的函数能够接受余下的参数,并返回和原函数相同的结果。
- 参数对复用
- 提高实用性
- 延迟执行 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。柯里化的函数可以延迟接收参数,就是比如一个函数需要接收的参数是两个,执行的时候必须接收两个参数,否则没法执行。但是柯里化后的函数,可以先接收一个参数
// 普通的add函数function add(x, y) { return x + y}// Currying后function curryingAdd(x) { return function (y) { return x + y }}add(1, 2) // 3curryingAdd(1)(2) // 3
JS对象深克隆
递归遍历对象, 解决循环引用问
解决循环引用问题,我们需要一个存储容器存放当前对象和拷贝对象的对应关系(适合用key-value的数据结构进行存储,也就是map),当进行拷贝当前对象的时候,我们先查找存储容器是否已经拷贝过当前对象,如果已经拷贝过,那么直接把返回,没有的话则是继续拷贝。
function deepClone(target) { const map = new Map() function clone (target) { if (isObject(target)) { let cloneTarget = isArray(target) ? [] : {}; if (map.get(target)) { return map.get(target) } map.set(target,cloneTarget) for (const key in target) { cloneTarget[key] = clone(target[key]); } return cloneTarget; } else { return target; } } return clone(target)};
暂无评论内容