一个小小的经验分享
需求:给一个构造器(即构造函数)传入一个对象,通过构造器实例得到的对象访问传入对象的属性;
//创建一个接受properties对象的对象
function User(properties){//遍历对象属性
for(var i in properties){
//为属性创建获取器
this['get' + i]=function(){
var p = i;
return properties[p];
}
//为属性创建设置器
this['set' + i] = function(val){
var p = i;
properties[p] = val;
}
}
}
var students = new User({age:'22',sex:'man',name:'Mr.smith'});
students.getage();//Mr.smith 我查,怎么回事,居然不是我想要的22,百思不得其姐
// 认真分析后发现,原来是循环出现了问题,实例化的时候回执行构造函数,所以实例的时候情况是这样的
this.['get' + 'age'] = function(){return properties[i]};//给实例得到的对象添加了一个getage属性,但是并没有执行属性的方法
this.['get' + 'sex'] = function(){return properties[i]};
this.['get' + 'name'] = function(){return properties[i]};
students.getage();//执行这个的时候执行对应的方法return properties[i],但是这个时候循环已经结束了,所以i的值永远等于最后一个属性值,所以返回最后一个属性对应的值
//头脑风暴后,我想到了用一个局部变量来存放每个i的值,改进代码如下:
function User(properties){
//遍历对象属性
for(var i in properties){
(function(){//每次循环都执行一个匿名函数,在匿名函数中保存变量i
var p = i; //把i当前的值赋给p,1.由于外部可以通过['get' + i]方法访问p,所以在匿名函数执行完后不会被释放,2.由于每次循环定义一个匿名函数,也就是说在多个函数定义p变量,所以p变量的值不会相互影响
//为属性创建获取器
this['get' + i]=function(){
return properties[p];
}
//为属性创建设置器
this['set' + i] = function(val){
properties[p] = val;
}
console.log(p);
})();
}
}
// 心里暗暗的佩服了一下自己,太牛逼了,于是开始测试代码
var students = new User({age:'22',sex:'man',name:'Mr.smith'});
students.getage();//什么?getage()is not function,你大爷的再说多一边,再测试了几百遍,还是一样,到底是什么原因呢?
// 转了几百遍,看到this然后想起有个叫上下文的东西,然后仔细分析,i的上下文是对象User函数,而匿名函数里面的this的上下文是window对象,想到这里,秒懂,把
// getage这些属性都加到隔壁老王window对象家里去了,当然在实例students上找不到对应属性啦,于是我去window家里找找
window.getage();//22,我哩个去,终于找到了,但是我们是想搬到我们家去,这个咋整呢?问题所在就是this指向错误了,咱给个正确的this指向不就完了吗,代码如下:
function User(properties){
//遍历对象属性
for(var i in properties){
(function(that){//每次循环都执行一个匿名函数,在匿名函数中保存变量i
var p = i; //把i当前的值赋给p,1.由于外部可以通过['get' + i]方法访问p,所以在匿名函数执行完后不会被释放,2.由于每次循环定义一个匿名函数,也就是说在多个函数定义p变量,所以p变量的值不会相互影响
//为属性创建获取器
that['get' + i]=function(){
return properties[p];
}
//为属性创建设置器
that['set' + i] = function(val){
properties[p] = val;
}
console.log(p);
})(this);//把this当作参数传递给匿名函数,此时的this指向User函数的实例对象
}
}
var students = new User({age:'22',sex:'man',name:'Mr.smith'});
students.getage();//22
students.getsex();//man
// 到此分享完毕,总结:写js代码最主要的是要充分认识作用域以及上下文,当然还有细心,不然一不小心就被一个低级错误放倒了