构造函数中中this重写函数方法

时间:2022-06-29 17:36:36

原文地址: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和构造函数的进一步理解吧。