javascript-原型链-变量提升-作用域

44 阅读1分钟

看代码输出

// a
function Foo () {
 getName = function () {
   console.log(1);
 }
 return this;
}
// b
Foo.getName = function () {
 console.log(2);
}
// c
Foo.prototype.getName = function () {
 console.log(3);
}
// d
var getName = function () {
 console.log(4);
}
// e
function getName () {
 console.log(5);
}

Foo.getName();           // 2
getName();               // 4
Foo().getName();         // 1
getName();               // 1 
new Foo.getName();       // 2
new Foo().getName();     // 3
new new Foo().getName(); // 3
  • 函数、变量声明会被提升,上述代码相当于:
// a
function Foo() {
  getName = function () {
    console.log(1);
  };
  return this;
}

function getName() {
  console.log(5);
}
var getName;
Foo.getName = function () {
  console.log(2);
};

Foo.prototype.getName = function () {
  console.log(3);
};

getName = function () {
  console.log(4);
};

Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3

    1. Foo.getName(); //2 直接获取函数的属性getName 输出2
    1. getName(); // 4 底部表达式 getName = function(){}输出了4
    1. Foo().getName(); // 1 调用了Foo()函数返回了一个返回值this,指向window,该函数内部getName变量不适用var、let声明,暴露成了全局对象,所以window.getName()输出1
    1. getName(); // 1 由于第3步,暴露了一个全局对象getName();,所以此处执行Foo()里的getName()输出1
    1. new Foo.getName(); // 2 执行执行Foo的上的getName属性,输出2
    1. new Foo().getName(); // 3 new了一个Foo构造函数的实例,并且执行getName,由于实例上没有,就去找原型链上继承来的Foo.prototype.getName,因此输出3
    1. new new Foo().getName(); // 3 new了两次,但是 new Foo().getName()并没有返回值,因此第二次new没有输出,还是找原型链上继承来的Foo.prototype.getName,因此输出3

其他

属性上声明的变量会放在Person.prototype.constructor对象上(无需继承),原型对象上声明的变量,直接暴露在与constructor同级上,如下:

image.png