这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章主要介绍了浅谈 javascript 原型链与继承的相关资料, 需要的朋友可以参考下
js 原型链与继承是 js 中的重点,所以我们通过以下三个例子来进行详细的讲解。
首先定义一个对象 obj,该对象的原型为 obj._proto_, 我们可以用 ES5 中的 getPrototypeOf 这一方法来查询 obj 的原型,我们通过判断 obj 的原型是否与 Object.prototype 相等来证明是否存在 obj 的原型,答案返回 true,所以存在。然后我们定义一个函数 foo(), 任何一个函数都有它的 prototype 对象,即函数的原型,我们可以在函数的原型上添加任意属性,之后通过 new 一个实例化的对象可以共享其属性(下面的两个例子会详细介绍)。
- function foo(){}
- foo.prototype.z = 3;
- var obj = new foo();
- obj.x=1;
- obj.y=2;
- obj.x //1
- obj.y //2
- obj.z //3
- typeof obj.toString; //function
- obj.valueOf(); // foo {x: 1, y: 2, z: 3}
- obj.hasOwnProperty('z'); //false
在这里,obj 的原型(_proto_)指向 foo 函数的 prototype 属性,foo.prototype 的原型指向 Object.prototype, 原型链的末端则为 null, 通过 hasOwnProperty 来查看 z 属性是否是 obj 上的,显示 false, 则 obj 上本没有 z 属性,但通过查找其原型链,发现在 foo.prototype 上有,所以 obj.z=3, 并且对于首例上 obj.valueOf() 以及 toString 都是 Object.prototype 上的,所以任何一个对象都有这两个属性,因为任何一个对象的原型都是 Object.prototype. 当然除了以下一个特例,
- var obj2 = Object.create(null);
- obj2.valueOf(); //undefined
Object.create() 为创建一个空对象,并且此对象的原型指向参数。下面一个综合实例向大家展示一下如何实现一个 class 来继承另外一个 class
- //声明一个构造函数Person
- function Person(name,age){
- this.name = name;
- this.age = age;
- }
- Person.prototype.hi = function (){
- console.log('Hi,my name is ' + this.name +',my age is '+this.age);
- };
- Person.prototype.LEGS_NUM=2;
- Person.prototype.ARMS_NUM=2;
- Person.prototype.walk = function (){
- console.log(this.name+' is walking !');
- };
- function Student(name,age,classNum){
- Person.call(this,name,age);
- this.classNum = classNum;
- }
- //创建一个空对象
- Student.prototype = Object.create(Person.prototype);
- //constructor指定创建一个对象的函数。
- Student.prototype.constructor = Student;
- Student.prototype.hi = function (){
- console.log('Hi,my name is ' + this.name +',my age is '+this.age+' and my class is '+this.classNum);
- };
- Student.prototype.learns = function (sub){
- console.log(this.name+' is learning '+sub);
- };
- //实例化一个对象Bosn
- var Bosn = new Student('bosn',27,'Class 3');
- Bosn.hi(); //Hi,my name is bosn,my age is 27 and my class is Class 3
- Bosn.LEGS_NUM; //2
- Bosn.walk(); //bosn is walking !
- Bosn.learns('Math'); //bosn is learning Math
构造函数 Person 与 Student 的 this 指向实例化的对象(Bosn),并且此对象的原型指向构造器的 prototype。
我们用 Object.create() 方法来创建一个空对象,此对象的原型事项 Person.prototype,这样写的好处是我们可以在不影响 Person.prototype 属性的前提下可以自己创建 Studnet.prototype 的任意属性,并且可以继承 Person.prototype 上原有的属性,因为子类 Student 是继承基类 Person 的。如果直接写 Person.prototype = Student.prototype, 那他两同时指向一个对象,在给 Student.prototype 添加属性的同时,Person 的原型链上也会增加同样的属性。
对于构造函数 Student 里面的 call 方法,里面的 this 指向新创建的 Student 的实例化的对象,并通过 call 来实现继承。
Student.prototype.constructor = Student, 这句话的含义是指定 Student 为创建 Student.prototype 这个对象的函数,如果不写这句话,该对象的函数还是 Person。
对于继承,一共有三种方式来实现,
- function Person(name,age){
- this.name = name;
- this.age = age;
- }
- function Student(){
- }
- Student.prototype = Person.prototype; //1
- Student.prototype = Object.create(Person.prototype); //2
- Student.prototype = new Person(); //3
第一种,刚刚在上面已经说过了,直接这样写会让子类和基类同时指向 bosn 实例;
第二种,恰到好处的避开这一点,并很好地实现继承,让实例先查询子类,若没有相应属性,再查询基类;
第三种,虽然也实现了继承,但调用了 Person 这个构造函数,这个例子中此构造函数有两个参数 name 和 age,但这第三种什么也没有传,并没有实例化。
来源: http://www.phperz.com/article/17/0412/270445.html