JavaScript原型链和继承
文章目录
- JavaScript原型链和继承
- 一、原型
- 二、原型链
- 原型链图解
- 了解this与call/apply方法
- 三、继承
一、原型
1.定义:原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖
先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
2.利用原型特点和概念,可以提取共有属性。
3.对象属性的增删和原型上属性增删改查。
4.对象如何查看原型 ==> 隐式属性 __ proto __
5.对象如何查看对象的构造函数 ==> constructor。
自己身上有属性,原型上也有属性,取近的,用自己的
二、原型链
1、构成原型链
Grand.prototype.lastName = "dzq";
function Grand(){};
var grand = new Grand();//grand对象继承了祖先的的lastName属性
console.log(grand.lastName);
Father.prototype = grand;//将对象grand赋给Father的原型
function Father(){
this.name = "lyh";
};
var father = new Father();//father就可以拿到lastName属性和它自己的name属性
console.log(father.lastName,father.name);
Son.prototype = father;//同理将对象father赋给Son的原型
function Son(){
this.hehe = "txc";
};
var son = new Son();//son就能拿到lastName、name属性,和自己的hehe属性
console.log(son.lastName,son.name,son.hehe)
2、原型链上属性的增删改查
原型链上的增删改查和原型基本上是一致的。只有本人有的权限,子孙是没有的。
3、谁调用的方法内部 this 就是谁
4、绝大多数对象的最终都会继承自Object.prototype
5、Object.create(原型);
Object.create 也能创建对象。var obj = Object.create(这里必须要有原型)
6、原型方法上的重写
原型上有这个方法,我自己又写了一个和原型上同一名字,但不同功能的方法,叫
做重写(同一名字的函数,不同重写方式)
通过返回值,形参列表不同传参
同样的名实现不同功能的,就是重写
原型链图解
了解this与call/apply方法
this
1.函数预编译过程 this —>指向 window
2.全局作用域里 this —> 指向 window
3.obj.func(); func()里面的 this 指向 obj(谁调用这个函数this就指向谁)
4.call/apply 可以改变函数运行时 this 指向,它们两的区别,是后面传的参数形式不同。
call
直接执行 Person.call ( )和 Person ( )没有区别
Person.call( );括号里面可以传东西
如果 Person.call( obj );里面的 call 让 person 所有的 this 都变成 obj
不 new 的话,this 默认指向 window。call 的使用必须要 new
call 的第一位参数用于改变 this 指向,第二位实参(对应第一个形参)及以后的参数都当做正常的实参,传到形参里面去
function Person(name,age,sex){
this.name=name;
this,age=age;
this.sex=sex;
}
function Student(name,age,sex,tel,grade){
this.name=name;
this.age=age;
this.sex=sex;
this.tel=tel;
this.grade=grade;
}
var student =new Student("sunny","123","male",123,2000)
/*call 改变 this 指向,借用别人的函数,实现自己的功能。
只能在你的需求完全涵盖别人的时候才能使用
如果不想要 age 这个,就不能使用这种方法*/
function Person(name,age,sex){
this.name=name;
this,age=age;
this.sex=sex;
}
function Student(name,age,sex,tel,grade){
Person.call(this,name,age,sex)
this.tel=tel;
this.grade=grade;
}
/*Person.call(this, name, age, sex);里面的 this 现在是 new 了以后的 var this={}
利用 Person 方法,实现了 Student 自己的封装*/
apply
apply 也是改变 this 指向的,只是传参列表不同,第一位也是改变 this 指向的人,第
二位,apply 只能传一个实参,而且必须传数组 argunments
call 需要把实参按照形参的个数传进去
三、继承
继承发展史
1.传统形式 ==> 原型链
问题:过多的继承了没用的属性
2.借用构造函数 ==>利用 call、apply 所以不算标准的继承模式
1)不能继承借用构造函数的原型
2)每次构造函数都要多走一个函数 ==>浪费效率
3.共享原型(较好的继承方法)
不能随便改动自己的原型
Father.prototype.lastName = 'dzq';
function Father(){};
function Son(){};
Son.prototype = Father.prototype;//原型对象指向一个房间
var son = new Son();
圣杯模式
圣杯模式是在方法三的共有原型,但是在共有原型的基础上有改变。
共享原型是:son.prototype=father.prototype
圣杯模式是:另外加个构造函数 function F(){}当做中间层,然后让 F 和 father 共
有一个原型 F.prototype=father.prototype,然后 son.prototype = new F();使用原
型链形成了继承关系,现在改 son.prototype 就不会影响 father.prototype
var inherit = (function (){
var F = function(){};//定义一个中间构造函数,私有化变量
return function (target,origin){//target接受继承者,origin继承的目标
F.prototype = origin.prototype;//将继承的目标原型对象赋给F.prototype
target.prototype = new F();
//new一个实例对象赋给接受继承的target
//new后,Target.prototype指向的一个全新的地方
//改变Target的原型链就不会影响到Origin
target.prototype.constuctor = target;//将constructor指向自己
target.prototype.uber = origin.prototype;//保存自己真正继承的目标,以便后期访问
}
}());