欢迎光临杨雨的个人博客站!

杨雨个人网站-杨雨个人博客-杨照佳

杨雨个人博客网站

关注互联网和搜索引擎的个人博客网站

首页 > WEB开发 > JavaScript >

深入浅出JavaScript之原型链担任

发布时间:2016-11-23  编辑:杨雨个人博客网站   点击:   

Javascript说话的担任机制,它没有"子类"和"父类"的观念,也没有"类"(class)和"实例"(instance)的区分,端赖一种很怪异的"原型链"(prototype chain)模式,来实现担任。

这部门常识也是JavaScript里的焦点重点之一,同时也是一个难点。我把进修条记清算了一下,利便各人进修,同时本身也加深印象。这部门代码的细节许多,必要重复推敲。那我们就开始吧。

深入浅出JavaScript之原型链接受

小试技艺

原型链例子(要点写在注释里,可以把代码复制到赏识器里测试,下同)

function foo(){}              //通过function foo(){}界说一个函数工具
foo.prototype.z = 3;          //函数默认带个prototype工具属性   (typeof foo.prototype;//"object")

var obj =new foo();           //我们通过new foo()结构器的方法结构了一个新的工具
obj.y = 2;                    //通过赋值添加两个属性给obj
obj.x = 1;                    //通过这种方法结构工具,工具的原型会指向结构函数的prototype属性,也就是foo.prototype
                              
obj.x; // 1                 //当会见obj.x时,发明obj上有x属性,以是返回1
obj.y; // 2                 //当会见obj.y时,发明obj上有y属性,以是返回2
obj.z; // 3                 //当会见obj.z时,发明obj上没有z属性,那怎么办呢?它不会遏制查找,它会查找它的原型,也就是foo.prototype,这时找到z了,以是返回3

//我们用字面量建设的工具可能函数的默认prototype工具,现实上它也是有原型的,它的原型指向Object.prototype,然后Object.prototype也是有原型的,它的原型指向null。
                                   //那这里的Object.prototype有什么浸染呢?
typeof obj.toString; // ‘function'  

//我们发明typeof obj.toString是一个函数,可是不管在工具上照旧工具的原型上都没有toString要领,由于在它原型链的结尾null之前都有个Object.prototype要领,
//而toString正是Object.prototype上面的要领。这也表明白为什么JS根基上全部工具都有toString要领
'z' in obj; // true               //obj.z是从foo.prototype担任而来的,以是'z' in obj返回了true
obj.hasOwnProperty('z'); // false   //可是obj.hasOwnProperty('z')返回了false,暗示z不是obj直接工具上的,而是工具的原型链上面的属性。(hsaOwnProperty也是Object.prototype上的要领)

深入浅出JavaScript之原型链接受

适才我们会见x,y和z,别离通过原型链去查找,我们可以知道:当我们会见工具的某属性时,而该工具上没有响应属性时,那么它会通过原型链向上查找,一向找到null还没有话,就会返回undefined。

基于原型的担任

深入浅出JavaScript之原型链接受

function Foo(){
   this.y = 2;     
}

Foo.prototype.x = 1;
var obj3 = new Foo();  //①当行使new去挪用的时辰,函数会作为结构器去挪用②this会指向一个工具(这里是obj3),而这个工具的原型会指向结构器的prototype属性(这里是Foo.prototype)
obj3.y; //2 
obj3.x; //1    //可以看到y是工具上的,x是原型链上的原型(也就是Foo.prototype上)

prototype属性与原型

深入浅出JavaScript之原型链接受

深入浅出JavaScript之原型链接受

我们再来看看Foo.prototype是什么样的布局,当我们用函数声明去建设一个空函数的时辰,那么这个函数就有个prototype属性,而且它默认有两个属性,constructor和__proto__,

constructor属性会指向它自己Foo,__proto__是在chrome中袒露的(不是一个尺度属性,知道就行),那么Foo.prototype的原型会指向Object.prototype。因此Object.prototype上

的一些要领toString,valueOf才会被每个一样平常的工具所行使。

function Foo(){}
typeof Foo.prototype; // "object"
Foo.prototype.x = 1;
var obj3 = new Foo();

 总结一下:我们这里有个Foo函数,这个函数有个prototype的工具属性,它的浸染就是当行使new Foo()去结构实例的时辰,这个结构器的prototype属性会用作new出来的这些工具的原型。

以是我们要搞清晰,prototype和原型是两回事,prototype是函数工具上的预设属性,原型凡是是结构器上的prototype属性。

实现一个class担任其它一个class

function Person(name, age) {
   this.name = name;    //直接挪用的话,this指向全局工具(this常识点清算)
   this.age = age;      //行使new挪用Peoson的话,this会指向原型为Person.prototype的空工具,通过this.name给空工具赋值,最后this作为return值
}

Person.prototype.hi = function() {   //通过Person.prototype.hi建设全部Person实例共享的要领,(可以参考上节的左图:工具的原型会指向结构器的prototype属性,以是想让obj1,obj2,obj3共享一些要领的话,只需在原型工具上一次性地添加属性和要领就可以了);
   console.log('Hi, my name is ' + this.name + ',I am ' + this.age + ' years old now.')//这里的this是全局工具
};

Person.prototype.LEGS_NUM = 2;   //再配置一些对Person类的全部实例共享的数据
Person.prototype.ARMS_NUM = 2;
Person.prototype.walk = function() {
  console.log(this.name + ' is walking...');
};

function Student(name, age, className) {  //每个门生都属于人
  Person.call(this, name, age);  //在Student这个子类内里先挪用一下父类
  this.className = className;
}

//下一步就是我们怎么去把Student的实例担任Person.prototype的一些要领

Student.prototype = Object.create(Person.prototype);    //Object.create():建设一个空工具,而且这个工具的原型指向它的参数  //这样子我们可以在会见Student.prototype的时辰可以向上查找到Person.prototype,又可以在不影响Person的环境下,建设本身的要领
Student.prototype.constructor = Student;  //保持同等性,不配置的话constructor会指向Person

Student.prototype.hi = function() {    //通过Student.prototype.hi这样子的赋值可以包围我们基类Person.prototype.hi
  console.log('Hi, my name is ' + this.name + ',I am ' + this.age + ' years old now, and from ' + this.className + '.');
}
Student.prototype.learn = function(subject) {    //同时,我们又有本身的learn要领
  console.log(this.name + 'is learning ' + subject + ' at' + this.className + '.');
};

//test
var yun = new Student('Yunyun', 22, 'Class 3,Grade 2');
yun.hi(); //Hi,my name is Yunyun,I'm 22 years old now,and from Class 3, Grade 2.
console.log(yun.ARMS_NUM); // 2     //我们自己工具是没有的,工具的原型也就是Student.prototype也没有,可是我们用了担任,继承向上查找,找到了Person.prototype.ARMS_NUM,以是返回2
yun.walk(); //Yunyun is walking...
yun.learn('math'); //Yunyun is learning math at Class 3,Grade 2.

深入浅出JavaScript之原型链接受

团结图我们来倒过来说明一下上面代码:我们先通过new Student建设了一个Student的实例yun,yun的原型指向结构器的prototype属性(这里就是Student.prototype), Student.prototype上有hi要领和learn要领,Student.prototype是通过Object.create(Person.prototype)结构的,以是这里的Student.prototype是空工具,而且这个工具的原型指向Person.prototype,接着我们在Person.prototype上也配置了LEGS_NUM,ARMS_NUM属性以及hi,walk要领。然后我们直接界说了一个Person函数,Person.prototype就是一个预置的工具,它自己也会有它的原型,它的原型就是Object.prototype,也正是由于这样,我们任意一个工具才会有hasOwnProperty,valueOf,toString这样些民众的函数,这些函数都是从Object.prototype上来的。这样子就实现了基于原型链的担任。那我们挪用hi,walk,learn要领的时辰产生了什么呢?好比我们挪用hi要领的时辰,我们起首看这个工具yun上有没有hi要领,可是在这个实例中没有以是会向上查找,查找到yun的原型也就是Student.protoype上有这hi要领,以是最终挪用的是Student.prototype.hi,挪用其他要领也是相同的。

改变prototype

我们知道JavaScript中的prototype原型不像Java中的class,Java中的class一旦写好就很难动态的去改变了,可是JavaScript中的原型现实上也是平凡的工具,那就意味着在措施运行的阶段,我们也可以动态的给prototype添加或删除些属性。

深入浅出JavaScript之原型链接受

在上述代码的基本上,我们已经有yun这个实例了,我们接着来举办尝试:

Student.prototype.x = 101;        //通过Student.prototype.x把yun的原型动态地添加一个属性x
yun.x;   //101                    //那我们发明全部的实例城市受到影响
//接着我们做个风趣的尝试
Student.prototype = {y:2};        //我们直接修改结构器的prototype属性,把它赋值为一个新的工具
yun.y;  //undefined               
yun.x;  //101                     //以是我们得出:当我们修改Student.prototype值的时辰,并不能修改已经实例化的工具
var Tom = new Student('Tom',3,'Class LOL KengB');  
Tom.x; //undefined                //但当我们建设一个新的实例时,这一次x就不见了,
Tom.y; //2                        //而且y是新的值

以是说当动态修改prototype的时辰,是会影响全部已建设或新建设的实例的,可是修改整个prototype赋值为新的工具的话,对已建设的实例是不会影响的,可是会影响后续的实例。

实现担任的方法

实现担任有多种方法,下面我们照旧以Person和Student来说明

function Person() {
}

function Student() {
}

Student.prototype = Person.prototype; // 我们可不行用这种方法呢?这种要领是错误的:由于子类Student有本身的一些要领
//,假如通过这样子赋值,改变Student的同时也改变了Person。

Student.prototype = new Person(); //这种方法是可以实现的,可是挪用结构函数偶然辰也是有题目的,好比要传进Person一个name和age
//,这里的Student是个类,还没实例化,这时辰有些稀疏了,传什么都不是。

Student.prototype = Object.create(Person.prototype); //相对来嗣魅这中方法是较量抱负的,这里我们建设了一个空的工具
//,而且工具的原型指向Person.prototype,这样我们既担保了担任了Person.prototype上的要领,而且Student.prototype又有本身空的工具。
//可是Object.create是ES5往后才有的
本文地址:http://itbyc.com/web/javascript/13033.html
转载请注明出处。
分享是一种快乐,也是一种美德:
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
博客首页 | WEB开发 | 网站运营 | CMS使用教程 滇ICP备14002061号-1