面向对象的基础生活中常见使用面向对象的例子:react、vue、组件、库
状态的问题,操作
对象 = 属性+方法
概念:
变量 - 属性、状态、数据
过程 - 方法、函数
类(class)
Date、String、Array…..
实例化、实例(instance)
使用 new 关键字
let oDate = new Date();
oDate就是一个实例
成员(member):
是统称,包括东西( 属性+方法 )
成员有:
实例成员:实例里面的成员
str.length、arr.push
类成员:
类里面的成员
Math.PI
实例成员和 类成员是不需要实例化
抽象:
第一个含义:
提取信息的过程,实现一系列功能的过程
第二种含义:
抽象类,并不能拿去用,它的作用提供一个公共的基类、父类,其他类都可以去继承他一些公共的方法
面向对象思想:
1.封装
目的为了让别人不能轻易去破坏你对象里面的属性和方法
保护对象里面的成员
数据的隐藏,必须通过方法修改
强制规定访问的权限
便于理解
2.继承
任何一个类可以不用从零写起,可以在原有类基础上做一些修改和添加,形成一个新的类
目的:
为了重用代码
无需去修改父类
多重继承:每个类可以有多个父类,js、java不支持,c++支持,会让结构比较混乱
抽象类:
3.多态
其实是一种抽象
简化问题
设计模式
前人的经验
每一个模式,可对应解决实际生活中的问题
重点是:如何设计一个对象,应该有哪些属性和方法
面向对象写法:
常见写法:
旧版本(es6前)
// ES5写法
// 即是构造函数 也是类
function A() {
this.name = 'summer';
this.age = 18;
}
// 需要额外的prototype 添加方法
A.prototype.show = function() {
console.log(this.name+','+this.age);
}
const a = new A();
a.show();
新版写法(es6后)
// 类
class B{
constructor(name, age) {
// 构造函数、构造器
this.name = name;
this.age = age;
}
show() {
console.log(this.name+','+this.age);
}
}
const b = new B('jack', 24);
const c = new B('lucy', 20);
b.show();
c.show();
类型检测
typeof
适合检测基本类型
number、boolean、string、function、object、undefined
instanceof
检测对象类型
检测实例的具体类型,对子级类型有反应、对父类类型也有也有反应
从继承来说,子类 >= 父类,子类包含父类的属性和方法
constructor
不常用
作用可以帮助返回实例的构造器,
精确类型判断,只包括子级、不包括父级
let a = 1;
let b = [1, 2];
let c = {a: 'ss'};
const f = () => {console.log('ddd');};
console.log(typeof a); // number
console.log(typeof b); // object
console.log(typeof c); // object
console.log(typeof f); // function
console.log(typeof undefined); // undefined
console.log('---------------------');
// 检测是哪种对象
console.log(b instanceof Array);
console.log(b.constructor);
console.log(c instanceof Object);
console.log(c.constructor);
console.log('---------------------');
class User extends Array{
}
let d = new User();
console.log(d instanceof Array); // true
console.log('-----------------');
let o = new Date();
console.log('o', o.constructor === Date); // ƒ Date()
// 如何判断节点类型
const div1 = document.getElementById('div1');
console.log(div1.constructor); // ƒ HTMLDivElement()
console.log(div1 instanceof HTMLDivElement); // true
设计一个类 思路
1.自上而下
功能:类需要哪些功能
方法,属性
编码
类不断修改
2.尽早定位
assert - throw new Error();
// 定义一个公用 断言函数,供类型检测时使用
function assert(reg, msg){
if(!reg) {
throw new Error(msg);
}
}
3.注意
属性不要直接暴露
渲染 - 不要重新渲染
/*
练习 设计一个简单的列表类
1.修改标题 setTitle、getTitle
2.设置列表的数据 setData、getData,一般有set,最好有个对应的get
3.重新渲染数据 render
*/
class HotList {
constructor(parent, title = '', data = []) {
// 参数 必须 类型检测
assert(parent, '必须有父级');
assert(typeof title === 'string', '标题必须为字符串');
assert(data instanceof Array, 'data必须为数组');
this.parent = parent;
// 问题1:直接把数据暴露在外面 后期优化
this.title = title;
// 数据类型检测
this.data = data;
}
setTitle(title){
this.title = title;
}
getTitle() {
return this.title;
}
setData(data){
this.data = data;
}
getData() {
return this.data;
}
// 目前需要手动渲染 后期优化
render() {
data.forEach(v => {
const div = document.createElement('div');
div.setAttribute('class', 'item');
div.innerHTML = `<div class='title'>${v.title}</div><div class='detail'>${v.detail}</div><div class="author">${v.author}</div>`;
parent.appendChild(div);
})
}
}
const parent = document.getElementById('hotList');
const data = [
{
title: '数据今生今世',
detail: '独家独家独家独家',
author: '定海村'
},
{
title: '节省时间',
detail: '的独家独家独家独家经典',
author: '大口袋'
},
{
title: '数据今生今世',
detail: '独家独家独家独家',
author: '定海村'
},
{
title: '节省时间',
detail: '的独家独家独家独家经典',
author: '大口袋'
}
];
const list = new HotList(parent, '热门新闻', data);
list.render();
原型 - prototype
1.作用
给类 添加/修改东西
这个类所有的实例都有这个东西
2.原理
实例需要某个东西(属性、方法),
首先从自己身上找,如果有直接用
如果没有 继续去类身上找
如果还没有 去父类身上找,直到找到为止,如果最终没找到 返回 undefined
const arr1 = ['1', '2'];
const arr2 = ['1', '2'];
arr1.a = 'test';
Array.prototype.a = 'abc';
console.log(arr1.a); // test
console.log(arr2.a); // abc
3.用途
给类添加方法
i. 添加公用的方法
let str = 'ahdhgagsaagdga';
String.prototype.countA = function() {
return this.match(/a/g).length;
}
console.log(str.countA());
<br /> ii. 修补系统的函数功能 - polyfill
// 例如,IE7不支持 map,自己重写
Array.prototype.map = function(cb) {
const result = [];
for(let i = 0; i < this.length; i++) {
result.push(cb(this[i], i));
}
return result;
}
let arr = [1, 2, 3];
let arr2 = arr.map((v,i) => v*3);
console.log(arr2);
课后作业
数组做 polyfill
filter
// 功能实现
// 功能编写顺序要写在调用他 之前
Array.prototype.filter = function(cb) {
const result = [];
for(let i = 0; i < this.length; i++) {
if(cb(this[i], i)) {
result.push(this[i]);
}
}
return result;
}
const a = [1, 3, 5, 8, 2, 7, 10, 56, 39];
// 过滤出偶数
const b = a.filter((v, i) => v%2 === 0); // [8, 2, 10, 56]
reduce
// 功能实现
Array.prototype.reduce = function(cb, accumulator) {
// 如果没有提供 初始值,则 collection(集合)中的第一个元素作为初始值
if(this.length === 0) return;
let result, i;
if(accumulator === undefined) {
result = this[0];
i = 1;
} else {
result = accumulator;
i = 0;
}
while(i < this.length) {
result = cb(result, this[i]);
i++;
}
return result;
}
const a = [1, 6, 2, 3, 3, 2];
// reduce 求数组和
console.log(a.reduce((prev, cur, index, arr) => prev + cur)); // 17
// reduce 求数组最大值
console.log(a.reduce((prev, cur, index, arr) => prev > cur ? prev : cur)); // 6
// reduce 数组去重
console.log(a.reduce((prev, cur, index, arr) => {
prev.indexOf(cur) === -1 && prev.push(cur);
return prev;
}, []));
// [1, 6, 2, 3]
Array.from
用于将两类对象转为真正的数组
类似数组的对象(array-like object)和可遍历(iterable)的对象
// 功能实现
Array.from = function(arrayLike) {
const result = [];
if(typeof arrayLike.length === 'number') {
for(let i = 0; i < arrayLike.length; i++) {
result.push(arrayLike[i]);
}
}
return result;
}
console.log(Array.from('hello')); // ["h", "e", "l", "l", "o"]
const arraylike = {
'0': 'jsjs',
'1': 'dk',
'2': 'uhdhd',
length: 3
};
console.log(Array.from(arraylike)); // ["jsjs", "dk", "uhdhd"]
String.trim()
// 功能实现
String.prototype.trim = function() {
let newStr = '';
let startIndex, endIndex;
for(let m = 0; m < this.length; m++) {
if(this.charAt(m) !== " "){
startIndex = m;
break;
}
}
for(let n = this.length - 1; n > 0; n--) {
if(this.charAt(n) !== " "){
endIndex = n;
break;
}
}
console.log(startIndex, endIndex);
for(let i = startIndex; i <= endIndex; i++) {
newStr = newStr+this.charAt(i);
}
return newStr;
}
// 正则实现
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
3.豆瓣弹出层,选择频道
i. 点击频道名称,豆瓣弹出层
ii. 点击页面任意位置,弹出层消失
iii. 弹出层中的数据需要是动态的
iv. 弹出层选择后 ,频道名称变了
// 功能实现