js高级
一、类与对象
-
创建类
语法:class name{ //class body }
创建实例:
var xx = new name();
注意:类必须使用new实例化对象
-
类constructor构造函数
constructor()方法是类的构造函数(默认方法),用于传递参数,返回实力对象,通过new命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给我们创建一个constructor()
1、类的继承
-
继承
现实中的继承:子承父业,比如我们继承父亲的姓。
程序中的继承:子类可以继承父类的一写属性和方法。
语法:class Father{//父类 } class son extends Father{//子类继承父类 }
-
super关键字
**super()**用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数class Father { say(){ return"我是爸爸"; } } class son extends Father{//这样子类就继承了父类的属性和方法 say(){ //super.say() super调用父类方法 return super.say()+'的儿子'; //super.say() 就是调用父类中的普通函数say() } } var damao = new son(); console.log(damao.say());
class Person{ //父类 constructor (surname){ this.surname = surname; } } class Student extends Person{ //子类继承父类 constructor(surname,firstname){ super(surname); //调用父类的constructor(surname) this.firstname = firstname; //定义子类独有的属性 } }
继承中的属性或者方法查找原则:就近原则
注意:子类在构造函数中使用super,必须放到this前面(必须先调用父类的构造方法,再使用子类构造方法)
2、ES6中的类和对象
三个注意点:
- 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象。
- 类里面的共有属性和方法一定要加this使用
- constructor里面的this指向实例对象,方法里面的this指向这个方法的调用者
二、构造函数和原型
1. 构造函数
-
构造函数是一种特殊函数,主要用来初始化对象,即为对象成员变量赋初值,它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在js中使用构造函数时要注意一下两点:
1.构造函数创建某一类对象,其首字母要大写
2.构造函数要和new一起使用才有意义 -
js中的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加。通过这两种方式添加的成员,就分别称为静态成员和实例成员。
-
静态成员:在构造函数本身上添加的成元称为静态成员,只能由构造函数本身来访问
Star.sex='男' //静态成员
-
实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问。
function Star(uname,age){ this.uname=uname; //实例成员 this.age=age; //实例成员 this.sing=function(){ console.log("唱歌") } //实例成员 }
-
-
构造函数的问题
构造函数方法很好用,但是存在浪费内存的问题
在创建复杂数据类型(如:function方法),会单独开辟内存空间来存放这个方法,每创建一个实例对象都会开辟一个空间来存放同一个方法,非常浪费内存和时间 -
构造函数原型prototype
构造函数通过原型分配的函数时所有对象所共享的js规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有的对象实例就可以共享这些方法
Star.prototype.sing = function(){ console.log('唱歌'); //调用:对象实例.sing() }
-
对象的原型
__proto__
每一个对象都会有一个属性__proto__
指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__
原型的存在。-
__proto__
对象的原型和原型对象prototype是等价的(对象实例的__proto__
对象的原型指向构造函数的原型对象prototype) -
调用方法的查找规则:(以sing方法为例)首先看对象本身有没有sing方法,如果有,就执行对象自己本身的sing方法,如果对象本身没有sing这个方法,因为所有
__proto__
的存在,就去构造函数原型对象prototype身上去查找sing这个方法。
-
-
constructor构造函数
对象原型(__proto__
)和构造函数(prototype)原型对象里面都有一个constructor属性,constructor我们成为构造函数,因为它指回构造函数本身。constructor主要用于记录该对象引用于那个构造函数,它可以用让原型对象重新指向原来的构造函数,很多情况下,我们需要手动的利用constructor这个属性指回原来的构造函数(例如:我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数)
-
js的成员查找机制(规则)
- 当访问一个对象的属性(包括方法)时,首先查找对象自身有没有该属性。
- 如果没有就查找它的原型(也就是
__proto__
指向的prototype原型对象)。 - 如果还没有就查找原型对象的原型(Object原型对象)。
- 依次类推一直找到Object为止(null)。
__proto__
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
-
原型链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3W5pemOS-1584628577581)(C:\Users\李善炳\Desktop\原型链.png)] -
原型对象this指向
this指向函数调用者(对象实例) -
扩展内置对象
可以通过原型对象,对原来的内置对象进行自定义的方法。比如给数组增加自定义求偶数和的功能。
例:给Array扩展求和的方法Array.prototype.sum = function(){ var sum = 0; for(var i = 0; i < this.length; i++){ sun += this[i]; } }
**注意:**数组和字符串内置对象不能给原型对象覆盖操作
Array.prototype = {}
,只能是Array.prototype.xxx =function(){}
的方式
2. 继承
es6之前并没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承没被成为组合继承。
-
call()
可以调用函数(fun.call()
),并且修改函数运行时的this指向fun.call(thisArg, arg1, arg2, ...)
- thisArg:当前调用函数this的指向对象
- arg1, arg2:传递其他参数
-
借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性
function Father(uname, age){ //this指向父构造函数的对象实例 this.uname = uname, this.age = age, } function Son(uname, age, score){ //this指向子构造函数的对象实例 Father.call(this, uname, age); this.score = score; } var son = new Son('小明', 18, 100); console.log(son) //son实例中有uname,age,scpre属性,uname和age是从Father继承来的,score是自己独有的
-
借用原型对象继承方法
Son.prototype = Father.prototype //这样赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father(); //将父构造函数实例化赋值给子原型对象,但是这样Son.prototype.constructor就指向了Father构造函数。 Son.prototype.constructor = Son;//使Son原型对象的constructor指回原来的构造函数
3. 类的本质
- class本质还是function
- 类的所有方法都定义在类的prototype属性上
- 类创建的实例,里面也有
__proto__
指向类的原型对象 - 所以ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰,更像面向对象编程的语法而已
- 所以ES6的类其实就是语法糖
- 语法糖:语法糖就是一种改变些的写法,简单理解,有两种方法可以实现同样的功能,但是有一种写法更加清晰、方便,那么这个方法就是语法糖
三、ES5 中的新增方法
-
数组方法
迭代(遍历)方法:forEach()、map()、filter()、some()、every();-
forEach()
array.forEach(function(currentValue, index, arr){})
-
currentValue:数组当前项的值
-
index:数组当前项的索引
-
arr:数组对象本身
var arr = [1, 2, 3]; arr.forEach(function(currentValue, index, arr){ console.log(currentValue);//输出每个数组元素 console.log(index);//输出每个数组元素的索引号 console.log(arr);//输出这个数组 })
-
-
filter()
array.filter(function(currentValue, index, arr){})
- filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
- 注意:它直接返回一个新数组
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
例:
var arr = [12, 66, 88]; var newArry = arr.filter(function(value, index){ return value>20;//返回大于20的数组元素,组成一个新的数组 }); console.log(newArry);//输出由66和88组成的数组
-
some()
array.some(function(currentValue, index, arr){})
- some()方法用于检测数组中的元素是否满足指定条件,通俗点就是查找数组中是否有满足条件的元素
- 注意:他返回时布尔值,如果查找到这个元素就返回
true
,如果查找不到就返回false
- 如果找到第一个满足条件的元素,则终止循环,不再继续查找。
- currentValue:数组当前项的值
- index:数组当前项的索引
- arr:数组对象本身
例:
var arr=[10, 30, 4]; var flag = arr.some(function(value, index){ return value>20; }) console.log(flag);//输出true
-
-
字符串方法
trim()方法会从一个字符串的两端删除空白字符str.trim()
trim()并不影响元字符串本身,它返回的是一个新字符串
-
对象方法
-
Object.defineProperty()定义对象中新属性或修改原有的属性
Object.defineProperty(obj, prop, descriptor)
- obj:必需。目标对象
- prop:必需。需定义或修改的属性的名字
- descriptor:必需。目标属性所拥有的特性
Object.defineProperty()第三个参数descriptor说明:以对象形式{}书写- value:设置属性的值。默认为undefined
- writable:值是否可以重写。true|false 默认为false
- enumerble:目标属性是否可以被枚举。true|false 默认为false
- configurable:目标属性是否可以被删除或是否可以被再次修改特性true|false 默认为false
-
Object.keys()用于获取对象自身所有属性
Object.keys(obj)
- 效果类似 for…in
- 返回一个由属性名组成的数组
-
四、函数进阶
1. 函数的定义和调用
-
函数的定义
-
函数声明方式function关键字(命名函数)
-
函数表达式(匿名函数)
-
new Function(‘参数1’, ‘参数2’, ‘函数体’)
var fu = new Function('参数1', '参数2'..., '函数体')
Function里面参数都必须是字符串格式
- 第三种方式执行效率低,也不方便书写,因此较少使用
- 所有函数都是Function的实例对象
- 函数也属于对象
-
-
函数的调用
- 普通函数
- 对象的方法
- 构造函数
- 绑定事件的函数
- 定时器函数
- 立即执行函数
2. this
-
函数内this的指向
这些this的指向,是当我们调用函数的时候确定的,调用方式的不同决定了this的指向不同
一般指向函数的调用者调用方式 this指向 普通函数调用 window 构造函数调用 实例对象,原型对象里面的方法也指向实例对象 对象方法调用 该方法所属对象 事件绑定方法 绑定事件对象 定时器函数 window 立即执行函数 window -
改变函数内部this指向
js提供了一些函数方法帮助处理函数内部this的指向问题,常用的有bind()、call()、apply()方法。-
call方法
call方法调用一个对象。简单理解为调用函数的方式,但是他可以改变函数的this指向。fun.call(thisArg, arg1, arg2,...)
-
apply()方法
apply()方法调用一个函数。简单理解为调用函数的方式,但是它也可以改变函数的this指向fun.apply(thisArg, [argsArray])
-
thisArg:在fun函数运行时指定this的值
-
argsArray:传递的值,必须包含在数组里面
-
返回值就是函数的返回值,因为它就是调用函数
-
我们可以利用apply借助于数学内置对象求最大值最小值以前其他操作
var arr = [1, 66, 3, 99, 4]; var max = Math.max.apply(Math, arr); console.log(max)//输出99
-
-
bind()方法
bind()方法不会调用函数,但是能改变函数内部this指向fun.bind(thisArg, arg1, arg2, ...)
-
thisArg:在fun函数运行时指定this的值
-
arg1,arg2:传递其他参数
-
返回由指定this值和初始化参数改造的原函数拷贝
var o = { name:'andy' }; function fn(){ console.log(this); console.log(a + b); } var f = fn.bind(o, 1, 2);//使fn函数的this指向o对象 f();//调用函数
-
-
call、apply、bind总结
**相同点:**都可以改变函数内部this指向
区别:- call和apply会调用函数,并且改变函数内部this指向
- call和apply传递参数不一样,call传递参数arg1、arg2、…形式 appl必须数组形式[arg]
- bind不会调用函数,可以改变函数内部this指向
主要应用场景:
- call经常做继承
- apply经常跟数组有关系,比如借助数学对象实现求数组最大值最小值
- bind不调用函数,但还想改变this指向,比如改变定时器内部的this指向
-
五、严格模式
js除了提供正常模式外,还提供了严格模式(strict mode)。Es5的严格模式是采用具有限制性js变体的一种方式,即在严格条件下运行js代码。
严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
严格模式对正常的JavaScript语义做了一些更改:
- 消除了JavaScript语法的一些不合理、不严谨之处,减少了一些怪异行为。
- 消除源代码运行的一些不安全之处,保证代码运行的安全
- 提高编译器效率,增加运行速度
- 禁用了ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的JavaScript做好铺垫。比如一些保留字:class,enum,export,extends,super不能做变量名
1. 开启严格模式
严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式两种情况。
-
为脚本开启严格模式
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句“use strict”;或<script> 'use strict'; </script> //或 <script> (function(){ 'use strict'; })() </script>
因为“use strict”加了引号,所以老版本的浏览器会把它当做一行普通字符串忽略
-
为函数开启严格模式
给某个函数开启严格模式,需要把"use strict";(或’use strict’;)声明放在函数体所有语句之前。<script> function fn(){ 'use strict'; //该函数里面的代码按照严格模式执行 //该函数外的代码还是按照普通模式执行 } function fun(){ //该函数里面的代码按照普通模式执行 } </script>
2. 严格模式中的变化
严格模对JavaScript的的语法和行为,都做了一些改变。
- 变量规定
- 在正长模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种做法,变量都必须先用var命令声明,然后再使用。
- 严禁删除已声明变量。例如 delete x; 语法是错误的
- 严格模式下this指向问题
- 以前在全局作用域函数中的this指向windows对象。
- 严格模式下全局作用域中函数中的this是undefined。
- 以前构造函数不加new也可以调用,当普通函数,this指向全局对象
- 严格模式下,如果构造函数下不加new调用,this 指向的是undefined,如果使用则会报错
- new实例化的构造函数指向创建的对象实例
- 定时器this还是指向window
- 事件、对象还是指向调用者
- 函数变化
- 函数不能有重名的参数(形参)。
- 函数声明必须在顶层,新版本的JavaScript会引入“块级作用域”(ES6中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。
六、高阶函数
高阶函数是对其他函数进行操作的函数,他接收函数作为参数或将函数作为返回值输出。
<script>
function fn(callback){//接收函数做参数
callback && callback();
}
fn(function(){alert('hi');});
//此时fn为高阶函数
function fun(){
return function(){}//函数做返回值
}
fun();
//fn也为高阶函数
</script>
函数也是一种数据类型,同样可以作为参数,传递给另一个函数做参数使用。最典型的就是作为回调函数。
七、闭包
1. 变量作用域
变量根据作用域不同分为两种,全局变量和局部变量。
- 函数内部可以使用全局变量
- 函数外部不可以使用局部变量
- 当函数执行完毕,本作用域内的局部变量会销毁
2. 闭包
闭包(closure)是指有权访问另一个作用域中变量的函数
简单理解就是,一个作用域可以访问另一个函数内部的局部变量。
八、递归
如果一个函数内部可以调用起本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己,这个函数就是递归函数
由于递归很容易发生“栈溢出”(stack overflow)错误,所以必须要加退出条件return。
1. 浅拷贝与深拷贝
-
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
var o = {}; var obj = { id:1, name:'andy', msg:{ age:18, }//该对象属性只会被拷贝地址 }; for(var k in obj){ o[k] = obj[k]; }
Object.assign(o, obj);//将obj拷贝给o
-
深拷贝拷贝多层,每一级别的数据都会被拷贝
var o = {}; var obj = { id:1, name:'andy', msg:{ age:18, } } function deepCopy(newObj, oldObj){ for(var k in oldObj){ var item = oldObj[k]; if(item instanceof Array){ //判断这个值是否是数组 newObj[k] = []; deepCopy(newObj[k], item) }else if(item instanceof Object){ //判断这个值是否是对象 newObj[k] = {}; deepCopy(newObj[k], item) }else{ //这个值属于简单数据类型 newObj[k] = item; } } }
九、正则表达式
1. 正则表达式概述
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在JavaScript中正则表达式也是对象。
正则表达式通常用来检索、替换那些符合某个模式(规则)的文本,例如验证表单:用户名只能输入英文字母、数字或者下划线,昵称输入框中可以输入中文(匹配)。此外,正则表达式还常用语过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等。
正则表达式的特点:
- 灵活性、逻辑性和功能性非常的强。
- 可以地用极简单的方式达到字符串的复杂控制。
- 对于刚接触的人来说,比较晦涩难懂。
- 实际开发,一般都是直接复制写好的正则表达式,但是要求会使用正则表达式并且根据实际情况修改正则表达式。
2. 正则表达式在JavaScript中的使用
-
创建正则表达式
在JavaScript中,可以通过两种方式创建一个正则表达式。-
通过调用RegExp对象的构造函数创建
var 变量名 = new RegExp(/表达式/);
-
通过字面量创建
var 变量名 = /表达式/;
-
-
测试正则表达式 test
test() 正则对象方法,用于检测字符串是否符合该规则,该对象返回true或false,其参数是测试字符串。regxObj.test(str)
- regexObj 是写的正则表达式
- str 是待测试文本
- 就是检测str文本是否符合我们写的正则表达式的规范
3. 正则表达式中的特殊字符
-
正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/。其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如^、$、+等。 -
边界符
正则表达式中的边界符(位置符)用来提示字符所处位置,主要有两个字符边界符 说明 ^ 表示匹配行首的文本(以谁开始) $ 表示匹配行尾的文本(以谁结束) 如果^和$在一起,表示必须是精确匹配。
var rg = /abc/; console.log(rg.test('abc'));//返回true console.log(rg.test('abcd'));//返回true console.log(rg.test('aabcd'));//返回true var reg = /^abc/; console.log(reg.test('abc'));//返回true console.log(reg.test('abcd'));//返回true console.log(reg.test('aabcd'));//返回false var reg1 = /^abc$/; console.log(reg1.test('abc'));//返回true console.log(reg1.test('abcd'));//返回false console.log(reg1.test('aabcd'));//返回false console.log(reg1.test('abcabc'));//返回false
-
字符类
字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内-
字符组合:
/^[a-z0-9]$/
-
[-]
方括号内部范围符-
-
如果中括号里有
^
表示取反的意思
var rg = /[abc]/;//只要包含有a、b、c其中一个,都返回true var rg1 = /^[abc]$/;//三选一,只有是a、b、c其中一个的时候才返回true var rg2 = /^[a-z]$/;//多选一,26个中任何一个小写字母都返回true var rg3 = /^[a-zA-Z0-9_-]$/;//26个字母中任何一个字母、十个数字中的任何一个以及短横线、下划线,都返回true,仍然是多选一
-
-
量词符
量词符用来设定某个模式出现的次数。量词 说明 * 重复0次或更多次 + 重复一次或更多次 ? 重复零次或一次 {n} 重复n次 {n,} 重复n次或更多次 {n,m} 重复n到m次 -
括号总结
- 大括号 量词符 里面表示重复次数
- 中括号 字符集合。匹配方括号中的任意字符。
- 小括号表示优先级
-
预定义类
预定义类指的是某些常见模式的简写方式预定类 说明 \d 匹配0-9之间的任一数字,相当于 [0-9]
\D 匹配所有0-9以外的字符,相当于 [^0-9]
\w 匹配任意的字母、数字和下划线,相当于 [A-Za-z0-9_]
\W 除所有字母、数字和下划线以外的字符,相当于 [^A-Za-z0-9_]
\s 匹配空格(包括换行符、制表符、空格符等),相当于 [\t\r\n\v\f]
\S 匹配非空格的字符,相当于 [^\t\r\n\v\f]
4. 正则表达式中的替换
-
replace替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。stringObiect.replace(regexp/substr, replacement)
- 第一个参数:被替换的字符串或者正则表达式
- 第二个参数:替换为的字符串
- 返回值是一个替换完毕的新 字符串
-
正则表达式参数
/表达式/[switch] //例: /表达式/gi
switch(也称为修饰符)按照什么样的模式来匹配,有三种值:
- g:全局匹配
- i:忽略大小写
- gi:全局匹配,忽略大小写
十、ES6
ES6的全称是ECMAScript,它是由ECMA国际化标准组织制定的一项脚本语言的标准化规范。
1. let关键字
ES6中新增的用于声明变量的关键字
-
let声明的变量只在所处于的块级有效(一个大括号 )
if(true){ let a = 10; } console.log(a);//a is not defined
注意:使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用域特性
-
不存在变量提升(只能先声明再使用)
console.log(a);//a is not defined let a = 20;
-
暂时性死区
var tmp = 123; if(true) { tmp = 'abc';//tmp is not defined let tmp; }
2. const关键字
作用:声明常量,常量就是值(内存地址)不能变化的量
-
具有块级作用域
if(true) { const a = 10; } console.log(a); //a is not defined
-
声明常量是必须赋值
const PI; //missing initializer in const declaration
-
常量赋值后,值不能更改
const PI = 3.14; PI = 10;//Assignment to constant variable const arr = [100, 200]; arr[0] = 1; console.log(arr)//输出[1, 200]; arr = [1, 2]; console.log(arr);//Assignment to constant variable
3. let、const、var的区别
- 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。
- 使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升。
- 使用const声明的是常量,在后面出现的代码中不能再修改该常量的值。
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可更改 | 值可更改 | 值不可更改 |
4. ES6新增语法
-
解构赋值
ES6中允许从数组中提取值,按照对应位置,对应变量赋值。对象也可以实现解构。-
数组解构
数组解构允许我们按照一一对应的关系从数组中提取值然后将值赋值给变量let arr = [1, 2, 3]; let [a, b, c] = arr; console.log(a); console.log(b); console.log(c);
let [a, b, c] = [1, 2, 3]; console.log(a); console.log(b); console.log(c);
如果解构不成功,变量没有对应的值,则该变量为undefined。
let [foo] = []; console.log(foo);//输出undefined let [bar, f] = [1]; console.log(bar);//输出1 console.log(f);//输出undefined
-
对象解构
对象解构允许我们使用变量的名字匹配对象的属性 匹配成功将对象属性的值赋值给变量let person = { name:'张三', age:18 }; let {name, age} = person; console.log(name);// 张三 console.log(age);// 18 let{name:myname, age:myage} = person; //上面的语句相当于 //myname = person.name; //myage = person.age; console.log(myname);//张三 console.log(myage);//18
箭头函数
ES6中新增的定义函数的方式
箭头函数中没有arguments(形参1,形参2)=>{ //函数体 } const fn = ()=>{}
在箭头函数中,如果函数体中只有一句代码,并且代码的执行结果就是函数的返回值,函数体的大括号可以省略
const sum = (num1, num2) => num1 + num2; console.log(sum(10, 2));//输出12
在箭头函数中,如果形参只有一个,可以省略小括号
const result = n => n + 1; console.log(result(5));//输出6
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置中的this
const obj = { name:'张三' }; function fn(){ console.log(this); return () => { console.log(this); } } fun = fn.call(obj); fun();//两个输出都是obj对象
-
剩余参数(弥补箭头函数中没有arguments的不足)
剩余参数语法允许我们将一个不定数量的参数表示为一个数组function sum(first, ...args){//args前面加三个.代表剩余的实参由args接收,以数组形式存储 console.log(first);// 10 console.log(args);// [20, 30] } sum(10, 20, 30);
剩余参数和解构配合使用
let students = ['张三', '李四', '王五']; let [s1, ...s2] = students; console.log(s1);//输出'张三' console.log(s2);//输出['李四', '王五']
-
十一、ES6的内置对象扩展
1. Array的扩展方法
-
扩展运算符(展开语法)
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。let arr = [1, 2, 3]; ...arrl;//1, 2, 3 console.log(...arr); // 输出1 2 3 逗号被当做console.log的参数分隔符
扩展运算符可以应用于合并数组。
//方法一 let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; let arr3 = [...arr1, ...arr2]; console.log(arr3);//输出[1, 2, 3, 4, 5, 6] //方法二 let arr4 = arr1.push(...arr2); console.log(arr4);//输出[1, 2, 3, 4, 5, 6]
将类数组或可遍历对象转换为真正的数组
let divs = document.querySelectorAll('div');//获取页面中的所有div,以伪数组的形式存储 let arr = [...divs];//将伪数组转换为真正的数组
-
构造函数方法:Array.from()
将类数组或可遍历对象转换为真正的数组let arr = { '0':'a', '1':'b', '2':'c', length:3 }; let newArr = Array.from(arr);//['a', 'b', 'c']
方法还可以接受第二个参数,作用类似于map方法,用来对每个元素进行处理,将处理后的值放入返回的数组
let arr = { '0':1, '1':2, 'length':2 } let newArr = Array.from(arr, item => item * 2);//将每个数组元素乘2 console.log(newArr);//输出[2, 4]
-
实例方法:find()(接收一个函数做参数:查找条件)
用于找出第一个符合条件的数组成员,如果没有找到返回undefinedvar arr =[{ id:1, name:'张三' },{ id:2, name:'李四' }]; var newArr = arr.find(item => item.id==1); console.log(newArr);//输出{id:1, name:'张三'}
-
实例方法:findIndex()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1let arr = [1, 5, 6, 9]; let index = arr.findIndex(value => value>5); console.log(index);//输出2
-
实例方法:includes()
判断某个数组是否包含给定的值,返回布尔值[1, 2, 3].includes(3);//true [1, 2, 3].includes(4);//false
2. string 的扩展方法
-
模板字符串
ES6新增的创建字符串的方式,使用反引号定义let name = `amazing`;
模板字符串中可以解析变量。
let name = `张三`; let say = `你好,我叫${name}`; console.log(say);//输出:你好,我叫张三
模板字符串中可以换行
let result = { name:'张三', age:18, sex:'男' } let html = `<div> <span>${result.name}</span> <span>${result.age}</span> <span>${result.sex}</spam> </div>`;
模板字符串中可以调用函数
const say = function(){ return '即使遍体鳞伤,也要护你周全'; }; let print = `${say()},仅此而已`; console.log(print);//输出:即使遍体鳞伤,也要护你周全,仅此而已
-
实例方法:startsWith()和endsWith()
- startsWith():表示参数字符串是否在原字符串的头部,返回布尔值
- **endsWith():**表示参数字符串是否在原字符的尾部,返回布尔值
let str = 'Hellow world!'; str.startsWith('Hellow');//true str.endsWith('!');//true
-
实例方法:repeat() (参数为需要重复的次数)
repeat方法表示将原字符串重复n次,返回一个新字符串。'x'.repeat(3);///"xxx" 'hello'.repeat(2);//hellohello
3. Set数据结构
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值
Set本身是一个构造函数,用来生成Set数据结构。
const s = new Set();
Set函数可以接受一个数组作为参数,用来初始化。
const set = new Set([1, 2, 3, 3, 5]);
console.log(set);//{1, 2, 3, 5}
利用Set给数组去重。
let arr = [1, 1, 2, 4, 7, 4];
let set = new Set(arr);
let arr1 = [...set];
console.log(arr1);//输出数组:[1, 2, 4, 7]
实例方法:
- add(value):添加某个值,返回结构本身
- delete(value):删除某个值,返回一个布尔值,表示是否删除成功
- has(value):返回一个布尔值,表示是否为Set结构的成员
- clear():清除所有成员,没有返回值
const s = new Set();
s.add(1).add(2).add(3);//向Set结构中添加值
s.delete(2);//删除Set结构中的2值
s.has(1);//表示Set结构中是否含有1这个值,返回布尔值
s.clear();//将Set结构清空
遍历Set结构
Set结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作没有返回值。
let s = new Set(['a', 'b', 'c', 'd'])
s.forEach(value => console.log(value));//分别输出字符'a' 'b' 'c' 'd'