面向对象编程
·
Yin灏
/* 封装 */
/**
* 创建一个类
*/
var Book = function (id, bookname, price) {
this.id = id;
this.bookname = bookname;
this.price = price;
};
Book.prototype.display = function () {
// 展示这本书
};
// 或者
Book.prototype = {
display: function () {},
};
var book = new Book(10, "JavaScript设计模式", 50);
console.log(book.bookname);
/* 属性与方法封装 */
var Book = function (id, name, price) {
// 私有属性和方法,外部无法访问
var num = 1;
function checkId() {}
// 特权方法
this.getName = function () {};
this.getPrice = function () {};
this.setName = function () {};
this.setPrice = function () {};
// 公有属性和公有方法
this.id = id;
this.copy = copy;
// 构造器
this.setName(name);
this.setPrice(price);
};
// 静态公有属性,对象不能访问
Book.isChinese = true;
Book.resetTime = function () {
console.log("new Time");
};
Book.prototype = {
// 公有属性
isJSBook: false,
// 公有方法
display: function () {},
};
// 使用
var b = new Book(11, "JavaScript设计模式", 50);
console.log(b.num); // undefined
console.log(b.isJSBook); // false
console.log(b.id); // 11
console.log(b.isChinese); // undefined
console.log(Book.isChinese); // true
Book.resetTime(); // undefined
/**
* 有时经常将类的静态变量通过闭包实现。
*/
// 利用闭包实现
var Book = (function () {
// 静态私有变量
var bookNum = 0;
// 静态私有方法
function checkBook(name) {}
// 返回构造函数
return function (newId, newName, newPrice) {
// 私有变量
var name, price;
// 私有方法
function checkID(id) {}
// 特权方法
this.getName = function () {};
this.getPrice = function () {};
this.setName = function () {};
this.setPrice = function () {};
// 公有属性
this.id = newId;
// 公有方法
this.copy = function () {};
bookNum++;
if (bookNum > 100) {
throw new Error("我们仅出版 100 本书");
}
// 构造器
this.setName(name);
this.setPrice(price);
};
})();
Book.prototype = {
// 静态公有属性
isJSBook: false,
// 静态公有方法
display: function () {},
};
/**
* 在闭包外部添加原型属性和方法看上去像脱离了闭包这个类,
*/
var Book = (function () {
// 静态私有变量
var bookNum = 0;
// 静态私有方法
function checkBook(name) {}
// 返回构造函数
function _book(newId, newName, newPrice) {
// 私有变量
var name, price;
// 私有方法
function checkID(id) {}
// 特权方法
this.getName = function () {};
this.getPrice = function () {};
this.setName = function () {};
this.setPrice = function () {};
// 公有属性
this.id = newId;
// 公有方法
this.copy = function () {};
bookNum++;
if (bookNum > 100) {
throw new Error("我们仅出版 100 本书");
}
// 构造器
this.setName(name);
this.setPrice(price);
}
// 构建原型
_book.prototype = {
// 静态公有属性
isJSBook: false,
// 静态公有方法
display: function () {},
};
// 返回类
return _book;
})();
/**
* 创建对象安全模式
* 避免忘记 new 关键字造成的问题
*/
// 图书类
var Book = function (title, time, type) {
if (this instanceof Book) {
this.title = title;
this.time = time;
this.type = type;
} else {
return new Book(title, time, type);
}
};
var book = Book("JavaScript", "2014", "js");
/* 继承 */
/**
* 类式继承
*/
// 父类
function SuperClass() {
this.superValue = true;
}
SuperClass.prototype.getSuperValue = function () {
return this.superValue;
};
// 子类
function SubClass() {
this.subValue = false;
}
// 继承父类
SubClass.prototype = new SuperClass();
// 为子类添加公有方法
SubClass.prototype.getSubValue = function () {
return this.subValue;
};
var instance = new SubClass();
console.log(instance.getSuperValue()); // true
console.log(instance.getSubValue()); // false
/**
* 构造函数继承
* 解决共有属性中有引用类型,并且相互影响的问题
* 通过下面的方式不能继承父类的原型上的属性和方法
*/
// 父类
function SuperClass(id) {
// 引用类型共有属性
this.books = ["JavaScript", "html", "css"];
// 值类型共有属性
this.id = id;
}
SuperClass.prototype.showBooks = function () {
console.log(this.books);
};
// 子类
function SubClass(id) {
// 继承父类
SuperClass.call(this, id);
}
var instance1 = new SubClass(10);
var instance2 = new SubClass(11);
instance1.books.push("设计模式");
console.log(instance1.books); // ["JavaScript", "html", "css", "设计模式"];
console.log(instance1.id); // 10
console.log(instance2, books); // ["JavaScript", "html", "css"]
instance1.showBooks(); // TypeError
/**
* 组合继承
* 优势:解决上面两种结构出现的问题
* 缺陷:使用构造函数继承时执行了一遍父类的构造函数,在实现子类原型的类式继承时又调用了一遍父类构造函数
*/
function SuperClass(name) {
this.name = name;
this.books = ["JavaScript", "html", "css"];
}
SuperClass.prototype.getName = function () {
console.log(this.name);
};
function SubClass(name, time) {
SuperClass.call(this, name); // 构造函数式继承 name 属性
this.time = time;
}
SubClass.prototype = new SuperClass(); // 类式继承
SubClass.prototype.getTime = function () {
console.log(this.time);
};
var instance1 = new SubClass("js book", 2014);
instance1.books.push("设计模式");
console.log(instance1.books); // ["JavaScript", "html", "css", "设计模式"]
instance1.getName(); // js book
instance1.getTime(); // 2014
var instance2 = new SubClass("css book", 2013);
console.log(instance1.books); // ["JavaScript", "html", "css"]
instance1.getName(); // css book
instance1.getTime(); // 2013
/**
* 原型式继承
* 跟类式继承一样,父类对象 book 中的值类型被复制,引用类型的属性被共用
*/
function inheritObject(o) {
// 声明一个过渡函数对象
function F() {}
// 过渡函数的原型继承父对象
F.prototype = o;
// 返回过渡对象的一个实例,该实例的原型继承了父对象
return new F();
}
var book = {
name: "js book",
alikeBook: ["css book", "html book"],
};
var newBook = inheritObject(book);
newBook.name = "ajax book";
newBook.alikeBook.push("xml book");
var otherBook = inheritObject(book);
otherBook.name = "flash book";
otherBook.alikeBook.push("as book");
console.log(newBook.name); // ajax book
console.log(newBook.alikeBook); // ['css book', 'html book', 'xml book', 'as book']
console.log(otherBook.name); // flash book
console.log(otherBook.alikeBook); // ['css book', 'html book', 'xml book', 'as book']
console.log(book.name); // js book
console.log(book.alikeBook); // ['css book', 'html book', 'xml book', 'as book']
/**
* 寄生式继承
*/
var book = {
name: "js book",
alikeBook: ["css book", "html book"],
};
function createBook(obj) {
// 通过原生继承方式创建新对象
var o = new inheritObject(obj);
// 拓展新对象
o.getName = function () {
console.log(name);
};
// 返回拓展后的新对象
return o;
}
/**
* 寄生组合式继承
* subClass 子类、superClass 父类
* 这里仅仅继承父类的原型,不再需要调用父类的构造函数
*/
function inheritPrototype(subClass, superClass) {
// 复制一份父类的原型副本保存在变量中
var p = inheritObject(superClass.prototype);
// 修正因为重写子类原型导致子类的 constructor 属性被修改
p.constructor = subClass;
// 设置子类的原型
subClass.prototype = p;
}
/**
* 测试代码
*/
// 定义父类
function SuperClass(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
// 定义父类原型方法
SuperClass.prototype.getName = function () {
console.log(this.name);
};
// 定义子类
function SubClass(name, time) {
// 构造函数式继承
SuperClass.call(this, name);
// 子类新增属性
this.time = time;
}
// 寄生式继承父类原型
inheritPrototype(SubClass, SuperClass);
// 子类新增原型方法
SubClass.prototype.getTime = function () {
console.log(this.time);
};
// 创建两个测试方法
var instance1 = new SubClass("js book", 2014);
var instance2 = new SubClass("css book", 2013);
instance1.colors.push("black");
console.log(instance1.colors); // ['red', 'blue', 'green', 'black']
console.log(instance2.colors); // ['red', 'blue', 'green']
instance2.getName(); // css book
instance2.getTime(); // 2013
/**
* 多继承
*/
// 下面是一个用来继承单对象属性的 extend 方法
// 单继承 属性复制
// 这个 extend 方法是一个浅复制过程,只能复制值类型的属性,对于引用类型的属性它无能为力。
var extend = function (target, source) {
// 遍历源对象中的属性
for (var property in source) {
// 将源对象中的属性复制到目标对象
target[property] = source[property];
}
// 返回目标对象
return target;
};
// 测试
var book = {
name: "JavaScript设计模式",
alike: ["css", "html", "JavaScript"],
};
var anotherBook = {
color: "blue",
};
extend(anotherBook, book);
console.log(anotherBook.name); // JavaScript设计模式
console.log(anotherBook.alike); // ['css', 'html', 'JavaScript']
anotherBook.alike.push("ajax");
anotherBook.name = "设计模式";
console.log(anotherBook.name); // 设计模式
console.log(anotherBook.alike); // ['css', 'html', 'JavaScript', 'ajax']
console.log(book.name); // JavaScript设计模式
console.log(book.alike); // ['css', 'html', 'JavaScript', 'ajax']
/**
* 多继承
* 同时对多个对象进行复制
*/
var mix = function () {
var i = 1, // 从第二个参数起为被继承的对象
len = arguments.length, // 获取参数长度
target = arguments[0], // 第一个对象为目标对象
arg;
// 遍历被继承对象
for (; i < len; i++) {
arg = arguments[i];
for (var property in arg) {
target[property] = arg[property];
}
}
return target;
};
/**
* 将上面的方法绑定到原生对象 Object 上,这样所有对象就可以拥有这个方法了
*/
Object.prototype.mix = function () {
var i = 0, // 从第二个参数起为被继承的对象
len = arguments.length, // 获取参数长度
arg;
// 遍历被继承对象
for (; i < len; i++) {
arg = arguments[i];
for (var property in arg) {
this[property] = arg[property];
}
}
return target;
};
/**
* 多态
* 就是同一个方法多种调用方式,根据传入的参数做区分
*/
function add() {
var arg = arguments,
len = arg.length;
switch (len) {
case 0:
return 10;
case 1:
return 10 + arg[0];
case 2:
return arg[0] + arg[1];
}
}
// 转换形式
function Add() {
function zero() {
return 10;
}
function one(num) {
return 10 + num;
}
function two(num1, num2) {
return num1 + num2;
}
this.add = function () {
var arg = arguments,
len = arg.length;
switch (len) {
case 0:
return zero();
case 1:
return one(zrg[0]);
case 2:
return two(arg[0], arg[1]);
}
};
}
var A = new Add();
A.add();
A.add(5);
A.add(6, 7);