引言
JavaScript不是按面向对象的思想设计的程序语言,所以它不具备像现有的面向对象的语言那样的功能,但是面向对象的思想是如此的深入人心,以至于JavaScript也削尖了脑袋“面向对象”。果真,通过一些特殊的处理,JavaScript也具有了基本的面向对象的功能。
function、new、prototype与constructor
看代码:
<script language="javascript">
function Person(name){
this.name=name;
this.showMe=function(){
alert(this.name);
}
};
var one=new Person('JavaScript');
one.showMe();
</script>
很多人见到了久违的new操作符,于是就叫Person为“类”,可是又没有关键字class的出现,觉得叫“类”有点勉强。于是退而求其次叫Person为类的构造函数。这些概念好像都没有错,之所以出现这样的情况,可能是因为大家都学习了传统的面向对象语言(c++,c#,java等),还有一种思维定势吧。为了让javascript也面向对象,要在javascript中找到与传统面向对象语言的影子。可是按照javascript的说法,function定义的这个Person就是一个Object(对象),而且还是一个很特殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别。这个区别就是function定义的对象有一个prototype属性,使用new生成的对象就没有这个prototype属性。
prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。有点头晕,看下图吧:
下面举例证明:
<script language="javascript">
function Person(name){
this.name=name;
this.showMe=function(){
alert(this.name);
}
};
var one = new Person('JavaScript');
//结果undefined,证明new出的对象无prototype属性
alert(one.prototype);
//结果object,证明function定义的对象有prototype属性
alert(typeof Person.prototype);
//结果true,证明function定义的对象prototype的constructor属性指向的对象就是function定义的对象
alert(Person.prototype.constructor == Person)
</script>
对象创建三部曲与__proto__属性
看代码:
<script language="javascript">
function Person(name){
this.name=name;
this.showMe=function(){
alert(this.name);
}
}
Person.prototype.say = function(){alert("i'm from prototype");}
var one = new Person('JavaScript');
one.showMe();
one.say();
</script>
上面可以看到,不论是showMe还是say方法,我们都可以调用到。要解释这个结果就要仔细研究一下new这个操作符了,实际上对象的创建可以分为三个步骤:
1. var one = {}; 这是创建对象one
2. one.__proto__ = Person.prototype; 这是将步骤1所创建的对象的“隐式链”设置成person的原型对象。“__proto__”被称为“隐式链”,不对外开放,但firefox浏览器对外开放,如果要实验请到firefox上实验。隐式链上的方法和属性是通过对象名直接访问的,所有对象都有“隐式链”,通过这一步,one对象就拥有了Person.prototype下的所有属性和方法,可以通过one直接访问。
3. Person.call(one); 这是将步骤1所创建的对象one作为person构造函数的this并调用person函数。这样one对象的this就拥有了person构造函数中的所有属性和方法。
其中第二步中出现了一个新名词就是“隐式链”(__proto__属性), __proto__指向了函数Person的prototype对象。在person的prototype对象中出现的任何属性或者函数都可以在one对象中直接使用,这个就是javascript中的原型继承了。又头晕了,上图吧!
这样one对象通过内置的原型对象 (__proto__属性)就可以直接访问Person的prototype对象中的任何属性与方法了。这也就解释了上面的代码中为什么one可以访问from函数了。因为prototype对象中有一个constructor属性,那么one也可以直接访问constructor属性。代码:
<script language="javascript">
function Person(name){
this.name=name;
this.showMe=function(){
alert(this.name);
}
}
Person.prototype.say = function(){alert("i'm from prototype");}
var one = new Person('JavaScript');
//结果true,证明上面所说的one.__proto__ = Person.prototype;是成立的
alert(one.constructor == Person.prototype.constructor);
alert(one.constructor);
alert(Person.prototype.constructor);
//结果“JavaScript”,证明上面所说的Person.call(one);是成立的
alert(one.name);
</script>
继承的实现
看代码:
<script language="javascript">
function person(name){
this.name=name;
this.showMe=function(){
alert(this.name);
}
}
person.prototype.say = function(){alert("i'm from prototype");}
function employee(){
}
employee.prototype = new person();
var bill = new employee();
bill.say();
//结果为true,原因是bill.__proto__=person.prototype
alert(bill.constructor == person.prototype.constructor);
alert(bill.constructor);
</script>
继承的实现很简单,只需要把子类的prototype设置为父类的一个对象即可。注意这里说的可是对象哦!(就是必须用new)那么通过prototype属性实现继承的原理是什么呢?还是先看图形说明,然后编写代码进行验证。
__proto__是隐式链,所有对象都有__proto__属性,__proto__所属对象可以直接访问其下的属性和方法,__proto__属性的指向决定了对象可以访问哪里方法和属性。
上图不知道大家是否能够理解,最重要的是中间两个的关系似乎不那么好理解,因为之前所说的new可以理解为:
1 employee.prototype.__proto__ = person.prototype
2 person.call(employee.prototype)
我们最重要的是改变了employee.prototype的__proto__属性,关键就在这里,__proto__指向person.prototype后employee.prototype做拥有的所有东西都会丢失,取而代之的是person.prototype,或者说用new person()对象替代了employee.prototype对象更好理解。反过来也可以说只要__proto__的指向改变了就说明使用了new
好了,下面就解释为什么这样就模拟了面向对象的类的继承。首先来看bill对象,它是由employee构造函数创建而来,但它却可以使用person的prototype下的方法,我们根据上图来一步步查找。首先,在bill对象中查找,然后到bill对象的__proto__所指向的对象employee.prototype对象(new person()对象)查找,再到employee.prototype对象的__proto__所指向的person的prototype对象中查找,结果say方法就在person的prototype对象中找到了,然后调用它。如果划分为步骤则如下:
1 bill = new employee(); //就先在employee()构造函数中查找
2 bill.__proto__ = employee.prototype = new person(); //在employee.prototype中查找,也就是在new person()对象中查找
2.1 employee.prototype.__proto__ = person.prototype; //在person.prototype中查找
2.2 person.prototype.__proto__ = object.prototype; //在object.prototype中查找
这样的一个过程不就是模拟了类的继承吗?也许是我自己的思路还不够清晰,所以我的描述也只能到此为止了。
标签:__,function,person,继承,javascript,笔记,Person,对象,prototype From: https://blog.51cto.com/u_15906220/5920743