原文地址:http://www.zhangyunling.com/?p=293
这篇文章,说起来也没有什么要表达的东西,只是想要说明一点,就算是我们很熟知的知识点,如果你平时不使用,那么关于这个知识点,你也只能算是懂而已,并不代表你会,尤其是,当你在使用时,所以,多实践,才是学习掌握一门技术的不二之选。
概述
构造函数有一个知识点,如果你对构造函数有了解,那么就必定会知道这个知识点,那就是,实例中定义的属性,会覆盖原型链的属性。
开始
首先看下面这个例子,相信只要你对构造函数的实例化有一些了解,那么你就应该对下面这个实例,有一个很明确的认识:
<span style="font-size:14px;">function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
};
var per = new Person("zhang");
console.log(per.getName()); //?
per.getName = function(){
return "ling";
};
console.log(per.getName()); //?
delete per.getName;
console.log(per.getName()); //?</span>
没有什么问题,这就是正常的表现。
但是,游戏饿时候,我希望原型链中的函数,只执行一次,而不是像上面那么,显示的去定义一个同名的属性或者方法,把原型链中的覆盖掉。
而且,有一个问题就是,难道在每次实例化时,还得多加上N
多代码,把不想要的原型链上的方法,都给覆盖掉,想想就有些扯淡,这个时候,就要想想了,原型链方法中,我们习惯使用的this
关键字,是指向哪里的?
在构造函数的实例化时,this
关键字,总是指向实例化时新生成的那个对象。
比如前面代码,在实例化Person
时,在原型链方法中的this
就是作为返回值赋值给了per
变量,所以,per === this
;
其实,这和我之前关于this
的介绍也是相同的理解,想想原型链中的this
是在什么时候被调用呢,只有在该方法被调用的时候,才会把this
的指向给赋值。
所以,对上面的代码,进行一点点更改:
<span style="font-size:14px;">function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
if(this === window){
console.log("this === window");
}else if(this === per){
console.log("this === per");
}else {
console.log(this);
}
return this.name;
};
var per = new Person("zhang");
per.getName(); //?
var getName = per.getName;
getName(); //?</span>
关于上面为什么会有这些,不了解或者感到迷惑的,请参考:函数中this的指向-简单认识,关于闭包的一些-胡思乱想。
OK,刚才算是一个小的插曲,现在继续,既然this
是指向实例化后的对象的,那么如果我在调用到该函数一次之后,重写该方法,是不是就可以实现了一些原型链中的方法,只调用一次的问题?
所以,继续更改原来的代码:
<span style="font-size:14px;">function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
this.getName = null;
return this.name;
};
var per = new Person("zhang");
console.log(per.getName()); //?
//下面的代码,就是确认下,执行一次getName之后,是否还有getName的值
if(typeof per.getName == "function"){
console.log("if 1");
console.log(per.getName());//?
}else{
console.log("else 1");
console.log(per.getName);
}</span>
上述代码,也就证明了前面说的方法是可行的,我们可以在原型链中的方法内部,直接限制该方法,在是实例化之后,只运行一次的问题。
那么问题就来了,如果我在原型链中的方法内部,把本方法重写,会不会影响下次实例化时,调用该方法呢?那么你就需要了解到一个问题了,原型链中的this
的指向问题?关于这一点,本文前面有之处,如果您到这里还有这个疑问,请向前翻看本文。
并且,为了能更好的理解这个问题,那么下面进行一些测试:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
this.getName = null;
return this.name;
};
var per = new Person("zhang"),
per2 = new Person("ling");
console.log(per.getName()); //?
console.log(per2.getName()); //?
if(typeof per.getName == "function"){
console.log("if 1");
console.log(per.getName());//?
}else{
console.log("else 1");
console.log(per.getName);
}
delete per.getName;
if(typeof per.getName == "function"){
console.log("if 2");
console.log(per.getName());//?
}else{
console.log("else 2");
console.log(per.getName);
}
这证明了两个问题:
1:原型链中,使用this.getName
重写getName
的方法,并不会影响到其他实例化时,对getName
的调用。
2:在原型链中的方法中,使用this.getName=null
重新赋值,只是改变了实例化之后的实例的getName
方法,而对于构造函数Person
的原型链中的getName
的方法,是没有影响的,只是把原型链中的getName
的方法给覆盖了而已。所以,使用delete
方法,删除实例中的getName
之后,依然可以访问原型链中的getName
方法。
因为通过delete
方法删除实例中的同名方法,还是可以继续访问原型链中的属性和方法的,所以,该方法只能算是取巧,也算是对this和构造函数的进一步理解吧。