面向对象的基础生活中常见使用面向对象的例子: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); // numberconsole.log(typeof b); // objectconsole.log(typeof c); // objectconsole.log(typeof f); // functionconsole.log(typeof undefined); // undefinedconsole.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); // trueconsole.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、getTitle2.设置列表的数据 setData、getData,一般有set,最好有个对应的get3.重新渲染数据 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); // testconsole.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. 弹出层选择后 ,频道名称变了
// 功能实现
