JavaScript 性能优化之作用域安全的构造函数
构造函数其实就是一个使用new操作符调用的函数。当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例,如下面的例子所示:
1 | function Person(name, age, job) { |
上面这个例子中,Person构造函数使用this对象给三个属性赋值: name、age和 job。当和new操作符连用时,则会创建一个新的 Person对象,同时会给它 分配这些属性。问题出在当没有使用new操作符来调用该构造函数的情况上。由于该this对象是在运行时绑定的,所以直接调用Person(),this会映射到全局对象window.上,导致错误对象属性的意外增加。例如:
1 | var person = Person("aqingya", 18, "吴志广"); |
原本针对Person实例的三个属性被加到window对象上,因为构造函数是作为普通函数调用的,忽略了new操作符。这个问题是由this 对象的晚绑定造成的,在这里this被解析成了window对象。
解决方法:就是创建一个作用域安全的构造函数。在进行更改之前,首先确认this对象的正确类型的实例,如果不是就会创建新的实例并返回。
1 | function Person(name, age, job) { |
Person构造函数添加了一个检查并确保this对象是Person实例的 if 语句,它表示要么使用new操作符,要么在现有的Person实例环境中调用构造函数。任何一种情况下,对象初始化都能正常进行。如果this并非Person的实例,那么会再次使用new操作符调用构造函数并返回结果。
但是这也会出现一个问题:实现这个模式后,你就锁定了可以调用构造函数的环境。如果你使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏。如下:
1 | function Polygon(sides) { |
在这段代码中,Polygon 构造函数是作用域安全的,然而Rectangle构造函数则不是。新创建一个Rectangle实例之后,这个实例应该通过Polygon. call ()来继承Polygon的sides属性。但是,由于Polygon构造函数是作用域安全的,this 对象并非Polygon的实例,所以会创建并返回一个新的Polygon对象。Rectangle 构造函数中的this对象并没有得到增长,同时Polygon. call ()返回的值也没有用到,所以Rectangle实例中就不会有sides属性。
解决方法:构造函数窃取结合使用原型链的方法可以解决该问题。
1 | function Polygon(sides) { |
愿你的坚持终有收获。
Use this card to join the candyhome and participate in a pleasant discussion together .
Welcome to aqing's candyhome,wish you a nice day .