ES 6+ 面向对象
面向对象是一种通用思想,并非只有编程中能使用,任何事务都可以使用
- 唯一性:每个对象读有自身的唯一标识,通过这种标识,可以找到对应的对象
- 抽象性:就是指将具有一致的数据结果(属性)和行为(操作)的对象规程一类
- 继承性:是一种子类自动共享父类的数据结构和方法的机制,也是类之间的一种关系
- 多态性:是指作用在不同的对象中,使用相同的操作,却产生不同的结果
面向对象三大特性:抽象、封装、继承
var obj = { name: 'tom', age: 5 };
obj.say = function() {
console.log('miao! my name is ' + this.name + ', I\'m ' + this.age);
};
obj.say(); // "miao! my name is tom, I'm 5"
对象模板
JavaScript 是一种基于对象的语言,但它不是一种真正的面向对象编程语言,因为 JavaScript 中没有类,只能抽象生成类的创建,ES 6 以后就有类的概念
- 构造函数法:通过声明函数定义一个类,并使用 this 指向对象的属性和方法,通过构造函数引入这个类
- 创建对象法:通过声明对象定义一个类,并在对象中设置对象的属性和方法,通过 Object.create() 生成一个实例
- 极简主义法(推荐):通过声明对象定义一个类,并在对象中设置一个构造函数,用于生成实例,直接调用构造函数生成一个实例
function Cat() {
this.disc = '猫';
this.sound = function() {
return '喵!!!';
}
}
var tom = new Cat();
console.log('tom 是一只' + tom.disc + '它只会说:' + tom.sound()); // 'tom 是一只猫它只会说:喵!!!'
--------------------------------------------------------------------------------------------------------------------------------
var Cat = {
disc: '猫',
sound: function() {
return '喵!!!';
}
};
var jerry = Object.create(Cat);
console.log('jerry 是一只' + jerry.disc + '? 它会说:' + jerry.sound() + '?'); // "jerry 是一只猫? 它会说:喵!!!?"
--------------------------------------------------------------------------------------------------------------------------------
var Cat = {
newCat: function() {
var cat = {};
cat.disc = '猫';
cat.sound = function() {
return '喵!!!';
};
return cat;
}
};
var terry = Cat.newCat();
console.log('terry 是一只' + terry.disc + '它只会说:' + terry.sound()); // 'tom 是一只猫它只会说:喵!!!'
封装特性
封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的类或者对象进行信息隐藏
- 生成实例对象的原始模式:把对象的属性和方法看成是封装在对象内部的,外部需要通过对象才能进行属性和方法的访问
- 生成构造函数的改进模式:通过构造函数传值赋值给构造函数,外部表用需要通过实例化构造函数进行属性和方法的访问
-
- 声明的构造函数就是类,通过 new 构造函数产生实例是实例对象
-
- 构造函数中的 this 指向的是构造函数这个类,使用构造函数创建类建议函数名首字母大写
var Cat = {
name: '',
color: ''
};
Cat.name; Cat.name = 'tom';
--------------------------------------------------------------------------------------------------------------------------------
function Cat(name, color) {
this.name = name;
this.color = color;
}
var tom = new Cat('tom', 'blue');
tom.name; tom.color;
--------------------------------------------------------------------------------------------------------------------------------
function Cat(name, color) {
this.name = name;
this.color = color;
this.type = '猫科动物';
}
var tom = new Cat('tom', 'blue'); // 每次实例会造成内存浪费问题,可以通过原型机制改变引用类型地址指向
原型机制
每个构造函数都具有一个 prototype 属性,用于指向对象添加属性和方法,一般情况下属性放在构造函数内,方法通过原型生成,且可以共享出去,构造函数还有一个 __protp__ 原型链,用于指向实例化的函数原型
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
}
Person.prototype.say = function() {
console.log('hi');
};
var tom = new Person('tom', 'boy', 12);
var lily = new Person('lily', 'girl', 10);
tom.say(); // "hi"
lily.say(); // "hi"
--------------------------------------------------------------------------------------------------------------------------------
var Person = {
newPerson: function(name, age) {
var cat = {};
cat.name = name;
cat.age = age;
return cat;
}
};
var tom = Person.newPerson('tom', 12);
tom.say = function() {
console.log('My name is ' + this.name + ', i\'m ' + this.age);
};
tom.say(); // ”My name is tom, i'm 12“
--------------------------------------------------------------------------------------------------------------------------------
tom.__proto__ === Person.prototype; // true
原型验证
验证方法 | 方法说明 |
---|---|
isPrototypeOf() | 用来判断某个 prototype 对象和某个实例之间的关系 |
hasOwnProperty() | 用来判断某一个属性到底是本地属性还是继承自 prototype 对象的属性 |
in 运算符 | 用来判断某个属性是否是对象的属性,不管是不是本地属性或 prototype 对象的属性 |
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype.type = '猫科动物';
var tom = new Cat('tom', 'blue');
Cat.prototype.isPrototypeOf(tom); // true
tom.hasOwnProperty('name'); // true
tom.hasOwnProperty('type'); // false
('name' in tom); // true
('type' in tom); // true
/**
* 对 Date 的扩展,将 Date 转化为指定格式的 String 日期格式
* 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
* 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符
* @param {[Date]} this [需要转化格式的日期时间]
* @param {[String]} fmt [转化格式]
* @return {[String]} [返回转化后的格式化日期字符]
* new Date().format('yyyy-MM-dd hh:mm:ss.S') ==> 2020-07-22 21:54:08.58
* new Date().format('yyyy-M-d h:m:s.S') ==> 2020-7-22 21:54:8.58
*/
Date.prototype.format = function(fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
};
--------------------------------------------------------------------------------------------------------------------------------
/**
* 对 Date 的扩展,通过传递一个日期时间,根据调整模式判断调整对应模式的日期时间
* @param {[Date]} this [传递过来的参考日期时间]
* @param {[String]} mode [传过来的调整模式:M 月、d 天、h 时、m 分、s 秒]
* @param {[Number]} value [正数: 当前时间后时间,负数: 当前时间前时间]
* @return {[Date]} [返回处理后的日期时间]
* 得到当前系统时间 var now = new Date(); ==> Wed Jul 22 2020 22:10:30 GMT+0800 (中国标准时间)
* new Date().interval('d', -1); ==> Tue Jul 21 2020 22:10:25 GMT+0800 (中国标准时间)
*/
Date.prototype.interval = function (mode, value) {
switch(mode) {
case 'M': this.setMonth(this.getMonth() + value); break;
case 'd': this.setDate(this.getDate() + value); break;
case 'h': this.setHours(this.getHours() + value); break;
case 'm': this.setMinutes(this.getMinutes() + value); break;
case 's': this.setSeconds(this.getSeconds() + value); break;
}
return this;
};
继承特性
通过继承创建的新类称为”子类“或”派生类“,继承的整个过程就是从一般到特殊的过程。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function() {
console.log('My name is ' + this.name + ', i\'m ' + this.age);
}
function Man() {
this.sex = 'boy';
}
Man.prototype = Person.prototype; // 继承人的特征或属性
var tom = new Man();
tom.name = 'tom';
tom.age = 12;
tom.say(); // "My name is tom, i'm 12"
--------------------------------------------------------------------------------------------------------------------------------
var Animal = {
newAnimal: function() {
var animal = {};
animal.call = function(val) {
return '只会说: ' + val;
};
return animal;
}
};
var Cat = {
newCat: function() {
var cat = Animal.newAnimal();
cat.disc = '猫';
return cat;
}
};
var tom = Cat.newCat();
console.log('tom 是只' + tom.disc + tom.call('喵~')); // "tom 是只猫只会说: 喵~"
--------------------------------------------------------------------------------------------------------------------------------
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function() {
console.log('My name is ' + this.name + ', i\'m ' + this.age);
}
function Man(name, age) {
var man = new Person(name, age);
man.sex = 'boy';
return man;
}
var tom = new Man('tom', 12);
tom.say(); // ”My name is tom, i'm 12“
多态特性
对象的多功能、多方法,一个方法呈现多种表现形式,以下解析:同样是动物类,猫是喵叫,狗是汪汪叫
var Animal = {
newAnimal: function() {
var animal = {};
animal.call = function(_type) {
return '只会说: ' + (_type === 'cat' ? '喵~' : '汪汪~');
};
return animal;
}
};