【js面向对象第二天】 一、如何理解原型和原型链二、三种不同继承方式的优缺点 三、call()和apply()四,对象的私有属性
目录
一、如何理解原型和原型链
二、三种不同继承方式的优缺点
三、call()和apply()
四,对象的私有属性
一、如何理解原型和原型链
Object 是所有对象的爸爸,所有对象都可以通过 __ proto__ 找到它;
Function 是所有函数的爸爸,所有函数都可以通过 __ proto__ 找到它;
函数的 prototype 是一个对象;
对象的 __ proto__ 属性指向原型, __ proto__ 将对象和原型连接起来组成了原型链
原型链继承案例代码:
// 原型连继承 //创建构造函数 人类 function People(name, age) { this.name = name; this.age = age; } People.prototype.sleep = function() { console.log(this.name + "在睡觉"); return this; } People.prototype.eat = function() { console.log(this.name + "在吃饭") return this; //返回this,实现方法的链式调用 } //创建学生类 并继承人类的属性和原型 function Student(name, age) { // 将people的this指向student的this 继承构造函数people的属性 People.call(this, name, age); } // 将构造函数people实例化的对象设置为student的原型,达到继承people的原型的效果 Student.prototype = new People("zhangsan", 20) // 设置学生类的study方法 Student.prototype.study = function() { console.log(this.name + "正在学习"); return this; }//使用构造函数 学生类 创建一个学生对象 s1 var s1 = new Student("张三", 22) s1.eat().study().sleep(); console.log(s1);
图解
如图所示:
s1对象的_proto_属性指向它的构造函数Student的原型——Student.prototype
但是Student.prototype=new People(),所以s1的_proto_属性直接指向了构造函数function People创建的people对象,people对象中的_proto_属性又指向了它的构造函数的原型——people.prototype,而构造函数people原型中的_proto_属性直接指向了Object,Object中的_proto_属性指向null
二、三种不同继承方式的优缺点
// 三种不同继承方式 //创建构造函数 人类 function People(name, age) { this.name = name; this.age = age; } People.prototype.sleep = function() { console.log(this.name + "在睡觉"); return this; } People.prototype.eat = function() { console.log(this.name + "在吃饭") return this; //返回this,实现方法的链式调用 } // 1.原型链继承 : 将原型改成 对应的对象(要继承的构造函数创建的对象) //问题:无法初始化对应的属性 比如这里的name和age // 创建学生类 使用原型链继承法继承人类 function Student(name, age) { } Student.prototype = new People("张三", 22) Student.prototype.song = function() { console.log(this.name + "正在唱歌"); } // 创建两个学生对象 var s1 = new Student("王一", 20); var s2 = new Student("tom", 18); console.log(s1.name, s1.age, s2.name, s2.age) //张三 22 张三 22// s1,s2的name和age属性无法更改 // 2.冒充继承法:通过call或者apply改变原有函数的this指向 // 创建教师类 使用冒充继承法继承人类 // 将构造函数 人类的this指向当前构造函数 教师类的this function Teacher(name, age) { People.call(this, name, age) } Teacher.prototype.teach = function() { console.log(this.name + "正在讲课") } var t1 = new Teacher("李老师", 24) t1.teach() //李老师正在讲课 console.log(t1.name) //李老师 // t1.sleep() //Uncaught TypeError: t1.sleep is not a function // 缺点:无法继承原型中的方法和属性 // 3:组合继承: 原型链继承+冒充继承 //创建好学生类 并继承人类的属性和原型 // 优点:同时继承原型和属性,可以对属性初始化 function goodStudent(name, age) { // 将people的this指向student的this 继承构造函数people的属性 People.call(this, name, age); } // 将构造函数people实例化的对象设置为student的原型,达到继承people的原型的效果 goodStudent.prototype = new People("zhangsan", 20) // 设置学生类的study方法 goodStudent.prototype.study = function() { console.log(this.name + "正在学习"); return this; } //使用构造函数 学生类 创建一个学生对象 s1 var s1 = new goodStudent("李四", 22) s1.eat().study().sleep(); console.log(s1.name);//李四
三、call()和apply()
1.共同点:都能改变this指向
2.区别:加入参数的方式不同
// apply的参数: // 第一个参数: 方法执行的时候, 方法中的this的指向 // 第二个参数: 方法执行的时候, 所有参数组成的一个数组-- > []; test.call(obj,["hello"])
// Math.max() 和 Math.min()方法 中都是放数值,数值之间用逗号隔开 var arr1 = [20, 13, 56, 34, 89]; var arr2 = [12, 13, 14, 78, 90]; console.log(Math.max(arr)) //NAN console.log(Math.max(20, 13, 56, 34, 89)) //89 // 使用apply()方法就可以在Math.max() 和 Math.min()方法中放入数组 console.log(Math.max.apply(null, arr2)); //90 var res = Math.min.apply(null, arr2); console.log(res); //12
四,对象的私有属性
面向对象编程特点:
1.抽象性: 通过对象来分析具体问题
2.封装性: 将属性和方法,全部都封装到对象中,便于维护 节约二次开发成本 安全
3.继承性:将对象直接属性或者方法,进行传递 Java C python
4.多态性:一个类 产生多种对象!!
对象属性 :分为两种
公有属性:可以任意访问 ,修改的
私有属性:必须通过方法才能,访问或者修改 。
一.需要一定安全性的属性 比如密码
二.有一定的校验规则
如何设置对象的私有属性?请看下面的代码
function Person(name, age, ID) { // 设置私有属性ID var ID = ID; this.name = name; this.age = age; // 获取ID的方法 this.getID = function() { return ID; }; // 修改ID的方法 this.setID = function(value) { // 设置校验规则 var reg = /\d{6}$/; if (reg.test(value)) { ID = value; } else { alert("ID必须是六位数字组成!") } } } var p1 = new Person("小智", 18, 127346) // 获取p1的ID console.log(p1.ID) //undefined console.log(p1.getID()) //127346 // 修改p1的ID p1.setID(238434) console.log(p1.getID()) //238434
《新程序员》:云原生和全面数字化实践
50位技术专家共同创作,文字、视频、音频交互阅读