let a = {n:1}; let b = a; a.x = a = {n:2}; console.log(a.x); console.log(b.x);
解析
知识点:点的优先级大于等号的优先级;等号从右向左执行 promise
第一步:a=b, 因此a和b指向同一个内存地址
第二步:根据知识点,点号优先级高于,因此先执行a.x,即a和b都是 {n: 1, x: undefined}
第三步:等号从右向左执行,即a又变回了{n: 2}同时因而a指向了 { n : 2 } 再也不是以前的地址
第四步:执行a.x = a。左边的a是旧的a,等于b
b = { n:1, x:{n:2} }异步
输出:undefined {n: 2}async
let a = {n:1}; let b = a; b.n = a.f = {n:2}; console.log(a); console.log(b);
输出: {n:{n:2}, f:{n:2}}, {n:{n:2}, f:{n:2}}函数
function user(obj){ obj.name = 'aaa'; obj = new Object(); obj.name = 'bbb'; } let person = new Object(); user(person); console.log(person.name);
解析
引用类型作为参数进入函数,即复制的是内存区域的指针,可以理解形参obj首先由argument[0]赋值,即obj = argument[0]。当person进到函数的过程第一步就是argument[0] = person,即person的指针给了argument[0]。当obj.name ='aaa';由于argument[0]指针是person,而obj = argument[0],所以obj也就是指向person。所以person.name='aaa'对象。obj = new Object();创建一个新对象并他的指针复制给变量obj,此时obj的指针不再指向person了。而person的指针是不会受到影响的this
var a1 = {}, b1 = '123', c1 = 123; a1[b1] = 'b'; a1[c1] = 'c'; console.log(a1[b1]); var a2 = {}, b2 = Symbol('123'), c2 = Symbol('123'); a2[b2] = 'b'; a2[c2] = 'c'; console.log(a2[b2]); var a3 = {}, b3 = {key:'123'}, c3 = {key:'456'}; a3[b3] = 'b'; a3[c3] = 'c'; console.log(a3[b3]);
知识点:
1.对象的键名只能是字符串和Symbol类型
2.其余类型的键名会被转化成字符串类型
3.对象转字符串默认会调用 toString 方法
4.symbol是ES6 中新添加的数据类型。Symbol 本质上是一种惟一标识符,可用做对象的惟一属性名,这样其余人就不会改写或覆盖你设置的属性值
解析:
1.在 a1 中,a1[b1] = 'b' ; a1[c1] = 'c' ; c1 的键名会被转换成字符串 '123' 覆盖掉 b1 ,因此结果为 'c'
2.在 a2 中,b2,c2 都是 Symbol 类型,不须要转换,任何一个 Symbol 类型的值都是不相等的,因此不会覆盖,结果为 'b'
3.在 a3 中 , b3,c3 都是 object 类型,做为键名会调用 toString 方法转换为字符串 [object Object],c3 覆盖 b3 的值,结果为 'c'
结果:
'c' , 'b' , 'c'prototype
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(()=>{ console.log('setTimeout'); },0) async1(); new Promise((resolve)=>{ console.log('promise1'); resolve(); }).then(()=>{ console.log('promise2'); }); console.log('script end');
知识点:
1.Promise 一旦被定义就会当即执行
2.Promise 优先于 setTimeout 宏任务,因此 setTimeout 回调会最后执行
3.Promise 的 resolve 和 reject 是异步执行的回调。因此 resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 以前调用
4.await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象
5.宏任务优先执行于微任务
常见宏任务:script、I/O 、setTimeout、setInterval
常见微任务:Promise.then catch finally、process.nextTick线程
答案
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout指针
console.log('1'); setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) process.nextTick(function() { console.log('6'); }) new Promise(function(resolve) { console.log('7'); resolve(); }).then(function() { console.log('8'); }) setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') }) })
解析
第一个宏观任务:
1.第一个宏观任务script 做为总体进入主线程 遇到console.log('1') 输出1
2.遇到setTimeout,宏观任务(如今第一个宏观任务script尚未执行完毕 会分配到宏观任务中 暂时还不会执行)
3.遇到下面的process.nextTick 分配到微观任务中
4.遇到Promise,new Promise直接执行,输出7。then被分发到微任务Event Queue中 5.此时的微观任务表中:process.nextTick,Promise.then 则执行结果为 6 8
第一个宏观任务 执行结果 : 1 7 6 8
第二个宏观任务:
1.第二个宏观任务是第一个setTimeout
2.跟script的执行顺序是同样的 碰到console.log('2') 执行2 process.nextTick会分配到微观任务 Promise会当即执行 而后.then分配到微观任务
输出结果:2 4 3 5
第三个宏观任务:
第三个宏观任务就是第二个setTimeout 和第二个宏观任务执行顺序同样
输出结果 9 11 10 12code
const num = { a:10, add(){ return this.a + 2; }, reduce:()=>this.a - 2 }; console.log(num.add()); console.log(num.reduce());
解析:
知识点函数体内的this
对象,就是 定义 时所在的对象,而不是使用时所在的对象。
add是普通函数,而 reduce 是箭头函数。对于箭头函数,this 指向是他定义时的位置的环境,于普通函数不一样。 这意味着当咱们调用 reduce 时,它不是指向 num 对象,而是指其定义时的环境(window)。没有值 a 属性,因此返回 undefined。undefined - 2 返回 NaN
输出:NaN对象
var fullname = 'a'; var obj = { fullname: 'b', prop : { fullname: 'c', getFullname: function(){ return this.fullname; } } }; console.log(obj.prop.getFullname()); var test = obj.prop.getFullname; console.log(test());
解析:
对第一个 obj.prop.getFullname() 而言,getFullname() 是做为 obj.prop 对象的一个方法调用的,所以此时的执行环境应该是这个对象。
obj.prop.getFullname 被分配给 test 变量时,此时的执行环境变成了全局对象(window),缘由是 test 是在全局做用域下定义的。所以,此时 this 指向的是全局做用域的 fullname 变量,即 a
function Foo(){ Foo.a = function(){ console.log(1); } this.a = function(){ console.log(2) } } Foo.prototype.a = function(){ console.log(3); } Foo.a = function(){ console.log(4); } Foo.a(); let obj = new Foo(); obj.a(); Foo.a();
解析:Foo.a() 这个是调用 Foo 函数的静态方法 a,虽然 Foo 中有优先级更高的属性方法 a,但 Foo 此时没有被调用,因此此时输出 Foo 的静态方法 a 的结果:4let obj = new Foo(); 使用了 new 方法调用了函数,返回了函数实例对象,此时 Foo 函数内部的属性方法初始化,原型链创建。 obj.a() ; 调用 obj 实例上的方法 a,该实例上目前有两个 a 方法:一个是内部属性方法,另外一个是原型上的方法。当这二者都存在时,首先查找 ownProperty ,若是没有才去原型链上找,因此调用实例上的 a 输出:2Foo.a() ; 根据第2步可知 Foo 函数内部的属性方法已初始化,覆盖了同名的静态方法,因此输出:1