1、原型原型链
题1:
熟悉使用new创建对象的原理:
(1)新对象的隐式原型执向构造函数的显示原型
B._proto_ = A.protoType;
(2)将构造函数指向新实例对象。
A.call(B)
题2:
输出--》2, undefined
解析:(1)a.x首先要在自己的构造函数中查找,没有采取原型上找,这里有this.x = x.所以a.x = 2;
题3:
console.log(typeof ''.prototype);
console.log(typeof ''.__proto__);
console.log(typeof ''.__proto__ === typeof ''.prototype);
undefined、object、false
(1)字符串’‘,是String构造函数实例化的,实例上有隐式原型_proto_, 没有显示原型protoType,所以是undefined。
(2)''.__proto__ = String.protoType = Object类型;
(3) typeof ''.prototype 即typeof undefined 为undefined
题4:
function Person(age){
this.age = age;
}
Person.prototype = {
constructor:Person,
getAge:function(){
console.log(this.age);
},
}
var ldh = new Person(24);
Person.prototype.age = 18;
Object.prototype.age = 20;
ldh.getAge();
对象在调用方法和属性时依靠原型链的顺序进行查找,先从自身查找,然后是构造函数的原型对象,接着是Object的原型对象,一旦找到时停止查找,找不到则返回undefined。同时,原型对象中的this仍然指向实例对象,而非原型对象,在本题中,实例对象先调用原型对象的getAge()方法,然后输出age属性值,由于该实例对象已经有age属性,同时其原型链中,原型对象和原型对象的原型对象即Object对象均有age属性,依据上述查找规则,最终输出结果为实例对象的age,即为24。
题5:
class Phone{
constructor(brand){
this.brand = brand;
}
call(){}...①
}
function playGame(){console.log("我可以打游戏")};
function photo(){console.log("我可以拍照")};
console.log(typeof Phone);...②
var p = new Phone('华为');
console.log(p.brand);...③
1、call方法是定义在类Phone的prototype对象上
2、类的本质是函数,实际上,ES6中的类可以视为ES5中构造函数的另一种写法,所以②式的输出结果为function而不是Object。
3、p为类的实例对象,该对象有一个属性brand,属性值为华为
4、若想一次性给类添加playGame和photo两个实例方法,可以使用Object.assign(Phone.prototype,{playGame,photo})
题6:
function father() {
this.num = 935;
this.work = ['read', 'write', 'listen'];
}
function son() {}
son.prototype = new father();
let son1 = new son();
let son2 = new son();
son1.num = 117;
son1.work.pop();
console.log(son2.num);
console.log(son2.work);
// 解析
function father() {
this.num = 935;
this.work = ['read', 'write', 'listen'];
}
function son() {}
son.prototype = new father();
// son.prototype = { num:935, work:['read','write','listen'] }
let son1 = new son(); // son1 = { }
let son2 = new son(); // son2 = { }
son1.num = 117; // son1 = { num: 117 }
son1.work.pop();
//son1自己没有work,去原型里找到work,并删除work里的最后一项,
//此时son.prototype = { num:935, work:['read','write'] }
console.log(son2.num);// son2自己没有num,去原型里找,有num:935
console.log(son2.work);
//son1和son2原型是同一个,所以此时原型里的work是['read', 'write']
---》935、 ['read', 'write']
2、setTimeout异步任务/宏任务/微任务/事件机制
Promise面试题汇总_CUG-GZ的博客-CSDN博客_promise面试题
题1:
->>> 0 1 2 2
(1)上面的循环和下面的循环,都是同步代码,先执行上面的,往事件队列中放了两个异步的宏任务,任务1和任务2(RW1,RW2:都是使用let定义的块级作用域,所以RW1中i为0,RW2中i为1)
此时事件队列【RW1(i=0),RW2(i=1)】
(2)下面的循环,继续往事件队列中添加宏任务RW3、RW4,不过使用的var,没有块级作用域,定时器执行时,需要使用外面作用域中i的值。
此时事件队列【RW1(i=0),RW2(i=1),RW3(i=?),RW4(i=?)】
(3)外层的i为2,因为当i=0,i=1时,设定了两个任务,i=2时不符合条件,但也执行了,同步代码执行完毕,i=2最后。
(4)开始执行事件队列,输出0,1,2,2。
补充:如果上面定时器事件都是2000ms,也即是2s,那么结果是分别输出,还是一起输出》?
实际验证:等待2s之后,直接全部输出0,1,2,2。
题2:
for(var i=0;i<3;++i){
setTimeout(function(){
console.log(i);
},100);
}
3,3,3(100ms后一次输出3个3)这道题涉及了异步、作用域、闭包
settimeout是异步执行,100ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是3,所以此时再去执行任务队列里的任务时,i全部是3了。对于打印3次是:
每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了3次,就放了3次,当主线程执行完成后,才进入任务队列里面执行。
题3:
for(var i = 0; i < 5; i++){
setTimeout(function(){
console.log(i);
}, 1000 * i);
}
5 5 5 5 5(立即输出一个5,在每隔1s输出一个5)1000*i:这里的i实际不是异步任务要执行的函数,而是在塞进任务队列时,i值也即是定时执行的时间已经确认了。
待同步函数执行完之后,执行任务队列中的异步任务,异步任务的定时0s,1s,2s, 3s, 4s,所以可以看到的效果是,立即输出一个5,在每隔1s输出一个5
题4:
let date = new Date()
setTimeout(() => {
console.log('1')
}, 2000)
setTimeout('console.log(2)',1000);
setTimeout(function() {
console.log('3')
}, 1500);
while((new Date() - date) < 3000) {}
While所在是微任务,所以前3秒后在执行while函数,setTimeout函数虽然在各自对应时间后插入了队列,但是由于属于宏任务所以暂时还没有执行,直到while微任务完成,才按顺序输出。
--》3秒以后同时输出2 3 1
题5:
for(let i=0;i<2;i++){
setTimeout(function(){
console.log(i)
},100);
}
for(var i=0;i<2;i++){
setTimeout(function(){
console.log(i)
},100);
}
-》0 1 2 2
题6:
console.log(1);
let a = setTimeout(() => {console.log(2)}, 0);
console.log(3);
Promise.resolve(4).then(b => {
console.log(b);
clearTimeout(a);
});
console.log(5);
promise对象的then()方法属于微任务,而setTimeout()定时器函数为宏任务。在执行顺序处理上,js会先执行所有同步代码,然后执行微任务队列中的所有微任务,最后再继续执行宏任务。在本题中,先执行同步代码并输出1 3 5,接着执行Promise.resolve().then()方法,输出4,由于在then()方法内删除了定时器函数,所以不会再输出2,最终输出结果为1 3 5 4
题7:
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');
解析:
代码从上至下进行执行:
(1)首先碰到的就是Promise,是个微任务,放入任务队列中【WR1】
(2)继续执行碰到了一个宏任务,放入任务队列中【WR1,HR1】
(3)同步代码,打印出start。
(4)同步代码执行完,开始执行任务队列中任务。
(5)先执行微任务WR1,输出“promise1“, 遇到宏任务2加入任务队列【HR1,HR2】
(6)WR1微任务执行完,执行宏任务HR1。
(7)执行HR1,先输出“timer1”, 碰到微任务WR2,任务队列【HR2, WR2】
(8)宏任务R1执行完,任务队列中还有一个宏任务和微任务
(9)先执行微任务WR2,输出promise2,在执行宏任务输出提timer2
----> start ->promise1->timer1->promise2->timer2
题8:
function runAsync (x) {
const p = new Promise(r => setTimeout(() => r(x, console.log('ee--00:', x)), 1000))
return p
}
function runReject (x) {
const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log('ee--11:', x)), 1000 * x))
return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res => console.log('ee--22:', res))
.catch(err => console.log('ee--33:', err))
输出结果:
可以看到Promise.all执行四个promise实例,其中有reject的,所以promise.all状态不会变为fullfiled,也即是不会调用.then的回调函数。
(1)runAsync(1), runAsync(3), 是两个fullfied状态的实例,同时定时器为1s,所以1s之后同时输出1,3
(2)runReject(2)是reject状态,promise.all只要有一个实例状态变为reject,那么整体状态就是reject,会走.catch的回调,所以第2s会输出 2,Error: 2
(3)runReject(4)也是reject状态,但promise的实例状态不可逆,从reject->reject状态不变,不会触发调用回调函数,所有不会在执行.catch, 第4s输出4
// 1s后输出
ee--00: 1
ee--00: 3
// 2s后输出
ee--11: 2
ee--33: Error: 2
// 4s后输出
ee--11: 4
题9:
function runAsync(x) {
const p = new Promise(r =>
setTimeout(() => r(x, console.log(x)), 1000)
);
return p;
}
function runReject(x) {
const p = new Promise((res, rej) =>
setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x)
);
return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])
.then(res => console.log("result: ", res))
.catch(err => console.log(err));
// 先输出
0
Error: 0// 1s后同时输出
1
2
3
结果:
2、
第一:首先区分浏览器端和服务器端的js模块化规范。
1)浏览器端的js模块化规范:AMD 和 CMD
2)服务器端的js模块化规范:CommonJS(注:由NodeJS实现)
第二:浏览器端的js模块化规范分别由什么实现。
1)AMD是由require.js实现的(记忆法,认为A是Async异步, 依赖前置,就是所有的依赖必须放在最前面)
2)CMD是由sea.js实现的(依赖就近,所有依赖需要了再引入
//CMD Common Module Definition define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
//...
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})
//AMD Asynchronous Module Definition define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
//...
b.doSomething()
//...
})
Promise输出结果:
then 和finally的链式调用还没有理解!!!