构造函数的作用域还有安全这么一说。很多人估计都不知道,下面通过一个例子来说明,什么是作用域不安全的构造函数。
//大众化的造人函数
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var xiaoming = new Person("小明","20","boy"); //造了个小明 这样做是不会有问题的
var kangkang = Person("康康","21","boy"); //这样写就会出问题了 大问题
console.log(this.name); //康康
以上代码的输出在部分人看来或许是没错啊 构造函数中把name
的值赋给this
了。控制台输出的也是之前赋的值。但是,请注意这边的this
并不是 kangkang
这个新的对象 而是 window
对象 相当于把要给新对象的属性值 加到了全局对象上了。导致了新建的对象在取属性值时报错,而且在全局对象上新增了属性(方法)造成了污染。
以上说了那么多,就是想说像上面第二种方法实例化对象的时候,由于没有new
关键字,导致操作的this
并不是新的实例而是全局对象,从而可能引起页面的问题。如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)
以下是处理的办法
//还是那个造人函数
function Person(name,age,sex){
if (this instanceof Person){
this.name = name;
this.age = age;
this.sex = sex;
}else{
return new Person(name, age, job);
}
}
var xiaoming = new Person("小明","20","boy"); //造了个小明 这样做是不会有问题的
var kangkang = Person("康康","21","boy"); //这样写就会出问题了 大问题
console.log(this.name); //undefined
如此就能确保不管有没有 new 关键字都能正确的生成我们想要的对象实例。
当然以上修改后一定程度上解决了以上的问题。但是,若使用了构造函数窃取模式(个人理解:构造函数B中用call调用A构造函数 想使B中的this 带有A构造函数中的属性或方法)的继承且不使用原型链,那么就可能会破坏这个继承。
//还是那个造人函数
function Person(name,age,sex){
if (this instanceof Person){
this.name = name;
this.age = age;
this.sex = sex;
}else{
return new Person(name, age, job);
}
}
function Programmer(skill){
Person.call(this,"xiaoming","20","boy");
this.skill = skill;
}
var xiaoming = new Programmer("java"); //造了个会java的小明
console.log(xiaoming .name); //undefined
相信很多人都找到了问题的关键所在。在实例化时由于this
继承的并不是 Person 所以用 call
调用的时候 返回的对象是新的 Person对象(执行else里面的) this也是新的实例的 而不是属于Programmer构造函数中的this,新生成的Programmer实例并没有得到增长 call 调用后返回的值也没用到 所以得到的值会是undefined;
若使用原型链就可以解决上面的问题了。
......省略上面的两个构造函数
Programmer.prototype = new Person()// ******这里的代码是关键******
//以上代码会使一个Programmer实例同时也是Person的实例。this就能通过if判断
var xiaoming = new Programmer("java"); //造了个会java的小明
console.log(xiaoming .name); //xiaoming
作用域安全的构造函数在很多看来并没多少用处,但是为了避免造成一些难以追踪的问题,特别是在多人协同编写功能的情况下,还是推荐使用作用域安全的构造函数。
2017.03.02