封装
- 构造函数可能会需要隐藏一些属性和方法不被外界轻易访问到,可以将这些属性和方法封装起来,然后通过一个外部可以调用的特定接口 (或者公共方法) 进行调用;
- 示例代码:
function Person(name, age, sex) { this.name = name; // 公共属性 var age = age; // 私有属性 var sex = sex; // 私有属性 // 外部访问此函数,暴露出私有属性 this.show = function () { console.log(`${age}--${sex}`); } } var person = new Person("Bob", 21, "man"); console.log(person.name); // Bob console.log(person.age); // undefined person.show(); // 21 -- man
继承:四大继承方案
原型继承
-
特点:
- 不像其他语言的继承一样 (其他语言的继承一般是拷贝继承,也就是子类会把父类中的属性和方法拷贝一份到子类中,供子类调用),原型继承是把父类的原型放到子类实例的原型链上,实例想调取这些方法,是基于 __proto__ 原型链查找机制完成的;
- 子类可以重写父类的方法 (这样会导致其他实例也收到影响);
- 父类中私有或公有的属性和方法都会变成子类中公有的属性和方法;
-
示例代码:
function A(x) { this.x = x; } A.prototype.getX = function () { console.log(this.x); } function B(y) { this.y = y; } // 让父类 A 的属性和方法,在子类 B 实例的原型链上 B.prototype = new A(200); B.prototype.constructor = B; B.prototype.getY = function () { console.log(this.y); } B.prototype.__proto__.sum = function () { } let b1 = new B(20); console.log(b1.y); // 20 console.log(b1.getY()); // 20
-
图解
call 继承
-
特点:
- 只能继承私有的属性和方法 (因为把 Parent 当做普通函数执行,和其原型上的属性和方法没有关系),父类私有的变成子类私有的;
- 父类原型上的公有属性方法无法被继承过来;
-
示例代码:
function A(x) { this.x = x; } A.prototype.getX = function () { return this.x; } function B(x, y) { // this 是 B 的实例 b1 // b1.x = 200; A.call(this, x); // 因为把父类 A 当做普通函数执行,和其原型上的属性和方法没有关系 this.y = y; } B.prototype.getY = function () { return this.y; } let b1 = new B(100, 200); console.log(b1.x); // 100 console.log(b1.y); // 200 console.log(b1.getX); // undefined (父类原型上的公有属性方法无法被继承过来) console.log(b1.getY()); // 200
寄生组合继承(call + 类似于原型继承)
-
特点
- call 继承实现:私有到私有;
- 原型继承实现:公有到公有;
-
示例代码:
function A(x) { this.x = x; } A.prototype.getX = function () { return this.x; } function B(y) { // 继承 A 的私有属性和方法 A.call(this, 200); this.y = y; } // Object.create 原理: // - 创建一个空函数 Fn 构造函数,Fn.prototype 指向 A.prototype // - 返回值是 new Fn 的实例对象 B.prototype = Object.create(A.prototype); B.prototype.contructor = B; B.prototype.getY = function () { return this.y; } let b1 = new B(); console.log(b1.x); console.log(b1.y);
-
图解
ES6 中 class 实现继承
-
ES6 中基于 class 创建出来的类不能当做普通函数执行;
-
示例代码:
class A { constructor(x) { this.x = x; } getX() { console.log(this.x); } } // extends 继承和寄生组合继承基本类似,「子类公有」继承「父类公有」 // class Child extends Parent{} => B.prototype.__proto__ = A.prototype class B extends A { constructor(y) { // 子类只有继承了父类,才可以不写 constructor // 浏览器会默认自己创建 constructor(...args){super(...args)} 并执行 // 但是一旦写了 constructor,必需要写 super() => A.call(this,200) super(200); this.y = y; } getY() { console.log(this.y); } } // B.__proto__ = Object.create(A.prototype);// 不允许重定向原型的指向 let b1 = new B(200); console.log(b1);
多态:同一接口不同实现
-
就是在执行同一操作且作用于不同对象时,返回不同的结果,其实也就是把做什么和由谁去做分开,这样使得代码更容易维护,且条例清晰;
-
示例代码:
function Animal() { this.bite = function () { console.log("animal bite!"); } } function Cat() { this.bite = function () { console.log("Cat bite!"); } } Cat.prototype = new Animal(); function Dog() { this.bite = function () { console.log("Dog bite!"); } } Dog.prototype = new Animal(); function AnimalBite(animal) { if (animal instanceof Animal) //这 里是判断 animal 的原型是否指向 Animal animal.bite(); } var cat = new Cat(); var dog = new Dog(); AnimalBite(cat); // Cat bite! AnimalBite(dog); // Dog bite!
第 2️⃣ 座大山:数据类型检测的 4 种方案
上一篇