js的一道函数,变量基础题。进来看看

function Foo(){
    bar=function(){console.log(1)};
    return this;
}

Foo.bar=function(){console.log(2)}
Foo.prototype.bar=function(){console.log(3)};
var bar = function(){console.log(4)}
function bar(){
    console.log(5);
}



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

这样浏览器编译后又有函数提升和变量提升了,最后会变成什么结果,为什么new bar会打印4,console.log(5)是不是被永久覆盖了?

阅读 2.1k
4 个回答

一点一点讲:
第一步,js解释器对js代码进行解析编译,这个时候会进行你知道的函数声明提升步骤。
这是源代码:

function Foo() {
    bar = function() { console.log(1) };
    return this;
}

function bar() {
    console.log(5);
}

Foo.bar = function() { console.log(2) }
Foo.prototype.bar = function() { console.log(3) };
var bar = function() { console.log(4) }

声明提升转化后代码:

function Foo(){
    bar=function(){console.log(1)};
    return this;
}

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

var bar = undefined;

function bar(){
    console.log(5);
}

bar = function(){console.log(4)}

看到了吧,bar函数被进行了覆盖,相当于以下代码:

function Foo(){
    bar=function(){console.log(1)};
    return this;
}

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

var bar = function(){console.log(4)}

第二步,接着往下执行

new bar();//4 这句没什么好解释的,上面就一个bar函数,使用new操作符执行,自然是 4
Foo.bar();//2 这句也简单,函数上直接赋值的静态方法,Foo.bar = function() { console.log(2) },自然是2;

第三步,接着往下

Foo().bar(); 
// 这行代码信息比较过,首先调用了 Foo函数,函数里面对bar进行了 重新赋值,然后返回了this,注意理解一下,这里的this是谁,明说了吧,因为Foo在全局直接调用的的,根据谁调用this指向谁原则,这是默认是window。
// 所以现在 bar进行了重新定义为: bar = function() { console.log(1) };
接着又执行了bar函数,根据上面重新定义的函数运行结果,自然是 1

第四步

bar();//再次调用bar函数,相信这里不用在解释了吧,和上面那步一样,自然是1

第五步,再往下

new Foo().bar();
// 首先 对Foo进行new操作符,实例化Foo类,这里不用关系全局bar再次赋值的问题,因为是new操作符,返回的就是 这个类的实例,所以返回值是 Foo的实例。
// 接着执行了Foo的实例上的 bar函数,那么 先从实例上查找bar函数,发现找不到(Foo上有一个静态的bar函数,但是不是实例的方法,只能通过构造函数调用),然后接着从原型链上查找,发现原型链Prototype上恰好有一个bar方法,找到后就直接调用,自然是  3

这里主要是函数声明提升,函数表达式不提升。提升后的代码为

var bar;
function Foo() {
    bar = function() { console.log(1) };
    return this;
}

function bar() {
    console.log(5);
}

Foo.bar = function() { console.log(2) }
Foo.prototype.bar = function() { console.log(3) };
bar = function() { console.log(4) }


new bar();//4
Foo.bar();//2  由于Foo中未声明bar bar找到全局变量并赋值
Foo().bar();// 1
bar();// 1
new Foo().bar()//3
function bar(){
    console.log(5);
}

会函数提升,等于在最上面
然后被 var bar = function () {} 覆盖掉

1.声明提升,所以var bar和后面的函数定义就是5都被提升了
2.提升之后继续执行,bar被赋值为4的函数体,所以5的被覆盖

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题