javaScript 高级 含 ES6
2020年7月9日在es6中新增概念,可以用class关键字声明一个类,之后以这个类来实例化对象.
- 类 抽象了 对象 的公共部分,它泛指某一大类
- 对象特制某一个,通过类实例化一个具体的对象
- 先定义类在实例化
- 类里面的属性和方法必须加上this使用
- constructor 里面的this指向实例对象,方法里面的对象指向这个方法的调用者
创建类,new一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/** * 创建类 */ class Star { /** * 构造函数 不写系统也会自动生成 * @param userName */ constructor(userName) { this.userName = userName } /** * 类里面 所有方法不需要写function * 类里面 多个函数和方法之间不需要,分隔 */ sing(songTitle){ console.log(songTitle) } } // new一个对象 $star = new Star('刘德华'); $star.sing('冰雨') |
继承类
简单继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * 父类 */ class Father { /** * 构造函数 不写系统也会自动生成 * @param userName */ constructor() { } money(){ console.log('我有100块钱') } } class Son extends Father { } son = new Son(); son.money() |
继承时调用父类构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/** * 父类 */ class Father { /** * 构造函数 不写系统也会自动生成 * @param userName */ constructor(x, y) { this.x = x; this.y = y; } money() { console.log(this.x + this.y) } } /** * 子类 */ class Son extends Father { constructor(x,y) { /** * 因为 Father类constructor方法中的 this.x 和 this.y 和 Father类money方法中的 this.x 和 this.y 指向的是Father, * 就算Son继承也是Father 并且在这里写上 this.x = x; this.y = y; Son从Father中继承过来money方法中的 this.x 和 this.y * 还是 指向 Father , 除非使用super 调用父类上的函数,并给父类上的函数传参. * super不光可以用在constructor 构造方法上 还可以使用在普通方法上 * 在子类构造函数中 super 必须在子类的this之前 * 调用父类的构造函数 */ super(x,y); } } son = new Son(100,200); son.money() |
继承时调用父类普通方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * 父类 */ class Father { money() { console.log('我有100块') } } /** * 子类 */ class Son extends Father { money() { //super和PHP中的parent类似 super.money() //console.log('我有100000块') } } son = new Son(); son.money() |
面向对象实例(tab栏切换)
js代码 使用demo https://cloud.zfajax.com/index.php?share/file&user=102&sid=9EawRHC6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
var zfTabThis; class ZfTab { /** * 构造方法 */ constructor() { this.init() zfTabThis = this; } /** * 获取初始元素 */ init() { this.li = document.querySelectorAll('.fisrstnav li') //获取所有li标题 this.close = document.querySelectorAll('.fisrstnav li .icon-guanbi') //获取li下所有关闭按钮 this.content = document.querySelectorAll('.tabscon section') //获取li对应的内容展示 this.tabAdd = document.querySelector('.fisrstnav .tabadd') //获取添加按钮 this.ul = document.querySelector('.fisrstnav ul') //获取标题li 父类 ul this.contentDiv = document.querySelector('.tabscon') //获取content 父类 this.on() } /** * 绑定事件方法 */ on(){ this.tabAdd.onclick = this.createTab this.liNumber = this.li.length; for (var i = 0; i < this.li.length; i++) { this.li[i].setAttribute('data-index',i) this.content[i].setAttribute('data-index',i) this.li[i].onclick = this.switchTab this.li[i].ondblclick = this.updateTabTitle this.close[i].onclick = this.destroyTab this.content[i].ondblclick = this.updateTabContent } } /** * 切换tab的方法 */ switchTab() { for (var i = 0; i < zfTabThis.li.length; i++) { zfTabThis.li[i].className = ''; zfTabThis.content[i].className = ''; } this.className = 'liactive'; zfTabThis.content[this.getAttribute('data-index')].className = 'conactive' } /** * 创建tab的方法 */ createTab() { zfTabThis.liNumber++ var li = document.createElement('li') li.innerHTML = '<span>测试'+zfTabThis.liNumber+'</span><span class="iconfont icon-guanbi"></span>' li.setAttribute('data-index', zfTabThis.liNumber) zfTabThis.ul.appendChild(li) var section = document.createElement('section') section.innerHTML = '测试' + zfTabThis.liNumber section.setAttribute('data-index', zfTabThis.liNumber) zfTabThis.contentDiv.appendChild(section) zfTabThis.init() } /** * 删除tab的方法 */ destroyTab(e) { e.stopPropagation() var li = this.parentNode var dataIndex = li.getAttribute('data-index') zfTabThis.content[dataIndex].remove() li.remove() zfTabThis.init(); /** * 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变 */ if (document.querySelector('.fisrstnav .liactive')) { return; }else{ // 手动调用我们的点击事件 不需要鼠标触发 zfTabThis.li[dataIndex - 1] && zfTabThis.li[dataIndex - 1].click() ? '' : zfTabThis.li[dataIndex] && zfTabThis.li[dataIndex].click() } } /** * 更新tabTitle的方法 */ updateTabTitle() { // 双击禁止选定文字 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); var spanText = this.firstChild.innerHTML; //获取span文本 this.firstChild.innerHTML = '<input type="text" />'; //将内容改为表单 var input = this.firstChild.children[0]; //获取刚刚添加到DOM中的input input.value = spanText; //设置value值 input.select(); //让input默认选中 /** * 鼠标离开input 就赋值 */ input.onblur = function() { this.parentNode.innerHTML = this.value; }; /** * 按下回车赋值 * @param e */ input.onkeyup = function(e) { console.log(e) if (e.code === 'Enter') { // 手动调用表单失去焦点事件 不需要鼠标离开操作 this.blur(); } } } /** * 更新tabContent的方法 */ updateTabContent() { // 双击禁止选定文字 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); var spanText = this.innerHTML; //获取span文本 this.innerHTML = '<input type="text" />'; //将内容改为表单 var input = this.children[0]; //获取刚刚添加到DOM中的input input.value = spanText; //设置value值 input.select(); //让input默认选中 /** * 鼠标离开input 就赋值 */ input.onblur = function() { this.parentNode.innerHTML = this.value; }; /** * 按下回车赋值 * @param e */ input.onkeyup = function(e) { if (e.code === 'Enter') { // 手动调用表单失去焦点事件 不需要鼠标离开操作 this.blur(); } } } } |
构造函数 静态成员与实例成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function Star(userName, age) { this.age = age this.userName = userName this.sing = function () { console.log('老子要唱歌') } } Star.sex = '男' //给Star 构造方法添加一个静态成员 var ldh = new Star('刘德华',18) //实例化 console.log(ldh.age) //实例成员 实例成员只能通过实例化的对象来访问, age userName sing 都是 console.log(ldh.userName) //实例成员 ldh.sing() //实例成员 //console.log(ldh.sex) //静态成员只能通过构造函数 Star 函数来访问 console.log(Star.sex) //通过构造函数访问 sex 静态成员 //console.log(Star.age) //构造函数只能访问静态成员 |
构造函数原型对象(prototype)
- 构造函数虽然好,但是存在内存浪费的问题
- 构造函数通过该原型分配的函数是所有对象共享的
- JavaScript规定,每一个构造函数都有prototype属性,指向另一个对象,prototype就是一个对象,这个对象的所有属性和方法,都会被被构造函数所拥有
- 我们可以把那些不变的方法直接定义在prototype对象上,
- 原型是什么? 一个对象,我我们也成为prototype为原型对象(我称作构造原型)
- 原型的所用是什么? 共享方法
- 可以通过原型对象,对原来的内置对象进行自定义扩展,比如给Array添加sun方法
- 在构造函数中,里面的this指向的是对象实例ldh(刘德华),在原型对象函数里面的this指向的是 实例对象 ldh(刘德华)
prototype简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function Star(userName, age) { this.age = age this.userName = userName } /** * 把共享的方法和 属性放到prototype(构造函数原型)里 * 解决内存浪费问题 */ Star.prototype.sing = function () { console.log('老子要唱歌') } var zxy = new Star('张学友',19) var ldh = new Star('刘德华',18) console.log(zxy.sing === ldh.sing) |
给Array对象扩展方法sum
1 2 3 4 5 6 7 8 9 |
Array.prototype.sum = function () { var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i] } return sum; } var arr = [1, 2, 3] console.log(arr.sum()) |
对象原型 __proto__
对象都一个__proto__属性,指向构造函数的prototype原型对象(我叫作构造原型),之所以我们对象能使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__的存在,prototype 等价与 proto 因为指向一样
constructor 构造函数
- 对象原型 (__proto__) 和 构造函数(prototype) 原型对象里面都有一个constructor属性,constructor我们成为构造函数,因为他指回构函数本身.
- constructor主要用于记录该对象引用那个构造函数,他可以让原型对象重新指向原来的构造函数(var ldh = new Star(‘刘德华’,18))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function Star(userName, age) { this.age = age this.userName = userName } /** * 这里会使用constructor, 因为 直接给原型对象赋值一个对象, * 会把原先的对象覆盖掉,和单个添加方法不一样,所以要使用 * constructor 重新指向 */ Star.prototype = { constructor : Star, sex: '男', sing() { console.log('老子要唱歌') } } var zxy = new Star('张学友',19) var ldh = new Star('刘德华',18) console.log(zxy.sing === ldh.sing) |
构造函数 原型 对象 ,三者之间的关系
原型链
继承
es6之前并没有给我们提供extends继承.我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
var Fthis = null var Sthis = null /** * 父构造函数 * @param userName * @param age * @constructor */ function Father(userName, age) { Fthis = this this.userName = userName this.age = age } /** * 子构造函数 * @param userName * @param age * @constructor */ function Son(userName, age) { Sthis = this /** * 在子(Son)构造函数中,通过call的方式调用父(Father)构造函数,如果是用new 构造方法()的方式调用this指向的是window */ Father.call(this, userName, age) //使用call()的方式调用,改变指向, this 后的参数可以无限添加都是形参 console.log(Sthis === Fthis) //判断是否是一个this 可以删除 还有上面的Sthis Fthis变量 } /** * 通过构造函数实例化的方式,获取构造原型的方法, * 这样下次再给Son.prototype追加方法,也不会 * 影响到Father的构造原型,不可以构造原型等于构造原型 * X Son.prototype = Father.prototype * @type {Father} */ Son.prototype = new Father(); //给son原型赋值 Son.prototype.constructor = Son; //如果是用对象的方式修改了原型,别忘了利用constructor 指回来原来的构造函数 var son = new Son('刘德华', 18) |