因为最近也是学习到pink老师的JS高级里面的构造函数、原型以及原型链,在这里分别阐述一下这三者以及这三者的关系 首先就是构造函数: JS首先作为一门OOP语言,在迎来es6时代的时候,也迎来了它的一个新成员:类 以下是创建的一个类,名字叫Star:
class Star {
constructor(uname ,age){
this.uname=uname;
this.age=age;
}
简单引入一点,其他不作过多介绍
然而在ES6之前,对象不是基于类创建的,而是用一种构建函数的特殊函数来定义对象和它们的特征
function Star(uname,age){
this.uname=uname;
this.age=age;
}
var ldh = new Star('刘德华',18);//这里记住,一定要用new,要不然这个构造函数将无法使用
说到构造函数了,那么接下来就是讲解构造函数里面静态成员以及实例成员了
首先是静态成员:在构造函数本身上添加的成员才称为静态成员,只能用构造函数本身来访问
以咱们刚刚创建的构造函数为例:
function Star(uname,age){
this.uname=uname;
this.age=age;
}
var ldh = new Star('刘德华',18);
Star.sex='男';
console.log(Star.sex);
在原先Star这个构造函数里面,没有sex这个成员,然后我们在构造函数本身上(非内部)以"构造函数.成员名='属性值';"的形式添加这个静态成员后,便在Star构造函数里面新添加了此静态成员,值得注意的是:静态成员只能通过构造函数来访问
接下来是咱们的实例成员:实例成员是在构造函数内部创建的对象成员,只能由实例化对象来访问:
function Star(uname,age){
this.uname=uname;
this.age=age;
this.sing=function(){
console.log('我会唱歌’);
}
var ldh = new Star('刘德华',18);
在此构造函数来说,实例成员便是uname age和sing,简单来说:实例成员便是函数内部通过this添加的成员,同样的:实例成员只能通过实例化的对象来访问
比如说咱们想要看看咱们实例化之后该对象的名字,则通过以下方式访问:
console.log(ldh.uname);
目前为止:构造函数看起来还挺好用的,但是有一个问题,就是如果咱们需要使用某个构造函数的某个方法的时候,则需要使用不同实例化对象或者构造函数来调用,这样包括构造函数里面的方法以及实例化对象都会浪费不少的内存,接下来就引用到我们原型的概念了:
原型:
JS规定,每一个构造函数都有一个prototype属性,指向另外一个对象,这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有,我们可以把哪些不变的方法,直接定义在prototype对象上,这有所有对象的实例就可以共享这个方法(削弱JS构造函数中浪费内存的问题) 以上述内容的构造函数代码为例:
编译后打开控制台就会看见这个prototype的东西,这个东西便是构造函数里面自带的原型对象
那么,我们定义了一个构造函数之后,有某个对象对其进行实例之后,是如何调用构造函数里面的方法的呢?
function Star(uname,age){
this.uname = uname;
this.age = age;
// this.sing=function(){
// console.log('我会唱歌');
// }
}
Star.prototype.sing=function(){
console.log('我会唱歌');
}
var ldh= new Star('刘德华',18);
var zxy= new Star('张学友',19);
//console.log(ldh.sing === zxy.sing);//比较的是地址
// console.dir(Star);
ldh.sing();
console.log(ldh);//对象身上系统自己添加一个_proto_指向我们构造函数的原型对象prototype
//2.一般情况下,公共属性定义到构造函数里面,公共方法我们放到原型对象身上
console.log(ldh._proto_ === Star.prototype);
//方法的查找规则:首先先看ldh 对象身上是否有sing方法,如果有就执行这个对象上面的sing
//如果没有sing这个方法,因为有_proto_的存在,就去构造函数原型对象prototype身上去查找sing这个方法
一般而言,作为编译者,我们会把共有属性和方法存放到原型对象prototype之中,当我们实例对象之后,这个实例的对象身上,系统就会自动添加一个_proto_,从而指向我们构造函数的原型对象prototype,因为有_proto_的存在,就回去构造函数原型对象prototype身上去查找该方法或者属性
那么进一步的就引申到了我们的查找机制: 在此之前,先浅谈一下我们的原型链
function Star(uname,age){
this.uname = uname;
this.age = age;
// this.sing=function(){
// console.log('我会唱歌');
// }
}
var ldh= new Star('刘德华',18);
还是以这段代码为例子,我们在创建Star构造函数之后,系统会给Star自动添加一个prototype属性,这个属性呢会使构造函数指向该构造函数的原型对象,同时原型对象中也会出现一个constructor使原型对象指回该构造函数 我们在进行对象实例的时候,对象实例中系统就会分配一个_proto_属性,使实例对象指向构造函数的原型对象 然而作为构造函数的原型对象,它自身也会被分配一个_proto_的属性,使其指向更深处的Object原型对象 Object原型对象中自然也会出现一个constructor使其指向Object构造函数,Object构造函数自然也会出现prototype使其指向Objecet原型对象
自然而然的,我们也可以体会到JS里面的查找机制:
①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
②如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
③如果还没有就查找原型对象的原型(Object的原型对象)
④以此类推一直找到Object位置(null)
⑤__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。