一、封装
1.对象实现封装
var Book = function(id, name) {
// 私有属性
var num = 1;
// 私有方法
function checkId() {
console.log('checkId');
};
// 特权方法:可访问对象的公有属性和方法,也能访问类或对象的私有属性和方法,不能访问类的公有属性和方法
this.getName = function() {
console.log(num);
console.log(checkId);
console.log(this.id);
console.log(this.copy);
// console.log(this.isChinese);
// console.log(this.resetTime);
console.log(this.isJSBook);
console.log(this.display);
};
// 实例公有属性
this.id = id;
// 实例公有方法
this.copy = function() {
console.log('copy');
};
// 构造器:在创建实例时能初始化实例属性的特权方法
// this.setName(name);
}
// 类静态公有属性(实例不能访问)
Book.isChinese = true;
// 类静态公有方法(实例不能访问)
Book.resetTime = function() {
console.log('resetTime')
}
Book.prototype = {
// 公有属性
isJSBook: false,
// 公有方法
display: function() {
console.log('display')
}
}
var book = new Book(2,'sjsf');
book.getName()
2.闭包实现封装
var Book = (function() {
// 静态私有变量
var bookNum = 0;
// 静态私有方法
function checkBook() {}
// 创建类
function book(newId, newName) {
// 私有变量
var name, price;
// 私有方法
function checkId(id) {};
// 特权方法
this.getName = function() {
console.log('getName');
console.log(this.id);
console.log(newName);
};
// 公有属性
this.id = newId;
// 公有方法
this.copy = function() {};
}
// 构建原型
book.prototype = {
// 静态公有属性
isJSBook: false,
// 静态公有方法
display: function() {}
}
// 返回类
return book;
})();
Book.isChinese =true;
var book = new Book(2,'sjsf');
book.getName()
二、继承
new:通过new关键字创建的对象:实质是对新对象this的不断赋值,并将prototype指向类的prototype对象
1.类式继承:
原理:子类原型=父类实例。(父类实例是通过new创建出来的,能获取到父类构造函数中的公有属性和方法,以及父类原型中 的属性和方法)。
功能:继承了父类构造函数中的公有属性和方法,以及父类原型中的属性和方法。
缺点:(1)父类构造函数中的公有属性若是引用类型,会在子类中被所有实例共用(一改全改)
(2)创建父类时无法向父类传递参数,因此在实例化父类时无法对父类构造函数的属性进行初始化。
function Parent(){
this.name = 'John';
this.type = [1,2,3];
}
Parent.prototype.show = function(){
console.log(123);
}
function Son(){
this.age = 12;
}
Son.prototype = new Parent();
var son1 = new Son();
var son2 = new Son();
console.log(son1.name); // John
console.log(son1.type); // [1,2,3]
console.log(son2.type); // [1,2,3]
console.log(son1.show); // function(){ console.log(123);}
son1.type.push(4);
console.log(son1.type); // [1,2,3,4]
console.log(son2.type); // [1,2,3,4]
2.构造函数继承
原理:将父类构造函数中的公有属性和公有方法指向子类构造函数(call方法)
功能:继承父类构造函数中的公有属性和公有方法,解决了父类构造函数中的公有属性共用和父类实例化时无法初始化的问题。
缺点:无法继承父类原型中的属性和方法
function Parent(name) {
this.name = name;
this.type = [1,2,3];
}
Parent.prototype.show = function() {
console.log('show');
}
function Son(name) {
this.age = 12;
Parent.call(this,name);
}
var son1 = new Son('John');
var son2 = new Son('Amy');
console.log(son1.name); // John
console.log(son1.show); // undefined 继承不了父类原型中的属性和方法
console.log(son1.type); // [1,2,3]
console.log(son2.type); // [1,2,3]
son1.type.push(4);
console.log(son1.type); // [1,2,3,4]
console.log(son2.type); // [1,2,3]
3.组合继承(结合类式继承和构造函数继承)
原理:子类原型=父类实例,父类构造函数中的公有属性和公有方法指向子类构造函数
功能:继承了父类构造函数中的公有属性和方法,以及父类原型中的属性和方法。
缺点:实行了两次继承了父类构造函数中的公有属性和方法。
function Parent(name) {
this.name = name;
this.type = [1,2,3];
}
Parent.prototype.show = function() {
console.log('show');
}
function Son(name) {
this.age = 12;
Parent.call(this,name);
}
Son.prototype = new Parent();
var son1 = new Son('John');
var son2 = new Son('Amy');
console.log(son1.name); // John
console.log(son1.show); // function show() {console.log('show');}
console.log(son1.type); // [1,2,3]
console.log(son2.type); // [1,2,3]
son1.type.push(4);
console.log(son1.type); // [1,2,3,4]
console.log(son2.type); // [1,2,3]
4.原型式继承(相当于类式继承)
原理:根据一个对象创建另一个对象(子类原型=父类实例)
功能:继承了父类实例中的属性和方法,以及父类原型中的属性和方法。
缺点:(1)父类构造函数中的公有属性若是引用类型,会在子类中被所有实例共用(一改全改)
(2)创建父类时无法向父类传递参数,因此在实例化父类时无法对父类构造函数的属性进行初始化。
function inheritObj(obj) {
function Son() {}
Son.prototype = obj;
return new Son();
}
var obj = {
name : '123',
type : [1,2,3]
}
var son1 = inheritObj(obj);
var son2 = inheritObj(obj);
console.log(son1); //{}
console.log(son1.__proto__); //{name : '123',type : [1,2,3]}
相当于
var son = Object.create(obj);
5.寄生式继承(对原型继承的二次封装,添加自身属性和方法)
原理:根据一个对象创建另一个对象(子类原型=父类实例)
功能:继承了父类实例中的属性和方法,以及父类原型中的属性和方法。
缺点:(1)父类构造函数中的公有属性若是引用类型,会在子类中被所有实例共用(一改全改)
(2)创建父类时无法向父类传递参数,因此在实例化父类时无法对父类构造函数的属性进行初始化。
function inheritObj(obj) {
function Son() {}
Son.prototype = obj;
return new Son();
}
function Son(obj) {
var son1 = inheritObj(obj);
son1.show = function() {
console.log(show);
}
return son1;
}
var obj = {
name : '123',
type : [1,2,3]
}
var son1 = new Son(obj);
var son2 = new Son(obj);
console.log(son1); //{show:f}
console.log(son1.__proto__); //{name : '123',type : [1,2,3]}
6.寄生组合式继承
原理:将父类构造函数中的公有属性和公有方法指向子类构造函数(call方法),根据父类实例创建对象(子类原型=父类实例),对象的构造函数指向子类构造函数,子类原型指向对象
功能:继承了父类实例中的属性和方法,以及父类原型中的属性和方法。
function inherit(son,parent) {
var obj = Object.create(parent.prototype);
obj.constructor = son;
son.prototype = obj;
}
function Parent(name) {
this.name = name;
this.type = [1,2,3];
}
Parent.prototype.show = function() {
console.log('show');
}
function Son(name) {
Parent.call(this,name);
}
inherit(Son,Parent)
var son1 = new Son('John');
console.log(son1); // {name : '123',type : [1,2,3]}
console.log(son1.__proto__); // Parent {constructor: ƒ}
console.log(son1.name); // John
console.log(son1.type); // [1, 2, 3]
三、多继承
由于寄生组合式继承是依赖原型链实现的,但原型链只有一条,不能实现多继承。
多继承原理:将父类实例中的属性和方法复制到子类实例中
var mix = function() {
var i = 1,
len = arguments.length,
target =arguments[0],
arg;
for(; i < len; i++) {
arg = arguments[i];
// 遍历父类实例属性
for(var key in arg) {
target[key] = arg[key];
}
}
return target;
}
var book1 = {
name:'jsBook'
}
var book2 = {
year:14,
address:'Chinese'
}
var book3 = mix(book1,book2)
console.log(book1); //{name: "jsBook", year: 14, address: "Chinese"}
console.log(book3); //{name: "jsBook", year: 14, address: "Chinese"}
四、多态
多态:同一个方法,根据参数个数的不同,有多种调用方式
function Add() {
// 无参数
function zero() {
return 10;
}
// 1个参数
function one(num) {
return 10 + num;
}
// 2个参数
function two(num1, num2) {
return 10 + num1 + num2;
}
this.add = function() {
var arg = arguments,
len = arguments.length;
switch(len) {
case 0:
return zero();
case 1:
return one(arg[0]);
case 2:
return two(arg[0],arg[1]);
}
}
}
var test = new Add();
console.log(test.add()); // 10
console.log(test.add(1)); // 11
console.log(test.add(1,2)); // 13