笔记 06 JS 函数 – 构造函数

原文地址

函数

函数是JavaScript中的一等对象
=> 可以把函数像其它值一样传递。

构造函数

  • 通过 new 关键字方式调用的函数都被认为是构造函数。

  • 在构造函数内部 – 也就是被调用的函数内 – this 指向新创建的对象 Object。

  • 新创建的对象的 prototype 被指向到构造函数的 prototype。

  • 如果被调用的函数没有显式的 return 表达式,
    则隐式的会返回 this 对象 – 也就是新创建的对象。

function Foo() {
    this.bla = 1;
}

Foo.prototype.test = function() {
    console.log(this.bla);
};

var test = new Foo();

显式的 return 表达式将会影响返回结果,但仅限于返回的是一个对象。

/**
 * new Bar() 返回的是新创建的对象,而不是数字的字面值 2。 
 * 因此 new Bar().constructor === Bar
 */
function Bar() {
    return 2;
}
new Bar(); // 返回新创建的对象

function Bar() {
    return new Number(2);
}
new Bar().constructor === Number

/**
 * new Test()是函数返回的对象,而不是通过new关键字新创建的对象
 */
function Test() {
    this.value = 2;

    return {
        foo: 1
    };
}
new Test(); // 返回的对象
(new Test()).value === undefined
(new Test()).foo === 1

/**
 * 如果 new 被遗漏了,则函数不会返回新创建的对象
 */
function Foo() {
    this.bla = 1; // 获取设置全局参数
}
Foo(); // undefined

工厂模式

/**
 * 两种对 Bar 函数的调用返回的值完全相同,
 * 一个新创建的拥有 method 属性的对象被返回,
 * 其实这里创建了一个闭包
 */
function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

// new Bar() 并不会改变返回对象的原型
// 返回对象的原型不会指向 Bar.prototype
// 因为构造函数的原型会被指向到刚刚创建的新对象,
// 而这里的 Bar 没有把这个新对象返回
// 返回了一个包含 method 属性的自定义对象
new Bar();
Bar();

var bar1 = new Bar();
typeof(bar1.method); // "function"
typeof(bar1.foo); // "undefined"

var bar2 = Bar();
typeof(bar2.method); // "function"
typeof(bar2.foo); // "undefined"
/**
 * 比起 new 的调用方式不容易出错,
 * 并且可以充分利用私有变量带来的便利
 *
 * 缺点
 *  1 会占用更多的内存,因为新创建的对象不能共享原型上的方法
 *  2 为了实现继承,工厂方法需要从另外一个对象拷贝所有属性,
 *    或者把一个对象作为新创建对象的原型。
 *  3 放弃原型链仅仅是因为防止遗漏 new 带来的问题,
 *    这似乎和语言本身的思想相违背
 */
function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}

虽然遗漏 new 关键字可能会导致问题,
但这并不是放弃使用原型链的借口。
最终使用哪种方式取决于应用程序的需求
选择一种代码书写风格
并坚持下去才是最重要的。