记一道经典前端题

题目以下:node

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

// 输出结果为
// 2
// 4
// 1
// 1
// 2
// 3
// 3
复制代码

下面对输出值进行分析:函数

  1. Foo.getName() 输出为 2, 访问的是函数 Foo 上的静态属性,输出为 2。优化

    如今,尝试在函数内定义 getName 函数和在 Foo 原型上绑定 getName 函数, 都没法成功执行 Foo.getName(), 而以字面量建立对象的方式建立对象后,则能正常的执行 getName() 函数。ui

尝试

经过建立对象运行 getName() 定义在函数内部没法正常执行,即便它是全局变量。this

尝试

结论: 因为函数自己是对象,经过函数绑定属性和方法属于静态方法 ,能够直接调用。绑定在原型上的属性和方法要建立对象后才能调用,在构造函数对象内部定义的方法没法经过对象调用。spa

  1. getName(); 结果输出为 4,而不是输出 5。这是由于JS 存在变量声明提高(全部声明的变量或声明的函数都会被提高到当前函数的顶部)。prototype

    故代码执行顺序为:code

    var getName;
    function getName() { alert(5); }
    // ... 省略代码
    getName = function () { alert(4) }
    复制代码

    最终执行 getName 输出为 4cdn

    延伸题目:对象

    console.log( Foo )
    function Foo() {
        console.log(1);
    }
    var Foo = 1
    复制代码

    Foo 的输出结果为?

  2. Foo().getName(); 输出值为1, 先执行 Foo() 函数,定义全局变量 getName, 以后调用全局对象的 getName() 方法, 返回 1。

    注意, Foo() 函数返回的 this 指向的是全局对象 window,因此调用的是全局对象 getName()。 函数里的 getName 绑定的是全局对象,经过 Foo 调用会报错。

    Node 下执行这条语句会报错,由于 node 没有全局对象 window, 因此没法调用 getName

  3. getName() 调用全局函数, 由于执行 Foo(), 更新了 getName 的值,因此返回 1。

  4. new Foo.getName() 考察了运算符的优先级。 . 的优先级高于 new, 至关于执行 new (Foo.getName)(), 至关于执行 getName 的构造函数,返回 2

  5. new Foo().getName() 执行方式为 (new Foo()).getName() 先生成 Foo 对象, 再执行 getName() 函数。 在 new Foo() 返回的是新建立的空对象,因为对象这时还没绑定属性 getName, 因此这时调用的是原型上的 getName, 结果返回3

    注意: 构造函数 return this,在执行 new 的时候,返回的是新建立的对象。

    延伸题目:

    function A() {
        this.a = 2;
        function B() {
            this.a = 1;
        }
        return B();
    }
    console.log(new A());
    复制代码

    a的值是? 若是 return new B(); a的值是?

  6. new new Foo().getName() 能够改写为 new ((new Foo()).getName)() 先初始化实例,而后将原型对象上的 getName() 做为构造函数执行,结果返回 3

最终代码能够优化为

var getName;
function getName() { alert(5); }
function Foo() {
    getName = function() { alert(1); }
    return this
}
Foo.getName = function() { alert(2); }
Foo.prototype.getName = function() { alert(3); }
getName = function () { alert(4); }

Foo.getName(); // 2
getName(); // 4
Foo();
getName(); // 1
getName(); // 1
Foo.getName(); // 2
(new Foo()).getName(); // 3
(new Foo()).getName(); // 3
复制代码
相关文章
相关标签/搜索