本篇绪论
1, 宏任务、微任务
2,创建对象
3,instanceof
1, 宏任务、微任务
JS是单线程执行的语言,在同一时间内只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS出现了同步任务和异步任务。
同步任务:在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈
异步任务:不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中进行执行。由于主线程不断重复的获取任务、执行任务、再获取再执行...,所以这种机制被叫做事件循环(Event Loop)
任务队列中又分为宏任务、微任务
console.log(1)
setTimeout(_ => {
console.log(2)
}, 0)
Promise.resolve().then(res => {
console.log(3)
}) // 1 3 2
常见的微任务:Promise、process.nextTick、MutationObserver
常见的宏任务: script、setTimeout、setInterval、setImmediate
Event loop执行顺序:
先执行宏任务script,并执行里面的同步任务,执行栈为空后查询是否存在微任务,存在立即执行,然后开始下一轮的事件循环。
定时器
定时器:超时定时器setTimeout,间歇调用定时器setInterval
定时器是宏任务,在定时器计时完毕后会将它的回调函数加入到任务队列中,等待下一次的事件循环。也就是说下一次执行的定时器是回调函数,计时已经在定时器模版中完成了。
promise
setTimeout(_ => {
console.log(1)
}, 0)
new Promise(resolve => {
console.log(2)
resolve()
})
.then(_ => {
console.log(3)
})
console.log(4)
// 2 4 3 1
2,创建对象
JS对每个创建的对象都会设置一个原型,指向它的原型对象。
当我们访问一个对象的属性时(obj.xxx),JS引擎会在当前对象上找该属性,如果没找到,会去其原型对象上找,如果还找不到就一直上溯到Object.prototype对象,最后还是没找到就只能返回undefined了。
// 创建一个Array对象
const arr = [1,2,3,4,5]
其原型链:
arr ----> Array.prototype ----> Object.prototype ----> null
// 创建一个函数对象
function fn () {return 1}
其原型链:
fn ----> Function.prototype ----> Object.prototype ----> null
构造函数方法创建对象
function Student(name) {
this.name = name;
this.hello = function () {
console.log('Hello, ' + this.name + '!')
}
}
这是一个普通的函数,但是在js中,可以用关键字new来调用这个函数,并返回一个对象
const p1 = new Student('xiaowang')
console.log(p1)
console.log(p1.hello())
image
如果不new,这就是一个普通函数,它返回undefined,如果写了new它就是一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就是说,不需要在最后写return this
新创建的p1的原型链:
p1 ----> Student.prototype ----> Object.prototype ----> null
也就是说,p1的原型指向Student的原型
用new Student()创建的对象还从原型上获得了一个constructor属性,它指向函数Student本身
console.log(p1.constructor === Student.prototype.constructor) // true
console.log(Student.prototype.constructor === Student) // true
console.log(p1 instanceof Student) // true
console.log(Object.getPrototypeOf(p1) === Student.prototype) // true
// getPrototypeOf用来获取p1对象的原型对象
Student.prototype指向的对象就是p1的原型对象,这个原型对象自己还有个属性constructor,指向Student本身。
函数Student有个属性prototype指向p1的原型对象,但是p1对象没有prototype这个属性,不过可以用proto这个非标准用法来查看
我们认为p1对象继承Student
const p1 = new Student('p1')
const p2 = new Student('p2')
console.log(p1.hello === p2.hello) // false
p1和p2各自的hello是一个函数,但是它们是两个不同的函数,虽然函数名称和代码都是相同的
如果我们通过new Student创建了很多对象,这些对象的hello函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存。
function Student(name) {
this.name = name
}
Student.prototype.hello = function () {
console.log(this.name)
}
const p1 = new Student('p1')
const p2 = new Student('p2')
console.log(p1.hello === p2.hello) // true
3,instanceof
instanceof用于判断引用类型属于哪个构造函数的方法。
const arr = []
arr instanceof Array // true
typeof arr // object
instanceof可以在继承关系中用来判断一个实例是否属于它的父类型
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo() //JavaScript 原型继承
var foo = new Foo()
console.log(foo instanceof Foo)
console.log(foo instanceof Aoo)
foo instanceof Foo的判断逻辑:foo的proto一层一层往上,是否对应到Foo.prototype,再往上,看是否对应着Aoo.prototype,再试着判断 foo instanceof Object
即instanceof可以用来判断多层继承关系
网友评论