一,面向对象/过程
面向对象和面向过程:同一个问题,把大象装进冰箱里面
-
面向过程
- 打开冰箱
- 把大象装进去
- 关上冰箱门
-
面向对象
-
写一个大象类,有进去这个功能
-
写一个冰箱类,有打开个关闭两个功能
-
使用大象和冰箱的功能
面向对象是以对象类划分问题,而不是步骤
面向对象具有灵活性,代码可复用性,容易维护和开发的有点,适合多人合作的大项目
面向对象的特征:
- 封装性
- 继承性
- 多态性
-
1,创建类
-
创建一个类
class People { constructor (age) { // constructor是初始化函数,相当于 __init__(): this.age = age } }
-
利用new实例化一个对象
xyb = new People(20);
例子
class People { constructor(name, age) { this.name = name this.age = age } sing(song) { console.log(this.name + '唱了' + song); } } var xyb = new People('xyb', 20); xyb.sing('《今天》') var lyw = new People('lyw', 19) lyw.sing('《后来》')
2,类的继承
-
继承父类
class Father { money(song) { console.log('父亲的100块'); } } class Son extends Father {} var son = new Son(); son.money() // 子类继承父类的money方法
-
继承中的问题
class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends Father { constructor(x, y) { this.x = x; this.y = y; } } var father = new Father(10, 20); father.sum() var son = new Son(20, 30); son.sum() // 这里会报错,son继承父类的sum方法,但是重写了初始化构造函数 // 父类里面的sum的this.x和y指向的是父类里面的x和y // 我们实例的son传入的20和30是属于子类的值,所以sum用不了
- 如果一个类是继承的,并且继承父类的方法中有 this.属性 这样的属性调用,那么就得用 super 方法
-
解决继承中的问题
super()函数
class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends Father { constructor(x, y) { super(x, y); // 把x和y传入父类的构造函数,这样sum就能正常使用 } } var father = new Father(10, 20); father.sum() var son = new Son(20, 30); son.sum()
-
子类继承父类并扩展方法
class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends Father { constructor(x, y) { super(x, y); // 调用父类的构造函数必须写在第一行 // 这是为保证在子类可以访问父类对象之前要完成对父类对象的初始化 this.x = x; this.y = y; } subtract() { console.log(this.y - this.x); } } var son = new Son(10, 20); son.subtract() son.sum()
- 构造函数里面的 super 必须写在第一行,为的就是能够保证在子类可以访问父类对象之前要完成对父类对象的初始化
3,类里面的this指向
-
谁调用 this,this 就指向谁
var btn = document.querySelector('button'); console.log(btn); class People { constructor(name, age) { this.name = name; this.age = age; this.btn = btn; this.btn.onclick = this.getThis; } getThis() { console.log('返回的this: '); console.log(this); // 谁调用了this,this就指向谁 } } var xyb = new People('xyb', 20); xyb.getThis()
案例1:面向对象Tab栏切换
-
insertAdjacentHTML 将字符串转换成html元素到DOM中
语法
element.insertAdjacentHTML(position, text);
beforebegin
元素自身的前面。
afterbegin
插入元素内部的第一个子节点之前。
beforeend
插入元素内部的最后一个子节点之后。
afterend
元素自身的后面
-
var that; class Tab { constructor(id) { that = this; this.main = document.querySelector(id); this.add = this.main.querySelector('.add'); this.ul = this.main.querySelector('.tab-header ul'); this.tab_contant = this.main.querySelector('.tab-contant'); this.init(); } init() { this.updateNode() // init 初始化操作,页面加载时元素就绑定相对应的事件 this.add.addEventListener('click', this.addTab); for (var i = 0; i < this.lis.length; i++) { this.lis[i].index = i; this.lis[i].addEventListener('click', this.toggleTab); this.removes[i].addEventListener('click', this.removeTab); this.is[i].addEventListener('dblclick', this.editTab); this.sections[i].addEventListener('dblclick', this.editTab); } } // 获取所有的li和section updateNode() { this.lis = this.main.querySelectorAll('li'); this.sections = this.main.querySelectorAll('section'); this.removes = this.main.querySelectorAll('.tab-header ul li span'); this.is = this.main.querySelectorAll('.tab-header i'); } // 1. 具有切换功能 toggleTab() { that.clearClass() this.className = 'active'; that.sections[this.index].className = 'active'; } clearClass() { for (var i = 0; i < this.lis.length; i++) { this.lis[i].className = ''; this.sections[i].className = ''; } } // 2. 添加功能 addTab() { // 在添加新的标签之后,清除样式 that.clearClass() // (1) 创建li元素和section元素 var li = '<li class="active"><i>新建</i><span>-</span></li>'; var section = '<section class="active">新建</section>'; // (2) 把这两个元素追加到对应的父元素里面 that.ul.insertAdjacentHTML('beforeend', li); that.tab_contant.insertAdjacentHTML('beforeend', section) that.init() } // 3. 删除功能 removeTab(e) { e.stopPropagation() // 阻止删除按钮的点击事件冒泡 var index = this.parentNode.index; that.lis[index].remove(); that.sections[index].remove(); that.init(); // 删除元素之后,需要重新更新下init() // 当我们删除的不是选中状态的li的时候,原来选中状态的li保持不变 // 当我们删除了选中状态的li时,让前一个li处于选中状态 // 不用担心index的问题,因为每次删除之后,index都会帮我们重新赋值 if (that.main.querySelector('.active')) return; index--; // 手动帮我们点击按钮,不需要手动点击鼠标触发, that.lis[index] && that.lis[index].click(); } // 4. 修改功能 editTab() { var str = this.innerHTML; window.getSelection ? window.getSelection().removeAllRanges : document.getSelection.empty(); this.innerHTML = '<input type="text"/>'; // 双击的时候ipt里面的value为str的值 var ipt = this.children[0]; ipt.value = str; ipt.select(); // 默认选中ipt表单里面的值 // 当我们离开文本框时,就把ipt里面的值赋给span ipt.addEventListener('blur', function () { this.parentNode.innerHTML = ipt.value; }) // 按下回车也能赋值给span ipt.addEventListener('keyup', function (e) { if (e.keyCode == 13) { // 回车的时候让他自动执行blur的操作 this.blur(); } }) } } var tab1 = new Tab('#tab');