1.1 单例设计模式
单例模式:把描述事务的信息放到一个命名空间中进行分组归类,防止全局变量的污染。
let name = '和冉';
let age = 18;
let sex = '美女';
let name = '小璐璐';
let age = 81;
let sex = '看着办';
// => 把描述当前事务特征的信息进行分组归类(减少全局变量的污染)
// => 这就是JS中的单例设计模式
/*
* beautiGirl不仅仅被叫做变量(对象名),也被称为“命名空间”
* 单例模式:把描述事务的信息放到一个命名空间中进行分组归类,防止全局变量的污染
*/
let beautiGirl = {
name: '和冉',
age: 18
};
let oldMan = {
name: '小璐璐',
age: 81
};
为了让单例模式变的高大上一些,项目中的单例模式都这样处理:【使用闭包】
function fn() { }
let namespace = (function () {
// 创建一些方法(闭包中的私有方法)
let fn = function () {
// ....
};
// ...
return {
name: 'xxx',
fn: fn
}
})();
namespace.name
namespace.fn();
例如:完成一个需要团队协作开发的案例(百度首页)
/*
* 公共模块
*/
let utils = (function () {
let queryElement = function () {... }
return {
//queryElement: queryElement
queryElement
}
})();
/*
* XXX负责的页卡模块
*/
let pageTabModule = (function () {
// => 获取元素(调取其它命名空间下的方法)
let tabBox = utils.queryElement('.tabBox');
let show = function () {... }
...
return {
init: function () {
//调用自己模块下的方法
show();
}
}
})();
pageTabModule.init();
...
1.2 工厂模式
批量化生产:把实现某个功能的代码进行封装,后期在想实现这个功能,我们直接执行函数即可
- 低耦合:减少页面中冗余的代码
- 高内聚:提高代码的重复使用率
function createPerson(name, age) {
let person = {};
person.name = name;
person.age = age;
return person;
}
let beautyGirl = createPerson('和冉', 18);
let oldMan = createPerson('小璐璐', 81);
beautyGirl.name
oldMan.name
...
1.3 什么是面向对象
把抽象的“对象”,按照特点进行详细分类(大类/小类),把共同的东西进行抽取,放到对应的类别中。
=> “类”是对“对象”的一种细分,以及对公共部分的封装。
类别中派生出来的具体的事务叫做类的“实例”。
实例既有属于自己私有的东西,也有继承各个类别中的共有信息。
面向对象编程,其实就是掌握“对象”、“类”、“实例”之间的关系、知识。
例如:类的封装、继承、多态。
控制台中,用dir()函数查看,dir(tabBox),tabBox是元素id
1.4 构造函数
构造原型模式(正统面向对象编程)
自己能够创造出自定义类和对应实例,构建起一套完整的面向对象模型
/*
* new CreatePerson()执行和普通函数执行的区别
* 1.new这种执行方式叫做“构造函数执行模式”,此时的CreatePerson不仅仅是一个函数名,被称为“类”,而返回的结果(赋值给person1的)是一个对象,我们称之为“实例”,而函数体中出现的this都是这个实例
*/
function CreatePerson(name, age) {
this.name = name;
this.age = age;
}
// 普通函数执行模式
let zs = CreatePerson('张三', 25); // => 普通函数执行,this指向window,前面没有点
console.log(zs) // undefined,因为没有返回值
console.log(window.name, window.age) // 张三 25
// 构造函数执行模式
let person1 = new CreatePerson('和冉', 18);
console.log(person1) // CreatePerson {name: "和冉", age: 18}
手动修改构造函数中的this
function CreatePerson(name, age) {
// this => person1
this.name = name;
this.age = age;
// => 如果手动RETURN的是一个基本值,对返回的实例无影响。如果手动RETURN的是一个引用类型的值,会把默认返回的实例给替换掉(所以在构造函数模式执行下,我们一般都不要手动写RETURN,防止把返回的实例给替换)
// return 100; // => 返回的还是实例对象,不影响
/* return {
xxx: 'xxx'
}; */
}
let person1 = new CreatePerson('和冉', 18);
console.log(person1) // CreatePerson {name: "和冉", age: 18}
1.5 instanceof
instanceof:要求检测的实例必须是对象数据类型的,基本数据类型的实例是无法基于它检测出来的。【用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。】
/*
* instanceof:用来检测某个实例是否属于这个类
* 实例 instanceof 类,属于返回TRUE,不属于返回FALSE
* [局限性]
* 1.要求检测的实例必须是对象数据类型的,基本数据类型的实例是无法基于它检测出来的
*/
console.log(person1 instanceof CreatePerson); // => TRUE,上例的
let ary = [12, 23];
console.log(ary instanceof Array); // => TRUE
console.log(ary instanceof RegExp); // => FALSE
console.log(ary instanceof Object); // => TRUE
console.log(1 instanceof Number); // => FALSE ,因为 1不是对象类型
// --------------------------------
/*
* 基本数据类型在JS中的特殊性
* 1.一定是自己所属类的实例
* 2.但是不一定是对象数据类型的
*/
// 字面量创建方式(也是Number类的实例,也可以调取内置的公有方法)
let n = 10;
console.log(n.toFixed(2));
console.log(typeof n); // => "number"
// 构造函数创建模式(创建出来的实例是对象类型的)
let m = new Number("10");
console.log(m)
console.log(typeof m); // => "object"
console.log(m.toFixed(2)); // 10.00
1.6 构造函数中的局部变量以及new构造函数时不加括号
// 构造函数执行,因为也具备普通函数执行的特点,所以:
// 1.和实例有关系的操作一定是 this.xxx = xxx ,因为this是当前类创造出来的实例
// 2.私有变量和实例没有必然的联系
function Fn(n) {
let m = 10;
this.total = n + m;
this.say = function () {
console.log(this.total);
};
}
let f1 = new Fn(10);
let f2 = new Fn(20);
// => new的时候不论是否加小括号,都相当于把Fn执行了,也创建了对应的实例,只不过不加小括号是不能传递实参的(当前案例中的形参n=undefined)
let f3 = new Fn;
console.log(f1.m); // => undefined
console.log(f2.n); // => undefined
console.log(f1.total); // => 20
f2.say(); // => this指向f2,因为say执行前面有点, 输出30
console.log(f1 === f2); // => FALSE(因为是两个不同的实例对象,也就是不同的堆地址)
console.log(f3) // Fn {total: NaN, say: ƒ}