类与对象,继承,构造函数,原型,ES6语法,闭包等
1. 面向对象介绍 1.1. 面向对象OOP vs 面向过程POP 面向过程 preocess-oriented programming
分析出解决问题的步骤,函数一步步实现,使用时一个个调用
面向对象 object-oriented programming
事务分解为对象,对象分工完成
把大象放进冰箱
面向过程:打开冰箱 -> 放入大象 -> 关闭冰箱
面向对象: 冰箱.打开,大象.进去,冰箱.关闭
面向对象特性
:封装,继承,多态
1.2. 面向对象思维 面向对象更贴近实际生活,使用对象描述现实世界事物。
事物又分具体事物
和抽象事物
。泛指的手机和特指的这个手机
故可以:
抽取共用的属性和行为封装成一个模板 —> 类
对类进行实例化,获取类的对象
1.3. 对象 万物皆对象
对象是一个具体的事物,看得见摸得着的实物。一本书,一支笔…
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有事物都是对象。字符串,数值
对象由属性
和 方法
组成:
属性:事物的特征,在对象中用属性来表示 - 名词
方法:事物的行为,在对象中用方法来表示 - 动词
1.4. 类 ES6中,使用class关键字声明一个类
类是抽象了对象的公共部分,泛指某一大类
对象特指一个
类实例化一个具体的对象
1.5. 语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Person { constructor (name ){ this .uname = name; } sing (some ){ return this .uname +" sing " +some; } } var user = new Person ("John" );console .log (user.sing ("小星星" ));
2. 父类 调用父类方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Father { say ( ){ return 'Father' ; } } class Son extends Father { say ( ){ return super .say ()+"'s Son" ; } } var user = new Son ();console .log (user.say ());
3. this 类里面的共有属性和方法一定要加this
constructor里面的this指向实例对象,方法里面的this指向方法调用者
4. 案例:动态添加标签页 4.1. 源码 https://www.aliyundrive.com/s/LAXNHxbZAG6
4.2. html 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 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Tab切换</title > <link rel ="stylesheet" href ="css/style.css" > <link rel ="stylesheet" href ="css/tab.css" > <script src ="js/index.js" > </script > </head > <body > <main > <h4 > Js 面向对象 动态添加标签页 </h4 > <div class ="tabsbox" id ="tab" > <nav class ="firstnav" > <ul > <li class ="liactive" > <span > 测试1</span > <span class ="iconfont icon-guanbi" > </span > </li > <li > <span > 测试2</span > <span class ="iconfont icon-guanbi" > </span > </li > <li > <span > 测试3</span > <span class ="iconfont icon-guanbi" > </span > </li > </ul > <div class ="tabadd" > <span > +</span > </div > </nav > <div class ="tabscon" > <section class ="conactive" > 测试1</section > <section > 测试2</section > <section > 测试3</section > </div > </div > </main > </body > </html >
4.3. css tab.css
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 * { margin : 0 ; padding : 0 ; } ul li { list-style : none; } main { width : 960px ; height : 500px ; border-radius : 10px ; margin : 50px auto; } main h4 { height : 100px ; line-height : 100px ; text-align : center; } .tabsbox { width : 900px ; margin : 0 auto; height : 400px ; border : 1px solid lightsalmon; position : relative; } nav ul { overflow : hidden; } nav ul li { float : left; width : 100px ; height : 50px ; line-height : 50px ; text-align : center; border-right : 1px solid #ccc ; position : relative; cursor : pointer; } nav ul li .liactive { border-bottom : 2px solid #fff ; z-index : 9 ; } #tab input { width : 80% ; height : 60% ; } nav ul li span :last-child { position : absolute; user-select: none; font-size : 12px ; top : -18px ; right : 0 ; display : inline-block; height : 20px ; } .tabadd { position : absolute; top : 0 ; right : 0 ; } .tabadd span { display : block; width : 20px ; height : 20px ; line-height : 20px ; text-align : center; border : 1px solid #ccc ; float : right; margin : 10px ; user-select: none; } .tabscon { width : 100% ; height : 300px ; position : absolute; padding : 30px ; top : 50px ; left : 0px ; box-sizing : border-box; border-top : 1px solid #ccc ; } .tabscon section ,.tabscon section .conactive { display : none; width : 100% ; height : 100% ; } .tabscon section .conactive { display : block; }
4.4. js ondblclick
- 双击
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 window .addEventListener ("load" ,function ( ){ var obj; var tab; var nav; var content; var li; var section; var tabadd; class Tab { constructor (id ){ obj=this ; tab = document .querySelector (id); nav = tab.querySelector (".firstnav ul" ); content = tab.querySelector (".tabscon" ); tabadd = tab.querySelector (".firstnav .tabadd" ); this .init (); } upload ( ){ li = nav.querySelectorAll ("li" ); section = content.querySelectorAll ("section" ); } init ( ){ this .upload (); var len = li.length ; for ( var i = 0 ;i<len;i++){ li[i].onclick =this .toggle ; li[i].index = i; var removeBtn = li[i].querySelector (".iconfont" ); removeBtn.index =i; removeBtn.onclick =this .removeTab ; var span = li[i].querySelector ("span" ); span.ondblclick =this .editTab ; section[i].ondblclick =this .editTab ; } tabadd.onclick =this .addTab ; } toggle ( ){ var len = li.length ; for ( var i = 0 ;i<len;i++){ li[i].className ='' ; section[i].className ='' ; } this .className ='liactive' ; section[this .index ].className ='conactive' ; } addTab ( ){ var str = '<li class="liactive"><span>选项</span><span class="iconfont icon-guanbi"></span></li>' ; nav.insertAdjacentHTML ('beforeend' ,str); str = '<section class="conactive">选项' +Math .random ()+'</section>' ; content.insertAdjacentHTML ('beforeend' ,str); obj.init (); li[li.length -1 ].click (); } removeTab (e ){ e.stopPropagation (); var idx = this .index ; li[idx].remove (); section[idx].remove (); if (nav.querySelector (".liactive" )){ return false ; } idx--; if (idx>=0 ){ li[idx].click (); } obj.init (); } editTab (e ){ window .getSelection ? window .getSelection ().removeAllRanges ():document .selection .empty (); var str = this .innerText ; this .innerHTML ='<input type="text" value="">' ; var input = this .querySelector ("input" ); input.value = str; input.select (); input.onkeyup =function (e ){ if (e.keyCode ==13 ){ this .blur (); } } input.onblur = function ( ){ this .parentNode .innerHTML =this .value ; } } } new Tab ("#tab" ); });
5. 构造函数 ES5 ES6,全称ECMAScript6.0,2015.06发版。
浏览器JavaScript是ES5版本。高版本支持ES6,不过只实现其部分特性和功能
在ES6之前,对象基于构建函数来定义对象和它们的特征
5.1. 创建对象方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var obj = new Object ();obj = {}; function Star (name,age ){ this .name =name; this .age =age; this .sing =function ( ){ console .log (name+' ' +age+' sing' ); } } obj1 = new Star ("John" ,18 ); obj1.sing ();
5.2. 静态成员 在构造函数上添加的成员,只能由构造函数本身访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Star (name,age ){ this .name =name; this .age =age; this .sing =function ( ){ console .log (name+' ' +age+' sing' ); } } Star .num =1 ;obj1 = new Star ("John" ,18 ); console .log (obj1.num );console .log (Star .num );
5.3. 实例成员 构造函数内部创建的对象成员,只能由实例化对象访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Star (name,age ){ this .name =name; this .age =age; this .sing =function ( ){ console .log (name+' ' +age+' sing' ); } } obj1 = new Star ("John" ,18 ); console .log (obj1.age );console .log (Star .age );
5.4. 不同对象,不同内存 1 2 3 4 5 6 7 8 9 function Star (name,age ){ this .name =name; this .age =age; this .sing =function ( ){ console .log (name+' ' +age+' sing' ); } } console .log (obj1.sing ==obj2.sing );
5.5. 原型 prototype 构造函数通过原型分配的函数是所有对象所共享的
js规定,每一个构造函数都有一个prototype属性,指向另一个对象
prototype就是这个对象,对象中所有属性和方法,都会被构造函数拥有
console.dir(Star);
把不变的方法,直接定义在prototype对象上,实现实例共享
1 2 3 4 5 6 7 8 9 10 11 12 13 function Star (name,age ){ this .name =name; this .age =age; } Star .prototype .sing =function ( ){ console .log (name+' ' +age+' sing' ); } obj1 = new Star ("John" ,18 ); obj2 = new Star ("Amy" ,19 ); console .log (obj1.sing ==obj2.sing );
5.6. 对象原型 _proto_ 对象属性中都有一个_proto_
指向构造函数的prototype原型对象
所以对象可以使用构造函数原型对象的属性和方法
_proto_
和prototype
是等价的
_proto_
存在的意义是为对象的查找机制提供一个方向,但是它是非标准属性,实际开发中,不可以使用这个属性
5.7. 构造函数 constructor 对象原型和构造函数原型对象里面都有一个属性constructor,称其为构造函数,它指回构造函数本身
手动指回constructor
1 2 3 4 5 6 7 8 9 Star .prototype ={ constructor : Star , sing : function (name ){ console .log (name+' sing' ); }, movie : function ( ){ console .log ("movie" ); } };
5.8. 成员查找机制
访问一个对象的属性时,首先查找这个对象自身
有没有该属性
如果没有就查找原型,_proto_指向的prototype原型对象
如果还没有就查找原型对象的原型 Object
依次类推至null
_proto_
为对象成员查找机制提供一个方向
5.9. 利用原型对象扩展内置对象方法 原型对象this指向实例对象
可以把自定义方法写在原型对象中,调用方法
1 2 3 4 5 6 7 8 9 10 11 Array .prototype .sum = function ( ){ var sum = 0 ; for (var i=0 ;i<this .length ;i++) { sum = this [i]; } return sum; } var arr = new Array (11 ,22 ,33 );var ans = arr.sum ();console .log (ans);console .log (Array .prototype );
5.10. 改变this指向 5.10.1. call(对象,参数1,参数2,...) 调用函数并且修改函数运行时的this指向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function fn (a,b ){ console .log (this ); console .log (a+b); } fn ();fn.call (); var obj = {name :'obj' };fn.call (obj,1 ,2 );
5.10.2. apply(对象,[参数]) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fun.apply (thisArg,[argsArray]); function Father (uname,age ){ this .uname = uname; this .age = age; } function Son (uname,age ){ Father .apply (this ,[uname,age]); } var son = new Son ('John' ,18 );console .log (son);
应用:求数组最大值
1 2 3 var ans = Math .max .apply (Math ,[1 ,2 ,0 ,5 ,3 ]);console .log (ans);
5.10.3. bind(对象,参数1,参数2,...) 方法不会调用函数,但能改变函数内部this指向
1 2 3 4 5 6 7 8 var o = { name : 'John' }; function fn ( ){ console .log (this ); } var f = fn.bind (o);f ();
按钮
1 2 3 4 5 6 7 8 9 10 11 btn.addEventListener ("click" ,function ( ){ this .disabled =false ; setTimeout (function ( ){ this .disabled =true ; }.bind (this ),3000 ); })
5.11. 继承 构造函数+原型对象 模拟实现继承
5.11.1. 继承属性 - call 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Father (a,b ){ this .a =a; this .b =b; } function Son (a,b ){ Father .call (this ,a,b); } var obj = new Son (3 ,4 ); console .log (obj);
5.11.2. 继承方法 - prototype 采用实例化父构造器对象 Son.prototype = new Father();
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 function Father (a,b ){ this .a =a; this .b =b; } Father .prototype .sum =function ( ){ console .log (this .a +this .b ); } function Son (a,b ){ Father .call (this ,a,b); } Son .prototype = new Father ();Son .prototype .constructor =Son ;var obj = new Son (3 ,4 );obj.sum (); console .log (new Father (5 ,6 ));console .log (obj);
5.12. ES5新增方法 5.12.1. forEach() forEach()中return并不会终止遍历
1 2 3 4 5 6 array.forEach (function (currentValue,index,array ));
js
1 2 3 4 5 6 var arr = [1 ,21 ,322 ,4311 ];arr.forEach (function (value,idx,arr ){ console .log ("value " +value); console .log ("idx " +idx); console .log ("arr " +arr); });
5.12.2. map() 5.12.3. filter() 创建一个新数组,新数组中的元素通过检查指定数组中符合条件所有元素,用于筛选数组
1 array.filter (function (currentValue,index,array ));
js
1 2 3 4 5 6 7 8 var arr = [1 ,21 ,322 ,4311 ];var arrNew = arr.filter (function (value,idx,arr ){ return value>300 ; }); console .log (arr);console .log (arrNew);
5.12.4. some() 检测数组中的元素是否满足指定条件
返回值是布尔值,查找到该元素返回true,否则返回false
找到第一个满足条件的元素,终止循环,不再继续查找
1 array.some (function (currentValue,index,array ));
js
1 2 3 4 5 6 var arr = [1 ,21 ,322 ,4311 ];var flag = arr.some (function (value,idx,arr ){ return value>300 ; }); console .log (flag);
5.12.5. every() 5.12.6. trim() 从字符串两端删除空白符
并不影响原字符串,返回新的字符串
5.12.7. keys() 获取对象自身所有属性
返回属性名组成的数组
js
1 2 3 4 5 6 7 8 var obj = { name : 'A' , age : 18 } var arr = Object .keys (obj);arr.forEach (function (key ){ console .log (obj[key]); });
5.12.8. defineProperty() 定义对象中新属性或修改原有属性
1 2 3 4 5 6 Object .defineProperty (obj.prop ,descriptor);
descriptor
以对象{}书写
6. 函数 6.1. 函数定义方式 1 2 3 4 5 6 7 8 9 10 11 function fn ( ){}fn ();var fun = function ( ){}fun ();var func = new Function ('a' ,'b' ,'console.log(a+b)' );func (1 ,2 );
所有函数都是Function的实例
函数也属于对象
6.2. 函数调用方法 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 function fn ( ){}fn ();fn.call (); var obj = { say : function ( ){ } } obj.say (); function Star ( ){} new Star ();window .onclick =function ( ){} window .click ();var timer = setInterval (function ( ){},1000 );(function ( ){})();
6.3. 函数内部this指向
调用方式
this指向
普通函数
window
构造函数
实例对象,原型对象里面的方法也指向实例对象
对象方法
该方法所属对象
事件绑定方法
绑定事件对象
定时器函数
window
立即执行函数
window
7. 严格模式 JavaScript除了提供正常模式外,还提供严格模式。
ES5的严格模式是采用具有限制性
在IE10以上才会被支持
严格模式对正常的JavaScript语义做出的更改:
变量必须声明后使用
严禁删除已声明的变量
全局作用域中函数的this是undefined
构造函数不加new调用,this会报错
new实例化的构造函数指向创建的对象实例
定时器中的this还是指向window
函数参数不可能重名
禁用ECMAScript的未来版本中可能会定义的一些语法,为未来版本的JavaScript做好铺垫。
保留了class,enum,export,extends,import,super等保留字
严格模式可以应用到整个脚本或个别函数时中。因此使用时,将严格模式分为为脚本开启严格模式
和为函数开启严格模式
两者情况。
7.1. 为脚本开启严格模式 在所有语句之前放一个特定语句use strict
1 2 3 4 5 6 7 8 9 10 11 <script > 'use strict' ;</script > <script > (function ( ){ 'use script' ; })(); </script >
7.2. 为函数开启严格模式 1 2 3 4 5 6 7 8 9 10 11 <script > function fn ( ){ 'use script' ; } function fn2 ( ){ } </script >
8. 高阶函数 对其他函数进行操作的函数,接收函数作为参数或者将函数作为返回值输出
1 2 3 4 5 6 function fn (callback ){ callback&&callback (); } fn (function ( ){ alert ('hi' ); });
9. 闭包 有权访问另一个函数作用域中变量的函数
一个作用域可以访问另一个函数内部的局部变量,这个局部变量所在的函数称为闭包
延长了变量的作用范围
1 2 3 4 5 6 7 8 9 10 11 12 13 function fn ( ){ var num = 10 ; function fun ( ){ console .log (num); } return fun; } var f = fn ();f ();
10. 正则表达式 用于匹配字符串中字符组合的模式。
在JavaScript中也是对象
通常被用来检索,替换那些符合某个模式的文本:
验证表单(匹配
)
过滤页面内容中的一些敏感词(替换
)
从字符串中获取特定部分(提取
)
10.1. 创建正则表达式
通过RegExp对象的构造函数创建
1 var 变量名 = new RegExp (/表达式/ );
通过字面量创建
js
1 2 3 var rg = /123/ ;rg.test (123 );
10.2. 字符类 只要匹配其中一个就可以
1 2 3 4 5 6 var rg = /[abc]/ ;rg.test ('andy' ); rg.test ('dy' );
三选一:只有是a或者b或者c才返回true
1 2 3 4 var rg = /^[abc]$/ ;rg.test ('aa' );
26个英文字母任何一个字符:-表示范围
字母+数字
1 var rg= /^[a-zA-Z0-9]$/ ;
取反:不可以是字母或数字
1 var rg= /^[^a-zA-Z0-9]$/ ;
10.3. 量词
量词
说明
用法
*
重复零次或更多次
/^a*$/
+
重复一次或更多次
/^a+$/
?
重复零或一次
/^a?$/
{n}
重复n次
/^a{3}$/
{n,}
重复n次或更多次
/^a{3,}$/
{n,m}
重复n到m次
/^a{3,6}$/
10.4. 替换 1 2 var rg= /^[激情|感觉]$/ ;rg.replace (rg,'**' );
11. let ES6新增的用于声明变量的关键字
let声明的变量只在所处于的块级有效
不存在变量提升
1 2 3 4 5 if (true ){ console .log (num); let num = 5 ; }
声明的关键字具有暂时性死区,一旦在块级作用域使用let定义变量,这个变量就和块级进行了绑定,在当前这个区域使用变量必须先定义
1 2 3 4 5 6 var num = 10 ;if (true ){ console .log (num); let num = 5 ; }
12. const 声明常量,值定义后不能更改
声明的常量具有块级作用域
13. 解构赋值 按照一定模式,从数组中或对象中提取值,将提取出来的值赋值给另外的变量
1 2 3 4 let [a,b,c]=[1 ,2 ,3 ];console .log (a);console .log (b);console .log (c);
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let person = { name : 'A' , age : 18 }; let {name,age }=person;console .log (name);console .log (age);let {name :myName,age :myAge }=person;console .log (myName);console .log (myAge);
14. 箭头函数 箭头函数不绑定this
箭头函数没有自己的this关键字
如果在箭头函数中使用this,this关键字将指向箭头函数定义位置的this
1 2 3 4 5 6 7 8 9 10 11 12 function fn ( ){ console .log (this ); return ()=> { console .log (this ); } } const obj = {name : 'zhangsan' };var refun = fn.call (obj);refun ();
面试题
this关键字将指向箭头函数定义位置,对象没有作用域,故this指向全局作用域,window,而window中没有age,打印undefined
1 2 3 4 5 6 7 8 var obj = { age : 20 , say : ()={ alert (this .age ); } } obj.say ();