美团2020校招前端方向笔试题(链接)
问答题
1>
1、考察js堆与栈:栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null以及对象变量的指针,堆主要存储object
所以字符串变量i,s以及对象指针a都存在栈中,new出来的对象开辟内存存在堆上,对应地址是指针a存的内容
2、考察参数传递按值传递:a是A类的实例,所以a.i=’op’,a.func(a.i)这句执行函数,把a.i作为参数传递,该函数会复制一个变量,两个变量完全独立,所以在函数体里只是把复制的那个变量(一个新的局部变量)改变为’op9’,在函数体外的a.i并没有被改变
另外补充说明ECMAScript中所有函数的参数都是按值传递的——《高程3》,其实对于参数是对象的情况,实际上也是按值传递,把传参的指针复制出一个完全独立的变量,只是存的内容和传参对象地址一摸一样https://www.cnblogs.com/chenwenhao/p/7009606.html
2>
var name = 'global';
var obj = {
name: 'local',
foo: function(){
console.log(this)
this.name = 'foo';
}.bind(window)
};
console.log(obj.foo());// 此时调用的this是window
// 由于new绑定的优先级大于bind绑定,所以函数内部this还是obj {}
var bar = new obj.foo();
console.log(bar);//{name:'foo'}
console.log(window.name);//global
// 定时器任务,在最后放入任务队列,window对象没有被改变,所以输出 'global'
setTimeout(function() {
console.log(window.name);
}, 0);
// 此时bar.name =foo,因为被赋值了
console.log(bar.name);
// 此时执行顺序是var bar3,bar2=bar,bar3=bar2, 所以bar3/bar2/bar都是指向同一个对象
var bar3 = bar2 = bar;
bar2.name = 'foo2';
// 所以bar2修改属性,bar3的也改变了,此时输出为'foo2'
console.log(bar3.name);
‘foo’ //bind返回一个函数,该函数体中的this绑定到window上,然后new对该函数进行构造调用,返回一个新对象,函数体中的this指向该对象。bind是硬绑定,new绑定的优先级高于硬绑定。所以this还是绑定在bar这个新对象上。this.name=’foo’就是bar.name=’foo’
‘foo2’ //复杂类型值地复制是引用复制,bar3、bar2和bar指向的都是同一个对象,所以bar2.name=’foo2’对对象的熟悉进行修改时,bar3和bar的数据同样受影响
‘global’ //setTimeout设置一个定时器,定时器到时后调用回调函数,但定时器到时后只能将回调的执行放到事件队列的末尾,不能插队,所以console.log(window.name)这条输出语句是最后执行的
3>
// 解析1:
// 定时器任务属于宏任务,并且需要先在任务队列等待,等到同步任务执行完,执行栈清空,才会在任务队列中按顺序选任务进去
setTimeout(() => console.log('a'));//4. 打印a
//Promise 属于异步微任务,在本轮同步任务结束之前执行
Promise.resolve().then(
// 1. 打印 b
() => console.log('b') // 单引号要改为',然后去掉;号
).then(
// 箭头函数的resolve传递的参数作为下一个then的参数
() => Promise.resolve('c').then(
// 执行箭头函数
(data) => {
// 把定时器任务也放入任务队列中等待,在第一个定时器之后
setTimeout(() => console.log('d')); //5. 打印d
// 2.打印 f
console.log('f');
// 此时返回的 数据作为下一个then的参数
return data;
}
)
).then(data => console.log(data)); // 3.打印 c
// `打印bfcad`
// 解析2:
// setTimeout是异步任务中的宏任务
setTimeout(() => console.log('a'));
// Promise是异步任务中的微任务。比setTimeout先执行,
链式执行法,遇到setTimeout先挂起,往下执行
Promise.resolve().then(
() => console.log('b') // 输出 'b'
).then(
//该函数返回值是 'c'
() => Promise.resolve('c').then(
(data) => {
setTimeout(() => console.log('d')); //挂起,放到宏任务队列之后
console.log('f'); //执行,输出'f'
return data;
}
)
).then(data => console.log(data) ); // 接收到的就是输出 'c'
// 执行宏任务
setTimeout(() => console.log('a')); //输出 'a'
// 后续添加的宏任务
setTimeout(() => console.log('d')); //输出 'd'
4>
ES6与 ES5对比
var Person = (function () {
function Person (name){
this._name = name;
}
Person.prototype.greet = function() {
console.log("Hi, my name is " + this._name);
}
Person.prototype.greetDelay = function(time) {
var _this = this;
setTimeout(function () {
console.log("Hi, my name is " + _this.name);
}, time);
}
})();
**setTimeout() **调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象
解决方法:
1.使用局部变量:
var _this=this; setTimeout(function() { console.log("Hi, my name is "+_this.name); }, time);2.使用箭头函数:
setTimeout(() => { console.log("Hi, my name is "+_this.name); }, time);3.bind函数:
bind()方法是在Function.prototype上的一个方法,当被绑定函数执行时,bind方***创建一个新函数,并将第一个参数作为新函数运行时的this






