Javascript高级技巧系列--作用域安全的构造函数

395 阅读2分钟

构造函数:构造函数其实就是一个使 用 new 操作符调用的函数。当使用 new 调用时,构造函数内用到的 this 对象会指向新创建的对象实例.

// 构造函数示例:
var Person = function(name,age){
    this.name = name
    this.age = age
    this.getInfo = function(){
        return this.name+':年龄 '+this.age
    }
}
var p1 = new Person('张三',18)
console.log(p1.getInfo()) // 张三:年龄 18

上述例子中,Person构造函数使用this对象给三个属性赋值:name、age和getInfo。当和new操作符连用时,则会创建一个新的 Person 对象,同时会给它分配这些属性。

但是,由于该 this对象是在运行时绑定的,如果没有使用 new 操作符直接调用 Person()this 会映射到全局对象 window上,导致错误对象属性的意外增加。

var p2 = Person('张三',18)
console.log(window.name,window.age) // '张三' 18

此时,由于 windowname 属性是用于识别链接目标frame 的,所以这里对该属性的偶然覆盖可能会导致该页面上出现其他错误。 这个问题的解决方法就是创建一个作用域安全的构造函数.

// 作用域安全的构造函数
var Person = function(name,age){
    if (this instanceof Person) {
        this.name = name
        this.age = age
        this.getInfo = function() {
            return this.name+':年龄 '+this.age
        }
    } else {
        return new Person(name, age)
    }
}

以上,稍微改造后,确保this对象是 Person 的实例,即:要么使用new操作符,要么在现有的Person实例环境中调用构造函数。任何一种情况下,对象初 始化都能正常进行,避免了在全局对象上意外设置属性。

不过使用作用域安全的构造函数,在下述情况下,会有问题。

var Person2 = function(gentle){
    Person.call(this,'李四',20)
}
var p2 = new Person2('male');
console.log(p2.name) // undefined

由于Person构造函数是作用域安全的,this 对象并非 Person2 的实例,所以导致,Person中的this,并不指向Person2的实例p2.Person2构造函数中的 this对象并没有得到增长.p2中,也就不会有Person中的属性,name,age,getInfo.

如果p2要继承Person的属性,可作下述更改

// 将Person2的prototype属性,指向Person的实例,这里又涉及到了对象的继承,下个系列跟进
var Person2 = function(height){
    Person.call(this,'李四',20)
    this.height = height
    this.showInfo = function(){
        console.log(this.height)
    }
}
Person2.prototype = new Person()
var p2 = new Person2(180);
console.log(p2)// {name: "李四", height: 180, getInfo: ƒ, showInfo: ƒ}