Skip to content
本页目录

JavaScript 100 题😊

1、写出下列程序结果(词法)

javascript
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();

提示

在正式做之前,我们得清楚几个概念:

  • 函数提升要比var声明提升更加高,也就是说:如果在代码中同时定义了相同名称的一个函数和一个变量,是先会执行function getName() {},再执行var getName = function () {}的。
  • 关于new.以及()优先级的问题,不带参数的new调用优先级是要小于.的,而()的优先级是最大的

首先是初始化阶段:

  • function getName() {} function Foo() {}被提升到作用域最顶层(但是此时还没有调用Foo函数,所以它里面的内容不会被执行)
  • 随后,var getName也被提升到了作用域最顶层,发现有一个和它同名的getName,后来者覆盖了它,所以此时的getName变成了alert(4)

然后到了调用阶段:

    1. 首先调用的是Foo.getName(),由于Foo是一个构造函数,且之前定义了它的静态方法Foo.getName = alert(2),因此显示调用整个静态方法,弹出2
    1. 之后调用了window 下的getName(),在初始化阶段已经说了,这时候的getNamealert(4),所以弹出4
    1. 接着执行Foo().getName(),这里可以分为两步来看,第一步:调用Foo()方法,这时候可以执行里面的代码了,也就是getName = alert(1),但是在Foo()函数内没有getName,所以此时 JS 就向外查找,找到了 window 下的那个getName(也就是alert(4)),找到了之后把它改为了alert(1),记住这时候的 window 下的getName就变成了alert(1),不过还没有结束,然后返回了this,这时候我们知道this表示的是window(因为调用Foo()函数的是windwo);第二步:执行Foo().getName(),刚刚Foo()的返回值我们已经知道了,是window,所以相当于调用了window.getName(),而在第一步中已经将getName变成了alert(1),所以这时候会弹出1
    1. 然后是调用getName(),这时候我们已经知道getNamealert(1),所以会再次弹出1
    1. 执行new Foo.getName(),在开头我已经提到了,不带参数的new调用优先级是要小于.的,所以这里相当于是new (Foo.getName)(),并且这里我们不要管new的产生结果,因为题目没有要你打印出它的结果,我们只需要关心new后面的东西就了,所以也就是关心Foo.getName(),额,这又是调用Foo构造函数的静态方法,和第一个弹出的一样,弹出2
    1. 同理,因为()的优先级是最大的,所以执行new Foo().getName()相当于是执行了(new Foo()).getName(),也就是先产生了一个Foo的实例,我假设它是{},也就是执行{}.getName(),但是这个空对象它自己没有getName()方法呀,所以它就用原型链上的getName,也就是弹出3
    1. 最后一个其实和第六个差不多,转换为伪代码就是new (new Foo()).getName(),也是弹出了3

温馨提醒

答案在下面,可以自己先尝试想想看哦。

答案

2 4 1 1 2 3 3


2、写出下列程序结果(堆地址和栈地址)

javascript
function test(person) {
  person.age = 26;
  person = {
    name: 'hzj',
    age: 18
  };
  return person;
}
const p1 = {
  name: 'fyq',
  age: 19
};
const p2 = test(p1);
console.log(p1); // -> ?
console.log(p2); // -> ?

温馨提醒

答案在下面,可以自己先尝试想想看哦。

答案 解析
js
p1:{name:fyq, age: 26}
p2:{name:hzj, age: 18}

原因: 在函数传参的时候传递的是对象在堆中的内存地址值,test 函数中的实参 person 是 p1 对象的内存地址,通过调用 person.age = 26 确实改变了 p1 的值,但随后 person 变成了另一块内存空间的地址,并且在最后将这另外一份内存空间的地址返回,赋值给了 p2。

MIT Licensed