首页 > 代码库 > JavaScript基础有关构造函数、new关键字和this关键字(009)

JavaScript基础有关构造函数、new关键字和this关键字(009)

1. 总是记得用new关键字来执行构造函数。
前面提到,可以用构造函数创建JavaScript的对象,这个构造函数在使用的时候需要使用new关键字,但如果忘记写入new关键字,会怎么样?事实上这个函数还是会被执行的,没有语法错误,但有逻辑错误。因此如果没有用new关键字,函数里的this指针将不会被存放新的对象的引用,实际存入是的全局对象。如果你在网页里执行代码,这个this就是window。比如,这个时候,构造函数里的this.member指向的就是window.member。如果在全局对象window里没有定义这个member属性,这个属性将会被隐式的声明!这有可能会捅出个大篓子:

// constructorfunction Waffle() {    this.tastes = "yummy";}// a new objectvar good_morning = new Waffle();console.log(typeof good_morning); // "object"console.log(good_morning.tastes); // "yummy"// antipattern:// forgotten `new`var good_morning = Waffle();console.log(typeof good_morning); // "undefined"console.log(window.tastes); // "yummy"

 这就是为什么我们应该让构造函数的首字母大写,让人一看就知道它是个构造函数。因为它如果不用new关键字执行,是会出问题的。

2. 在构造函数中别用this,用that
既然在构造函数中用了this会有隐患,那么我们可以别用this,改用that。当然,that不是个关键字。所以构造函数会变成这个样子:

function Waffle() {    var that = {};    that.tastes = "yummy";    return that;}

 这看起来有点奇怪,不过的确能提高代码的安全性。如果需要构造的对象足够简单,也可以直接return一个Literal的对象:

function Waffle() {    return {        tastes: "yummy"    };}

 使用这种方法写出的构造函数,总是能返回一个我们需要的对象,不管它是如果被调用的:

var first = new Waffle(),    second = Waffle();console.log(first.tastes); // "yummy"console.log(second.tastes); // "yummy"

 这种模式的最大问题是,新建的对象与Waffle对象的原型之间的关系丢失了,而通过Waffle的原型加入通用方法将不能奏效。如果要保证新对象和Waffle原型之间的关系,可以使用instanceof做个判断,然后再决定如何创建对象:

function Waffle() {    if (!(this instanceof Waffle)) {        return new Waffle();    }    this.tastes = "yummy";}Waffle.prototype.wantAnother = true;// testing invocationsvar first = new Waffle(),    second = Waffle();console.log(first.tastes); // "yummy"console.log(second.tastes); // "yummy"console.log(first.wantAnother); // trueconsole.log(second.wantAnother); // true

 还有一种通用的方法可以检查调用构造函数的方式 ,就是通过arguments.callee来判断:

if (!(this instanceof arguments.callee)) {    return new arguments.callee();}

 这种方法的原理是,所有的函数对象中,都有一个arguments的成员对象,arguments的其中一个属性叫callee,它指向这个函数的调用者。但这种方法并不适用过严格的JavaScript标准,所以不建议使用。

 

JavaScript基础有关构造函数、new关键字和this关键字(009)