原型、原型链、继承
作用
数据共享,节省内存空间
案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>title</title> <script> function Person(name,age) { this.name=name; this.age=age; } //通过原型来添加方法,解决数据共享,节省内存空间 Person.prototype.eat=function () { console.log("吃凉菜"); }; var p1=new Person("小明",20); var p2=new Person("小红",30); console.log(p1.eat==p2.eat);//true console.dir(p1); console.dir(p2); //实例对象中根本没有eat方法,但是能够使用,这是为什么? </script> </head> <body> </body> </html>
通过原型的方式修改标签样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>title</title> <style> div { width: 300px; height: 200px; background-color: red; } </style> </head> <body> <input type="button" value="显示效果" id="btn"/> <div id="dv"></div> <script src="common.js"></script> <script> function ChangeStyle(btnObj, dvObj, json) { // this代指当前对象 this.btnObj = btnObj; this.dvObj = dvObj; this.json = json; } ChangeStyle.prototype.init = function () { //点击按钮,改变div多个样式属性值 // this代指当前对象 var that = this; this.btnObj.onclick = function () {//按钮 console.log(this) // this:代指 this.btnObj for (var key in that.json) { that.dvObj.style[key] = that.json[key]; } }; }; var json = {"width": "500px", "height": "800px", "backgroundColor": "blue", "opacity": "0.2"}; var cs = new ChangeStyle(my$("btn"), my$("dv"), json); cs.init();//调用方法 //点击p标签,设置div的样式 </script> </body> </html>
简单原型的案例
需要手动修改构造器的指向
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>title</title> <script> function Student(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } //简单的原型写法 Student.prototype = { //手动修改构造器的指向 constructor:Student, height: "188", weight: "55kg", study: function () { console.log("学习好开心啊"); }, eat: function () { console.log("我要吃好吃的"); } }; var stu=new Student("段飞",20,"男"); stu.eat(); stu.study(); console.dir(Student); console.dir(stu); </script> </head> <body> </body> </html>
构造函数,原型,实例对象三者间的关系
构造函数
构造函数中有一个属性叫prototype,是构造函数的原型对象
构造函数的原型对象(prototype)中有一个constructor构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数
原型
实例对象的原型对象(
__proto__
)指向的是该构造函数的原型对象
实例对象
构造函数的原型对象(prototype)中的方法是可以被实例对象直接访问的
实例对象属性方法的调用顺序
先在构造函数中找
构造函数中没有,调用原型中的属性和方法、
圆形中没有则报错
改变原型的指向(原型链)
原型指向可以改变 实例对象的原型
__proto__
指向的是该对象所在的构造函数的原型对象构造函数的原型对象(prototype)指向如果改变了,实例对象的原型(__proto__
)指向也会发生改变原型的指向是可以改变的 实例对象和原型对象之间的关系是通过
__proto__
原型来联系起来的,这个关系就是原型链
//人的构造函数 function Person(age) { this.age=10; } //人的原型对象方法 Person.prototype.eat=function () { console.log("人的吃"); }; //学生的构造函数 function Student() { } Student.prototype.sayHi=function () { console.log("嗨,小苏你好帅哦"); }; //学生的原型,指向了一个人的实例对象 Student.prototype=new Person(10); var stu=new Student(); stu.eat(); stu.sayHi();
实例对象和原型对象中属性重名的问题
实例对象访问这个属性,应该先从实例对象中找,找到了就直接用
找不到就去指向的原型对象中找,找到了就使用
function Person(age,sex) { this.age=age; this.sex=sex; } Person.prototype.sex="女"; var per=new Person(10,"男"); console.log(per.sex); // 男 Person.prototype.sex="哦唛嘎的"; // 改变原型中的sex值 per.sex="人"; // 改变对象中sex的值 console.dir(per);
继承
通过原型实现继承
在构造函数的原型中添加要继承的对象,即可使用继承的方法
Student.prototype=new Person("小明",10,"男");
注:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都是一样的了
只能调用对象的属性,重新赋值,才能改变初始化的数据
这种赋值方式很不方便
function Person(name,age,sex) { this.name=name; this.sex=sex; this.age=age; } Person.prototype.eat=function () { console.log("人可以吃东西"); }; Person.prototype.sleep=function () { console.log("人在睡觉"); }; Person.prototype.play=function () { console.log("生活就是不一样的玩法而已"); }; function Student(score) { this.score=score; } //改变学生的原型的指向即可==========>学生和人已经发生关系 // Student.prototype=new Person("小明",10,"男"); // 所有继承的都会有初始值 Student.prototype=new Person(); // 只继承属性,不赋初始值 Student.prototype.study=function () { console.log("学习很累很累的哦."); }; //相同的代码太多,造成了代码的冗余(重复的代码) var stu=new Student(100); console.log(stu.name); console.log(stu.age); console.log(stu.sex); stu.eat(); stu.play(); stu.sleep(); console.log("下面的是学生对象中自己有的"); console.log(stu.score); stu.study();
借用构造函数继承
借用构造函数:构造函数名字.call(当前对象,属性,属性,属性....);
解决了属性继承,并且值不重复的问题
缺陷:
父级类别中的方法不能继承
function Person(name, age, sex, weight) { this.name = name; this.age = age; this.sex = sex; this.weight = weight; } Person.prototype.sayHi = function () { console.log("您好"); }; function Student(name,age,sex,weight,score) { //借用构造函数 // >> 会引用Person中的内容 // >> 一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。 Person.call(this,name,age,sex,weight); this.score = score; } var stu1 = new Student("小明",10,"男","10kg","100"); console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score); var stu2 = new Student("小红",20,"女","20kg","120"); console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score); var stu3 = new Student("小丽",30,"妖","30kg","130"); console.log(stu3.name, stu3.age, stu3.sex, stu3.weight, stu3.score);
组合继承
原型继承 + 借用用构造函数继承
//原型实现继承 //借用构造函数实现继承 //组合继承:原型继承+借用构造函数继承 function Person(name,age,sex) { this.name=name; this.age=age; this.sex=sex; } Person.prototype.sayHi=function () { console.log("阿涅哈斯诶呦"); }; function Student(name,age,sex,score) { //借用构造函数:属性值重复的问题 // >> 解决原型继承中:继承过来的属性值一样的问题 Person.call(this,name,age,sex); this.score=score; } //改变原型指向----继承 Student.prototype=new Person();//不传值,解决借用用构造函数继承中:父类级别的方法不能继承的问题 Student.prototype.eat=function () { console.log("吃东西"); };
保存redis相关笔记