Js 对象之间的继承及原型链查找分析
-
Js 对象之间的继承
-
构造函数的属性继承
-
①对象拷贝 :使用for....in循环继承父对象属性
<script> var student1 = { name : "lisi", id : 1213, meaasge : function(){ console.log(name + "," + id); } }; //使用for....in循环继承父对象属性 //封装成一个函数 function student(parent,child){ for (var k in parent) { if (child[k]) { continue;//对于student2里独有的要保留的值,则跳过该次循环 } child[k] = parent[k]; } } student(student1,student2); console.log(student2); </script>
上述继承父对象是对象拷贝,实际上继承指的是类型和类型之间的继承,而封装的构造函数就是用来创建类对象的
-
②原型继承
//原型继承 function Person(name, age, sex, score) { this.name = name; this.age = age; this.sex = sex; } //抽象,提取所有的公共属性,放到一个父类型中 function Student(score){ this.score = score; } function Teacher(course){ this.crouse = crouse; } //原型对象,可以将自己的属性和方法继承给将来的实例对象使用 Student.prototype = new Person("li",21,"male"); //生成一个实例 var s1 = new Student(90); console.dir(s1);
原型继承,在没有修改constructor之前,Student是没有自己的constructor属性的,但它有继承Person对象是的constructor属性,它指向的是Person。所以,这里需要人为定义一个constructor属性,指向Student。
//原型对象,可以将自己的属性和方法继承给将来的实例对象使用 Student.prototype = new Person("li",21,"male"); Studnet.prototype.constructor = Student; //生成一个实例 var s1 = new Student(90); console.dir(s1); console.log(s1.constructor);
这种继承的缺点是,只能继承一次,不适用属性的继承。
-
③函数的 call 方法
//函数的 call 方法 function fn(a,b){ console.log(this);//指向的是window console.log(a+b); } var name = { name:"li" }; //普通函数的调用fn(1,1) //call方法 第一个参数用来指定this,第二个及以后传的是实参。 fn.call(name,3,3);
函数call ,函数本身就是一种对象,可以有自己的属性和方法。call方法本身就是一种指向函数的方法。
call方法 在调用函数的时候,有两个功能:①更改函数内部的this指向;②调用函数执行内部代码,其当调用时,第一个参数用来指定this,第二个及以后传的是实参。
-
④借用构造函数继承属性
直接对父类型的构造函数进行一个普通调用,在调用的过程中,内部的this指向的是window,通过call方法更改Person内部的this指向调用函数(如,student调用的,使用call方法后,this指向的是student)
//借用构造函数继承属性 function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } //抽象,提取所以的公共属性,放到一个父类型中 function Student(name,age,sex,score){ //对父类型进行一个普通调用 Person.call(this,name,age,sex); this.score = score; } function Teacher(name,age,sex,course){ Person.call(this,name,age,sex) this.crouse = crouse; } var s2 = new Student("li",22,"male",90); console.dir(s2);
-
构造函数的方法的继承
for...in继承、原型继承、
①for...in继承
//构造函数的方法继承 function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } //抽象,提取所有的公共属性,放到一个父类型中 Person.prototype.message = function(){ console.log(123); } function Student(name,age,sex,score){ Person.call(this,name,age,sex); this.score = score; } function Teacher(name,age,sex,course){ Person.call(this,name,age,sex) this.crouse = crouse; } //for ..in继承 for(var k in Person.prototype){ //Student保留自己的constructor 不让Studnet继承Person的constructor if(k == "constructor"){ continue; } Student.prototype[k] = Person.prototype[k]; }
②原型继承
//原型继承 Student.prototype = new Person(); //在继承的情况下也不能改变Student的constructor的指向 Student.prototype.constructor = Student; var s1 = new Student("li",21,"male",91); s1.message(); console.dir(s1);
③组合继承:属性在构造函数内部继承,方法通过原型继承
//构造函数的方法继承 function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } //抽象,提取所有的公共属性,放到一个父类型中 Person.prototype.message = function(){ console.log(123); } function Student(name,age,sex,score){ //属性的继承,使用call方法继承 Person.call(this,name,age,sex); this.score = score; } function Teacher(name,age,sex,course){ Person.call(this,name,age,sex) this.crouse = crouse; } //方法继承,通过原型继承 Student.prototype = new Person(); //在继承的情况下也不能改变Student的constructor的指向 Student.prototype.constructor = Student; var s1 = new Student("li",21,"male",91); s1.message(); console.dir(s1);
通过实例对象本身查找自己原型链的方法,这个方法继承的是Person的方法,再查找new Person()的实例对象的原型对象,查找出它的方法。
-
Student函数部分的原型图
完整的原型链查找:
将Person对象的实例赋值给Student.prototype,所以s1指向的原型对象是Person对象。
而Person的message()方法则存放在Person的原型对象中,所以s1在调用方法时,首先在自身的方法中查找,没有查找到;继续向原型查找,自己的原型上还没有找到方法;那么原型方法又要在自己的原型上继续查找,找到message()方法。
如果还未找到,即Person的原型对象上还是没有该方法,则继续想Person原型对象的原型对象查找,查找Object原型对象,若还没有,则查找错误。