玩命加载中 . . .

备战大厂前端实习之代码输出结果篇


前端面试题系列文章:

输出结果

变量提升

题一

function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}
 
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

分析函数表达式和函数声明的提升层级:

getName() //oaoafly
var getName = function() {
	console.log('wscat')
}
getName() //wscat
function getName() {
	console.log('oaoafly')
}
getName() //wscat

这道题涉及到变量提升的机制。函数声明和函数表达式都会被提升,那么是函数声明覆盖函数表达式?还是函数表达式覆盖函数声明?很多人知道是函数表达式覆盖函数声明,但其实这里是有一个条件的:当 js 代码执行到函数表达式时,它才能覆盖函数声明,否则只会提升函数声明(没有函数表达式什么事了)。
现在再来看这道题,一开始会提升函数声明,上面的代码可以看成(由于未执行到函数表达式,因此不能提升):

function getName() {
	console.log('oaoafly')
}
getName() //oaoafly
var getName = function() {
	console.log('wscat')
}
getName() //wscat
getName() //wscat

所以第一个 getName() 输出 oaoafly 。当执行到函数表达式后,覆盖函数声明,于是变成:

var getName = function() {
	console.log('wscat')
}
getName() //oaoafly
getName() //wscat
getName() //wscat

因此后两个 getName() 都是输出 wscat

题二

下面继续看这道题,也是同样的道理:

var getName //变量被提升,此时为undefined

getName() //oaoafly 函数被提升 这里受函数声明的影响,虽然函数声明在最后可以被提升到最前面了
var getName = function() {
	console.log('wscat')
} //函数表达式此时才开始覆盖函数声明的定义
getName() //wscat
function getName() {
	console.log('oaoafly')
}
getName() //wscat 这里就执行了函数表达式的值

题三

难度升级:

function Foo() {
	this.getName = function() {
		console.log(3);
		return {
			getName: getName //这个就是第六问中涉及的构造函数的返回值问题
		}
	}; //这个就是第六问中涉及到的,JS构造函数公有方法和原型链方法的优先级
	getName = function() {
		console.log(1);
	};
	return this
}
Foo.getName = function() {
	console.log(2);
};
Foo.prototype.getName = function() {
	console.log(6);
};
var getName = function() {
	console.log(4);
};

function getName() {
	console.log(5);
} //答案:
Foo.getName(); //2
getName(); //4
console.log(Foo())
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName(); //3
//多了一问
new Foo().getName().getName(); //3 1
new new Foo().getName(); //3

变量提升

var x = 10;
if (true) {
  x = 20;
  console.log(x) // error
  let x;
}

变量赋值

let a = {a: 10};
let b = {b: 10};
let obj = {
  a: 10
};
obj[b] = 20;
console.log(obj[a]); // 20

这道题主要考察对JS数据类型的熟练度以及对ES6中属性名表达式的理解。在倒数第二行中 obj[b] = 20 的赋值操作后,obj 其实已经变成了 {a: 10, [object Object]: 20} ,这是因为如果属性名表达式是一个对象的话,那么默认情况下会自动将对象转为字符串 [object Object] ,最后一步获取 obj[a] 时,a 本身也是一个对象,所以会被转换为获取 obj['[object Object]'] 也就是说要查找 obj 中键为 [object Object] 的值,答案为上一步赋值的 20。

预编译/变量提升

题一

function test() {
console.log(b);
if (a) {
    var b = 100;
}
console.log(b);
c = 234;
console.log(c);
}
var a;
test();
a = 10;
console.log(c);

题二

var foo = 1;
function bar() {
    console.log(foo);  
    if (!foo) {
        var foo = 10;
    }
    console.log(foo); 
}

bar();

答案

undefined
10

题三

var a = 1;
function b() {
    console.log(a);  
    a = 10;
    return;
    function a() { }
}
b();
console.log(a); 

答案

function a() { }
1

题四

console.log(foo);
var foo = "A";
console.log(foo)
var foo = function () {
  console.log("B");
}
console.log(foo);
foo();
function foo(){
  console.log("C");
}
console.log(foo)
foo(); 

答案

ƒ foo(){
    console.log("C");
}
A
ƒ () {
    console.log("B");
}
B
ƒ () {
    console.log("B");
}
B

题五

var foo = 1;


function bar(a) {
  var a1 = a;
  var a = foo;
  function a() {
    console.log(a);
  }
  a1();
}

bar(3);

答案

1

总结

预编译的题目多数情况下就可以采用以下原则:

  • 函数声明,整体提升
  • 变量声明,声明提升

Promise

console.log('script start')
let promise1 = new Promise(function (resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function () {
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')

答案

script start
promise1
promise1 end
script end
promise2
settimeout

async/await

async function async1(){
   console.log('async1 start');
    await async2();
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}

console.log('script start');
async1();
console.log('script end')

答案

script start
async1 start
async2
script end
async1 end

事件循环

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2() {
    console.log('async2')
}

console.log('script start')

setTimeout(function () {
    console.log('setTimeout0')
}, 0)

setTimeout(function () {
    console.log('setTimeout2')
}, 300)

setImmediate(() => console.log('setImmediate'));

process.nextTick(() => console.log('nextTick1'));

async1();

process.nextTick(() => console.log('nextTick2'));

new Promise(function (resolve) {
    console.log('promise1')
    resolve();
    console.log('promise2')
}).then(function () {
    console.log('promise3')
})

console.log('script end')
  1. 先找到同步任务,输出 script start
  2. 遇到第一个 setTimeout ,将里面的回调函数放到 timer 队列中
  3. 遇到第二个 setTimeout ,传入的延迟时间为 300 ms,在定时器过程中只有在时间到达时才能将里面的回调函数放到 timer 队列中
  4. 遇到第一个 setImmediate ,它会在下一个循环迭代中触发,即把回调函数放到 check 队列中
  5. 遇到第一个 process.nextTick ,将其里面的回调函数放到本轮同步任务执行完毕后执行
  6. 执行 async1() ,输出 async1 start
  7. 执行 async2() ,输出 async2
  8. 遇到第二个,将其里面的回调函数放到本轮同步任务执行完毕后执行
  9. 遇到 new Promise ,执行里面的立即执行函数,输出 promise1promise2
  10. then 里面的回调函数进入微任务队列
  11. 遇到同步任务,输出 script end
  12. 执行下一轮回到函数,先依次输出 nextTick 的函数,分别是 nextTick1nextTick2
  13. 然后执行微任务队列,依次输出 async1 endpromise3
  14. 执行 timer 队列,依次输出 setTimeout0
  15. 接着执行 check 队列,依次输出 setImmediate
  16. 300ms 后,timer 队列存在任务,执行输出 setTimeout2

答案:

script start
async1 start
async2
promise1
promise2
script end
nextTick1
nextTick2
async1 end
promise3
setTimeout0
setImmediate
setTimeout2

函数柯里化

var MAP =  {
  onclick: function () {

  },
  curry: function (val) {
    return function (z) {
      return val++ + z
    }
  }
}

var getInfo = function (val) {
  return MAP[val]
}
var fn = getInfo('curry')

var a = fn(100)

console.log(a(200)) // 300
console.log(a(300)) // 401
console.log(fn(100)(200)) // 300
console.log(getInfo('curry')(100)(300)) // 400

深浅拷贝

var obj = {
  name: 'baidu', 
  arr: ['a', 'b', 'c']
}

var obj2 = obj
var arr = obj.arr

obj2.arr = ['a', 'b', 'c', 'd']
obj2.name = 'inke'

console.log(arr) // ['a', 'b', 'c']
console.log(obj.name) // 'inke'
console.log(obj === obj2) // true
console.log(obj.arr === obj2.arr) // true
console.log(obj.arr === arr)  //false

文章作者: hcyety
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hcyety !
评论
  目录