JavaScript封装 继承 多态
1.封装(和java,c++一样)
1.1 首先了解一下什么是对象的私有变量和函数
- 默认情况下对象中的属性和方法都是公有的, 只要拿到对象就能操作对象的属性和方法,外界不能直接访问的变量和函数就是私有变量和是有函数,构造函数的本质也是一个函数, 所以也会开启一个新的作用域, 所以在构造函数中定义的变量和函数就是私有函数
1.2 什么是封装
- 封装性就是隐藏实现细节,仅对外公开接口
1.3 为什么要封装
- 不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,别人可以任意的修改你的属性
- 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改. 封装是面向对象设计本质(将变化隔离)。这样降低了数据被误用的可能 (提高安全性和灵活性)
1.4 代码说明
function Person() { this.name = "lnj"; // this.age = 34; let age = 34; this.setAge = function (myAge) { //封装 if(myAge >= 0){ age = myAge; } } this.getAge = function () { //封装 return age; } this.say = function () { console.log("hello world"); } } let obj = new Person(); // 结论: 默认情况下对象的属性和方法都是公开的, 只要拿到对象就可以操作对象的属性和方法 // console.log(obj.name); // obj.age = -3; // console.log(obj.age); // obj.say(); // console.log(age); //封装后就不可任意修改 obj.setAge(-3); console.log(obj.getAge());
1.5 私有属性注意点
针对以上代码,我们看如下操作的区别
let obj = new Person(); // 1.操作的是私有属性(局部变量) obj.setAge(-3); console.log(obj.getAge()); /* // 注意点: // 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性 // 由于私有属性的本质就是一个局部变量, 并不是真正的属性, 所以如果通过 对象.xxx的方式是找不到私有属性的, 所以会给当前对象新增一个不存在的属性 */ // 2.操作的是公有属性 obj.age = -3; console.log(obj.age); //因此会返回-3 ,而不是34
1.6 JavaScript 属性方法分类
-
静态属性/静态方法
通过构造函数访问的属性, 我们就称之为静态属性
通过构造函数调用的方法, 我们就称之为静态方法
function Person() { this.name = "lnj"; this.say = function () { console.log("hello world"); } } // 构造函数也是一个"对象", 所以我们也可以给构造函数动态添加属性和方法 Person.num = 666; Person.run = function () { console.log("run"); } console.log(Person.num); Person.run();
-
实例属性/实例方法
- 通过实例对象访问的属性, 我们就称之为实例属性
- 通过实例对象调用的方法, 我们就称之为实例方法
2.继承
继承方式一 : 借用原型链实现继承
直接将子类的原型对象修改为父类对象, 这样就能使用原型链上的属性和方法
function Person() { this.name = null; this.age = 0; this.say = function () { console.log(this.name, this.age); } } // 由于是直接将子类原型对象修改为了父类对象 // 所以继承的属性值很难自定义,当父类的值需要传进去时,子类对象不能满足这个功能 function Student() { this.score = 0; this.study = function () { console.log("day day up"); } } Student.prototype = new Person(); Student.prototype.constructor = Student; var stu1 = new Student(99); console.log(stu.name, stu.age, stu.gender, stu.score);
继承方式二 : 借用构造函数实现继承
在子类中调用父类构造函数, 并且将父类构造函数的this修改为子类对象
// 父类 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; } // 借用构造函数只是调用了父类的构造函数, 借用了构造函数中的代码 // 相当于动态的给子类添加了许多属性, 但是并没有修改子类的原型 // 所以子类无法继承父类定义在prototype的方法和属性 Person.prototype.say = function () { console.log(this.name, this.age, this.gender); } // 子类 function Student(score, name, age, gender) { Person.call(this, name, age, gender); this.score = score; } var stu1 = new Student(99, "lnj", 33, "male"); var stu2 = new Student(66, "zq", 18, "female"); console.log(stu1.name, stu1.age, stu1.gender, stu1.score); console.log(stu2.name, stu2.age, stu2.gender, stu2.score); stu1.say(); // 报错 stu2.say(); // 报错
继承方式三 : 借用构造函数+借用原型链组合继承
通过借用构造函数实现属性继承
通过借用原型链实现方法继承
// 父类 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; } Person.prototype.say = function () { console.log(this.name, this.age, this.gender); } // 子类 function Student(score, name, age, gender) { Person.call(this, name, age, gender); this.score = score; } Student.prototype = Person.prototype; Student.prototype.constructor = Student; // 由于子类的原型指向了父类的原型, 所以操作的都是同一个原型对象 // 给子类的原型新增方法或者属性, 父类也会受到影响 Student.prototype.study = function () { console.log("好好学习天天向上"); }; Student.prototype.type = "学生"; var stu = new Student(99, "lnj", 33, "male"); stu.say(); stu.study(); console.log(stu.type); var p = new Person("zq", 18, "female"); p.say(); p.study(); console.log(p.type);
继承方式四 : 专业写法
// 父类 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; } Person.prototype.say = function () { console.log(this.name, this.age, this.gender); } // 子类 function Student(score, name, age, gender) { Person.call(this, name, age, gender); this.score = score; } Student.prototype = new Person(); //区别就在这 Student.prototype.constructor = Student; // 由于子类的原型指向一个全新的对象 // 所以给子类的原型新增方法或者属性, 父类不会受到影响 Student.prototype.study = function () { console.log("好好学习天天向上"); }; Student.prototype.type = "学生"; var stu = new Student(99, "lnj", 33, "male"); stu.say(); stu.study(); console.log(stu.type); var p = new Person("zq", 18, "female"); p.say(); p.study(); // 报错 console.log(p.type); // 报错
3.多态
- 3.1 什么是强类型语言:
一般编译型语言都是强类型语言,
强类型语言,要求变量的使用要严格符合定义
例如定义 int num; 那么num中将来就只能够存储整型数据 - 3.2 什么是弱类型语言:
一般解释型语言都是弱类型语言,
弱类型语言, 不会要求变量的使用要严格符合定义
例如定义 let num; num中既可以存储整型, 也可以存储布尔类型等 - 3.3 由于js语言是弱类型的语言, 所以我们==不用关注多态==
- 3.4 多态在编程语言中的体现
父类型变量保存子类型对象, 父类型变量当前保存的对象不同, 产生的结果也不同