(面试的时候总会被问到事件循环机制,在这里总结一下自己的理解)
了解了上述的既可以开始解从网上百度到的面试题了(嘿嘿嘿,来体验逐渐融会贯通,继而醍醐灌顶的感觉吧)
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('3');
resolve();
}).then(function() {
console.log('4');
})
})
new Promise(function(resolve) {
console.log('5');
resolve();
}).then(function() {
console.log('6');
})
setTimeout(function() {
console.log('7');
})
setTimeout(function() {
console.log('8');
new Promise(function(resolve) {
console.log('9');
resolve();
}).then(function() {
console.log('10');
})
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12');
})
console.log('13');
async function async1 () {
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2 () {
console.log('async2')
let p1 = Promise.resolve('promise then');
p1.then(function(value) {
console.log(value);
});
console.log('async2 after promise')
}
async function async3 () {
console.log('async3 start');
await async4();
console.log('async3 end')
}
async function async4 () {
console.log('async4')
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout')
}, 0);
async1();
async3();
new Promise(function (resolve) {
console.log('promise1');
resolve()
}).then(function () {
console.log('promise2')
});
console.log('script end')
里外煎透promise,配菜co模块&async
https://juejin.im/post/5e67a802e51d4526f76ecb9a
https://juejin.im/post/5e8edae5e51d4546b35655b2#heading-0
两位的文章都还是不错滴
// 1、vm.$nextTick
// 该函数的作用就是延迟 cb 到当前调用栈执行完成之后执行
export function nextTick (cb?: Function, ctx?: Object) {
// 传入的回调函数会在callbacks中存起来
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
// pending是一个状态标记,保证timerFunc在下一个tick之前只执行一次
if (!pending) {
pending = true
/**
* timerFunc 实现的就是根据当前环境判断使用哪种方式实现
* 就是按照 Promise.then和 MutationObserver以及setImmediate的优先级来判断,支持哪个就用哪个,如果执行环境不支持,会采用setTimeout(fn, 0)代替;
*/
timerFunc()
}
// 当nextTick不传参数的时候,提供一个Promise化的调用
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
// 2、process.nextTick
process.nextTick(callback[, ...args])
在没写出这个标题,脑子里就出现这么个意思“this指向的是其运行时所在的环境,一般指向window”;然而,坑之所以是个坑,那就代表没这么容易上岸!这句话主要指的是【非严格模式】下【普通函数调用】的this指向,如:
function testThis(){
console.log(this)
}
testThis(); // 打印window对象
然而,【严格模式】下,在【JavaScript高级程序设计】中如是说:“在严格模式下,未指定环境对象而调用函数,则this值不会转为window。除非明确把函数添加到某个对象或者调用appy()或call(),否则this值将是undefined”,所以是这样滴:
'use strict'
function testThis(){
console.log(this)
}
testThis(); // undefined
就是函数被当做一个对象的方法调用,使用【对象】.【方法】的方式,此时this指向被绑定的对象
var a = 1;
var obj = {
a: 2,
fn: function(){
console.log(this.a);
}
}
obj.fn() // 2
这里,大佬提醒注意document的绑定事件是属于方法调用模式,所以内部是dom对象,这样也确实很方便我们操作dom,合理便利。举得例子是这样的
document.addEventListener('click', function(e){
console.log(this); // document
setTimeout(function(){
console.log(this); // window
}, 200);
}, false);
而setTimeout为什么是window呢?也常有人问它为什么会丢失this呢?关于这个问题我也说不透,主要是从这里看来的setTimeOut,有这么几句话,__由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。备注:即使是在严格模式下,setTimeout()的回调函数里面的this仍然默认指向window对象, 并不是undefined。__读书少了,不知道是不是事件循环机制的道理,待研究。
'use strict'
setTimeout(() => {
console.log(this);
},200);
// 打印 window
参考文章的大佬帮助理解,setTimeout内的函数属于回调函数,可以这么理解,f1.call(null, f2),所以this指向window。
就是最终是函数调用,举了三个例子:
最普通的函数调用、函数嵌套、把函数赋值后调用
function fn(){
console.log(this); //window
}
fn();
function fn1(){
function fn2(){
console.log(this); //window
}
fn2();
}
fn1();
var obj = {
fn: function(){
console.log(this);
}
}
var fn1 = obj.fn;
fn1();//1
最后一种需要解释解释,因为这解释了我之前见过的这么一道题
var foo = {bar:function(){console.log(this)}}; (false || foo.bar)()
最后this指向的是window。obj.fn虽然是一个对象的函数,但是被赋值给fn1之后,fn1就是一个单纯的普通函数等待着被调用。所以这里在【非严格模式】下,无this或者说this为undefined和null的时候,它就是window;而【严格模式】,依然是undefined
'use strict'
var a = 1;
var obj = {
a: 2,
fn: function(){
console.log(this);
}
}
var fn1 = obj.fn;
fn1(); // undefined
所以这里__(false || foo.bar)()__可以理解为,前面的或语句是相当于定义了一个变量,变量被foo.bar赋值,调用则根据【非严格模式】指向window;【严格模式】,依然是undefined;
new一个函数时,背地里会创建一个连接到 prototype 成员的新对象,同时 this 会被绑定到那个新对象上。
function Person(name, age){
// 这里的this都是指向实例
this.name = name;
this.age = age;
this.sayAge = function(){
console.log(this.age);
}
}
var per = new Person('yw', 2);
per.sayAge(); // 2
关于这个的详细解释,嘿嘿嘿,估计要说说原型链了,后面补充
var num = 0;
function Obj (){
this.num = 1,
this.getNumLater = function(){
setTimeout(() => {
console.log(this.num);
}, 1000) //箭头函数中的this总是指向外层调用者,也就是Obj
setTimeout(function(){
console.log(this.num);
}.bind(this), 1000) //利用bind()将this绑定到这个函数上
}
}
这三个函数都是为了改变this的指向;
类型 | 接收参数 | 第一个参数 | 其余参数 | 返回 | 立即执行 |
---|---|---|---|---|---|
call | 多个 | this指向,默认window或undefined | 有多个即多个依次 | 无 | 是 |
apply | 两个 | this指向,默认window或undefined | arguments数组形式多个 | 无 | 是 |
bind | 两个 | 明显的this指向 | arguments数组形式多个 | 返回一个函数,等待调用 | 否,函数调用 |
function fn(a, b, c){
console.log(a, b, c);
}
var fn1 = fn.bind(null, 'yangwei');
fn('A', 'B', 'C'); // A B C
fn1('A', 'B', 'C'); // yangwei A B
fn1('B', 'C'); // yangwei B C
fn.call(null, 'yw'); // yw undefined undefined call 是把第二个及以后的参数作为 fn 方法的实参传进去,而 fn1 方法的实参则是在 bind 中参数中的基础上再往后排
在es6箭头函数下,call与apply失效;-- 待实践
node环境中无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this都指向空对象{} – 待实践
使用语法翻译:从this指向开始,找call、apply、bind前面的是操作,后面是参数。
var total = [].push.apply(arr1, arr2); —> this指向arr1,第二个参数是个数组对象,需要操作的是数据里每一个值;那么就是arr1 push arr2的每一项,就相当于concat;
第一次觉得“原型链和继承”看着是那么那么顺眼…