一、面向对象
面向对象是一种注重结果的思维方式
面向过程:注重的是过程
面向对象:注重的是结果—本质是面向过程的封装
1.面向对象编程
别人写好的对象 : 好处: 效率高 坏处: 维护不便
自己写的对象 : 好处:维护方便 坏处:效率低
<div>div1</div><div>div2</div><div>div3</div><p>我是p1</p><p>我是p2</p><p>我是p3</p><p>我是p4</p><script>let zxkObj = {setColor:function (arr,color){for(let i = 0;i<arr.length;i++){arr[i].style.color = color}},setBorder:function (arr,border){for(let i = 0;i<arr.length;i++){arr[i].style.border = border}}}//1.获取元素let divList = document.querySelectorAll('div')let pList = document.querySelectorAll('p')//2.循环遍历元素zxkObj.setColor(divList,'red')zxkObj.setBorder(divList,'5px solid yellow')zxkObj.setColor(pList,'green')zxkObj.setBorder(pList,'5px solid pink')</script>
2.内置对象api
内置对象api : js作者写好的对象的一些方法 内置对象 : js作者提前写好的对象,直接拿来使用即可 api : 是预先定义的函数
2.1数组对象api
<script>/*数组增删改查push() : 在数组末尾 新增元素unshift() : 在数组开头 新增元素pop() : 在数组末尾 删除元素shift() : 在数开头 删除元素*/let arr = [20, 40, 60, 30, 50, 70, 100]console.log(arr)//1.arr.join('分隔符') 拼接成字符串let str = arr.join('|')console.log(str)//2.arr.reverse() 翻转数组arr.reverse()console.log(arr)//3.arr.sort() 数组排序 回调函数arr.sort(function (a, b) {//return a - b //小到大[20, 30, 40, 50, 60, 70, 100]return b - a //大到小 [100, 70, 60, 50, 40, 30, 20]})console.log(arr)</script>
2.1字符串对象api
<script>let str = '再也没有留恋的斜阳'//1.字符串也有下标console.log(str[str.length - 1])/* 2.str.indexOf() : 返回某个指定字符首字符的下标位置应用:检查字符串中是否有某个字符返回值如果有,则返回对应字符的首字符的下标如果没有则返回 -1*/console.log(str.indexOf('斜阳')) //7console.log(str.indexOf('你好')) //-1/*3.str.split('分隔符') 切割字符串 返回的一定是数组*/let str1 = '黄雅兰&🐖'console.log(str1.split('&'))//4.str.substr(其实下标,截取长度) 截取部分字符串console.log(str1.substr(1, 2))//5.大小写转换console.log('abcdefgHIJKLMN'.toLocaleLowerCase()) //转小写abcdefghijklmnconsole.log('abcdefgHIJKLMN'.toLocaleUpperCase()) //转大写ABCDEFGHIJKLMNconsole.log('沉默是金'.toLocaleUpperCase()) //汉字返回的是本身 沉默是金</script>
3.原型对象
1.面向对象 : 是一种注重结果的思维方式
2.面向对象与面向过程关系 : 面向对象基于面向过程的封装
面向对象:注重结果
面向过程:过程
3.构造函数创建对象(new关键字四个流程)
a.创建一个空对象
b.this指向这个对象
c.对象赋值
d.返回这个对象
4.原型对象 : 函数在声明的时候,系统会自动创建与之对应的对象。 原型对象
作用:解决资源浪费+变量污染
使用:
构造函数.prototype
实例对象可以直接用原型成员
5.构造函数、原型对象、实例对象三角关系
1. prototype : 属于构造函数,指向原型对象
作用:解决资源浪费+变量污染
2.proto : 属于实例对象,指向原型对象
作用: 可以让实例对象访问原型中的成员
3.constructor: 属于原型对象,指向构造函数
* 作用: 可以让实例对象 知道自己被哪一个构造函数创建的
//1.构造函数function Person(name,age){this.name = namethis.age = age}//2.原型对象Person.prototype.eat = function(){console.log('我要吃东西')}console.log( Person.prototype.constructor )//Person//3.实例对象let p1 = new Person('ikun',30)console.log( p1 )//查看p1的构造函数console.log( p1.constructor )//p1.__proto__.constructor/*__proto__ : 属于实例对象,指向原型对象__proto__属性不是web标准属性,在浏览器看不见。但是代码可以用。 实际开发中一定要省略__proto__.*/p1.eat()//底层 p1.__proto__.eat()//检测构造函数、原型对象、实例对象三者之间关系: 两行代码console.log( p1.__proto__.constructor === Person )//true (你爹是你爹)console.log( p1.__proto__ === Person.prototype )//true (你妈是你妈)
3.1工厂函数
用于创建多个对象的函数
<script>/* 解决代码冗余方案:封装函数工厂函数 : 用于创建多个对象的函数*/function createPerson(name,age){//1.声明对象let p = {}//2.对象赋值p.name = namep.age = age//3.返回值return p}let p1 = createPerson('ikun',30)let p2 = createPerson('班长',20)let p3 = createPerson('班主任',40)console.log(p1,p2,p3)</script>
3.2构造函数
js中,所有的对象都是由构造函数创建创建
{}:new Object 内置对象函数
自定义构造函数
new关键字工作原理
1.创建空对象
2.this指向这个创建的空对象
3.给对象赋值
4.返回这个对象
5.构造函数首字母大写;提醒不要忘记new关键字
6.如果构造函数主动写return
如果返回的是值类型 ,无效
如果返回的是引用数据类型,会覆盖new创建的对象
<script>function Iphone(price, color) {//1.创建一个空对象//2.this指向空对象//3.给对象新增属性this.price = pricethis.color = color//4.返回这个对象 return this}let phone = new Iphone(8888, 'red')let phone2 = new Iphone(666, 'black')//5.构造函数首字母大写;提醒不要忘记new关键字//6.如果构造函数主动写return// 如果返回的是值类型 ,无效// 如果返回的是引用数据类型,会覆盖new创建的对象console.log(phone, phone2)</script>
3.3静态成员与实例成员
4.面向对象三大特征
封装 继承 多态
1.封装 :把代码放到对象中的方法
2.继承 :一个对象有另一个对象的所有的成员
继承的三种方式:
混入式:遍历父对象的成员,添加给子对象
应用场景:适用于单个对象继承
弊端:没继承一次,就要执行一次循环
替换原型:父对象 作为子对象构造函数原型
应用场景:给内置构造函数添加方法
弊端:会覆盖原先的原型
混合式:混入+替换原型.遍历父对象的成员,添加到子对象的构造函数
3.多态 : 一个对象在不同情况下的不同状态
4.1混入式继承
遍历父对象的成员,添加给子对象
let father = {house : {address:'武汉天地',price : 10000000},car:{brand:'劳斯莱斯幻影',price:8000000}}//子对象let son = {name:'爽哥',age:20}/*混入式继承 : 遍历父对象成员,添加给子对象特点: 单个对象继承*/for(let key in father){son[key] = father[key]}console.log( son )
4.2替换原型
替换原型:父对象 作为子对象构造函数原型
//父对象let father = {house : {address:'武汉天地',price : 10000000},car:{brand:'劳斯莱斯幻影',price:8000000}}//子对象构造函数function Son(name,age){this.name = namethis.age = age}//把父对象 赋值给子对象的原型Son.prototype = fatherlet son1 = new Son('爽哥',20)let son2 = new Son('ikun',30)console.log(son1,son2)
4.3混合式继承
混入+替换原型.遍历父对象的成员,添加到子对象的构造函数原型
//父对象let father = {house : {address:'武汉天地',price : 10000000},car:{brand:'劳斯莱斯幻影',price:8000000}}//子对象构造函数function Son(name,age){this.name = namethis.age = age}//遍历父对象成员for(let key in father){//添加到子对象的构造函数原型里Person.prototype[key] = father[key]}let zi = new Person('刘德华', 17)
5.原型链
5.1原型链
1.原型链:每一个实例对象都有自己的原型,原型也是对象,也有自己的原型,以此类推,
形成链式结构,称之为原型链
2.原型链访问规则:就近原则
3.原型链的作用:继承
//构造函数 : 创建对象function Person(name,age){this.name = namethis.age = age}//原型对象添加方法Person.prototype.eat = function(){console.log('吃东西')}//给原型对象添加属性Person.prototype.type = '哺乳动物'Person.prototype.name = '中国人'//实例对象let p1 = new Person('陈爽',20)let p2 = new Person('ikun',30)console.log(p1,p2)/* 请说出下列代码运行结果 */console.log( p1.name )//陈爽 p1自己有nameconsole.log( p1.type )//哺乳动物 p1没有type,但是p1的原型有p1.eat()//'吃东西' p1自己没有eat,但是原型有// p1.learn()//报错//为什么p1没有toString,p1的原型也没有toString,但是不报错//原因: p1的原型的原型有toString()p1.toString()//查看p1的原型的原型console.log( p1.__proto__.__proto__.constructor )//Object 内置构造函数console.log( p1.__proto__.__proto__ === Object.prototype )//true//查看p1的原型的原型的原型console.log( p1.__proto__.__proto__.__proto__ )//null
5.2内置对象原型链
//数组实例对象let arr = [10,20,30]// new Array(10,20,30)//1.查看数组的原型 : 2行代码console.log( arr.__proto__.constructor )//Arrayconsole.log( arr.__proto__ === Array.prototype )//true//2.查看数组的原型的原型console.log( arr.__proto__.__proto__.constructor )//Objectconsole.log( arr.__proto__.__proto__ === Object.prototype )//true//字符串实例let str = 'abc'// new String('abc')//查看str的原型console.log( str.__proto__.constructor )//Stringconsole.log( str.__proto__ === String.prototype )//true\//2.查看数组的原型的原型console.log( str.__proto__.__proto__.constructor )//Objectconsole.log( str.__proto__.__proto__ === Object.prototype )//true
5.3DOM对象原型链
5.4 instanceof运算符作用
<script>/*instanceof关键字(运算符) : 检测 构造函数的原型 在不在 实例对象的原型链中实例对象 instanceof 构造函数在:true不在:falseinstanceof运算符作用 : 限制函数的参数数据类型*///数组实例对象// arr->Array.prototype->Object.prototype->nulllet arr = [10,20,30]console.log( arr instanceof Array )//trueconsole.log( arr instanceof Object )//trueconsole.log( arr instanceof String )//false//报错: 参数不是节点//instanceof关键字一般用在函数中,用于限制参数的数据类型//例如 appendChild()参数只能是node节点,如果你传了其他类型就会报错。底层就会用到instanceof来检测参数数据类型let h1 = document.createElement('h1')h1.innerText = '我是h1标签'document.body.appendChild(h1)</script>
5.5 ES6类继承
<script>/*1.class关键字 : 声明类函数 (构造函数)* 语法:class 类函数名{//构造函数constructor(){}//原型方法eat(){}}* 特点: class类函数必须要用new关键字,否则代码报错2.extends关键字 : 类继承* 语法:class 子类函数 extends 父类函数{}3. super关键字 : 子类调用父类方法* 应用场景: 写在子类的constructor方法中* 语法 :class 子类函数 extends 父类函数{//子类构造函数constructor(name,age,score){super(name,age)this.score = score}//子类原型方法learn(){}}*///父类函数:Personclass Person{//构造函数constructor(name,age){this.name = namethis.age = age}//原型方法sayHi(){console.log('i love you')}}//子类函数:teacherclass Teacher extends Person{//构造函数constructor(name,age,className){//父类方法super(name,age)this.className = className}//子类原型learn(){console.log('一日为师终身为友')}}let t1 = new Teacher('ikun',30,'71期')console.log(t1)</script>
5.6 函数补充
/*1.函数中的关键字: arguments作用:arguments:获取函数所有的实参(伪数组)场景: 例如 arr.push() 底层就是用arguments获取实参2.rest参数(剩余参数) : ...形参名作用:获取所有的剩余参数(真数组)场景: 绝大多数情况下,剩余参数可以替代arguments*/function fn(...b){console.log(b)//获取所有的剩余参数console.log( arguments )//获取函数所有实参}fn(10,20,30,40,50)/* 函数默认参数1.函数传参本质是:实参给形参赋值2.函数形参和实参数量可以不一致,但是会按照顺序一一赋值3.函数默认参数:ES5 : 逻辑 或 中断ES6 : 形参 = 默认值*/function fn(a=10,b=20){//找真 : 左边为真,返回左边的值。反之返回右边的值// a = a || 10// b = b || 20console.log(a)//5console.log(b)//20}fn(5)//底层 fn(5,undefined)
二、函数进阶
1.this三种指向
/*1.this环境对象 : 谁‘调用’我,我就指向谁 (相当于中文‘我’,谁说出这个字,这个字就代表谁)* 重点: 与函数声明无关,取决于函数调用* (1)普通函数调用: 函数名() -> this指向window* (2)对象方法调用: 对象名.方法名() -> this指向这个对象* (3)构造函数调用: new 函数名() -> this指向new创建的实例对象2.分析this指向心得 : this指向取决于函数调用,而函数有三种调用方式。所以this指向也会有三种情况(1)优先用排除法分析, 如果有new关键字,则指向new创建的对象。 否则不是window就是对象(2)如何判断this是window还是对象,就看调用是: 函数名() 还是 对象名.方法名()*/function fn(){console.log( this )}//1.普通函数fn()//windowlet obj = {name:'ikun',age:30,eat:fn,sayHi:function(){function fn1(){//这里this指向window, this指向取决于调用console.log( this )//}fn1()}}obj.sayHi()//2.对象方法obj.eat()//3.构造函数new fn()
2.函数上下文调用
1.默认情况下,this指向是无法修改的。
普通函数:函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数: new 函数名() this指向new创建的对象
2.上下文调用 : 修改函数中this指向
(1)函数名.call(修改的this,参数1,参数2,….)
(2)函数名.apply(修改的this, 数组/伪数组 )
(3)函数名.bind(修改this)
bind不会立即执行函数,而是得到一个修改this之后的新函数(一次修改,终生受用)
细节: 如果你在bind后面传了函数参数,那么参数也会绑定。之后传参无效
3.经典面试题:请说说call、apply、bind有什么异同点
相同点:都是修改函数中this指向
不同点:
3.1 传参方式不同 : call是一一传参,apply是数组/伪数组传参
3.2 执行机制不同 : call、apply会立即执行函数, bind不会立即执行函数,会返回一个新的函数
2.1 call上下文调用
函数名.call(修改的this,参数1,参数2,….)
function fn(a,b){console.log( this )console.log(a+b)}fn(1,2)//this指向window//函数名.call(修改的this,参数1,参数2,....)fn.call({name:'张三'},10,20)//--------应用场景:检测数据类型// 修改this,检测数据的数据类型console.log(Object.prototype.toString.call(123)) //[object Number]console.log(Object.prototype.toString.call('123')) //[object String]console.log(Object.prototype.toString.call(undefined)) //[object Undefined]console.log(Object.prototype.toString.call(null)) //[object Null]console.log(Object.prototype.toString.call(false)) //[object False]console.log(Object.prototype.toString.call(function () {})) //[object Function]console.log(Object.prototype.toString.call([1, 2, 3])) //[object Array]console.log(Object.prototype.toString.call(obj)) //[object Object]console.log(Object.prototype.toString.call(Array.prototype)) //[object Window]console.log(Object.prototype.toString()) //[object 原型obj]console.log(this)console.log('-- -- -- -- -- -- - -- -- -- -- -- -- -- -- -- -- -- -- --')
2.2 apply上下文调用
函数名.apply(修改的this, 数组/伪数组 )
function fn(a,b){console.log(this)console.log(a+b)}//函数名.apply(修改的this, 数组/伪数组 )//apply传参的时候会自动的遍历这个数组,然后按照循序逐一传参 a = [30,40][0] b=[30,40][1]fn.apply({name:'李四'},[30,40])//应用场景---------伪数组转真数组/*伪数组: 有数组三要素(下标、元素、长度),但是不能使用数组的方法伪数组 本质是对象伪数组不能使用数组方法: 伪数组的原型指向对象的原型,而不是Array的原型*/let obj = {0:20,1:50,2:88,3:66,length:4}console.log( obj )//需求:伪数组转成真数组//ES5 : 上下文let newArr = []//函数名.apply(修改的this, 数组/伪数组 )//第一个参数: newArr 本来this就是newArr,这里面不需要修改this.(相当于this不变)//第二个参数: obj. 借助apply特点:自动遍历伪数组/数组,逐一传参(自己省去了for循环)// newArr.push(obj[0],obj[1],obj[2],obj[3])newArr.push.apply(newArr,obj)console.log( newArr )//ES6(推荐) : Array.from(伪数组)let arr = Array.from(obj)console.log(arr)//应用场景--------数组求最大值//求数组最大值let arr = [10,20,50,60,88,30]//1.排序法 : 从大到小排序,取0下标// arr.sort(function(a,b){// return b-a// })// console.log(arr[0])//数组从大到小排序,第一个元素就是最大值//2.擂台法// let max1 = arr[0]// for(let i = 1;i<arr.length;i++){// if( arr[i]>max1){// max1 = arr[i]// }// }// console.log( max1 )//3.ES5 : Math.max.apply(Math,数组名)//函数名.apply(修改的this, 数组/伪数组 )//第一个参数 Math : this本来就是Math,这里也不需要修改this (传Math相当于this不变)//第二个参数 arr : 借助apply特点。 自动遍历数组/伪数组。 逐一传参let max2 = Math.max.apply(Math,arr)console.log(max2)//4.ES6(推荐) :let max3 = Math.max(...arr)console.log(max3)
2.3 bind上下文调用
函数名.bind(修改this)
bind不会立即执行函数,而是得到一个修改this之后的新函数(一次修改,终生受用)
细节: 如果你在bind后面传了函数参数,那么参数也会绑定。之后传参无效
function fn(a,b){console.log(this)console.log(a+b)}fn(1,2)//普通函数 this->window//(1)函数名.call(修改的this,参数1,参数2,....)fn.call({name:'张三'},10,20)//(2)函数名.apply(修改的this, 数组/伪数组 )//apply传参的时候会自动的遍历这个数组,然后按照循序逐一传参 a = [30,40][0] b=[30,40][1]fn.apply({name:'李四'},[30,40])//(3)函数名.bind(修改this)//bind不会立即调用函数,而是得到一个修改this之后的新函数let newFn = fn.bind({name:'王五'})newFn(25,66)//此时this指向{name:'王五'}//应用场景 --------------定时器中的this//bind场景主要是修改 '不需要立即执行的函数'// 事件处理函数、定时器函数//1.定时器中的this一定是windowlet fn = function(){console.log( this )}//使用bind修改thislet newFn = fn.bind({name:'666'})// fn() : 调用函数, 运行结果是函数返回值// fn : 变量取值, 取出fn中存储的堆地址setTimeout( newFn ,3000)//下面这个写法和上面写法是一样的 : 函数是数据类型,也可以像其他数据一样直接使用语法setTimeout(function(){console.log(this)}.bind({name:'干饭'}),3000)
上下文注意点
1.上下文模式: 修改this指向
2.注意点: this一定是指向对象(引用类型)
a.如果修改的this是 : string,number,boolean则编译器会自动转成对应的对象类型。
基本包装类型 : new String() new Number() new Boolean()
b.如果修改的this是: undefined和null,则修改无效
function fn(){console.log( this )}fn.call('123')// new String('123')fn.call(123)//new Number(123)fn.call(true)//new Boolean(123)fn.call(undefined)//windowfn.call(null)//windowfn.call()//window
3.闭包—一个访问其他函数中局部变量的函数
作用:解决变量污染
总结:形成闭包要有两个条件,缺一不可。 (1)函数 (2)访问其他函数内部变量
//获取元素let input = document.querySelector('input')let button = document.querySelector('button')button.onclick = function(){//有一个变量存储搜索结果let str = '6666'//模拟网络请求:2秒钟之后获取搜索结果setTimeout(function(){alert(`搜索结束,本次搜索结果是${str}`)},2000)}
4.递归函数—函数内部调用自己
注意点:需要满足条件(if)才会递归,否则会导致死循环 递归函数的功能类似于循环
递归函数应用场景 :
2.1 浅拷贝与深拷贝
浅拷贝: 拷贝的是地址, 修改拷贝后的数据对原数据有影响
深拷贝:拷贝的是数据, 修改拷贝后的数据对原数据没有影响
2.2 遍历dom树
4.1递归场景:深拷贝与浅拷贝
浅拷贝
//声明一个对象//拷贝: 把对象中存储的数据 拷贝一份赋值给其他对象let obj = {name:'ikun',age:30,hobby:['讲课','学生','学习'],friend:{name:'朋友',sex:'男'}}//浅拷贝: 拷贝的是地址let obj1 = obj//由于浅拷贝,拷贝的是地址。 所以修改拷贝后的数据,原来的数据也会变化obj1.hobby = '美食'console.log(obj1,obj)
深拷贝一JSON转换
let obj = {name:'ikun',age:30,hobby:['讲课','学生','学习'],friend:{name:'朋友',sex:'男'}}//(1)先把js对象转成json格式字符串 : JSON.stringify(js对象)//json在把js转成json格式字符串的时候,底层会自动帮你深拷贝// let json = JSON.stringify(obj)// console.log( json )//(2)再把刚才的json字符串,转成js对象 : JSON.parse( json格式 )// let js = JSON.parse( json )// js.hobby = '学习'// console.log( js,obj )//以上两个流程,可以简写成一行代码let newObj = JSON.parse( JSON.stringify( obj ) )newObj.friend = '71期'console.log(newObj,obj)
深拷贝二
let obj = {name:'ikun',age:30,hobby:['讲课','学生','学习'],friend:{name:'朋友',sex:'男'}}/*(1)遍历obj,把所有的属性添加给newObj(2)如果obj[key]是引用类型(数组、对象),则不能直接拷贝地址(2.1)数组:给newObj声明一个空数组,然后遍历obj[key],把里面元素添加给newObj[key](2.2)对象:给newObj声明一个空对象,然后遍历obj[key],把里面元素添加给newObj[key](3)如果obj[key]不是引用类型,则直接赋值。结束递归*/function kaobei(newObj,obj){for(let key in obj){//判断 obj[key] 是不是数组类型if( obj[key] instanceof Array ){//声明一个空数组,然后继续拷贝数组里面的数据newObj[key] = []kaobei(newObj[key],obj[key])}else if(obj[key] instanceof Object){//声明一个空对象,然后继续拷贝数组里面的数据newObj[key] = {}kaobei(newObj[key],obj[key])}else{newObj[key] = obj[key]}}}//调用深拷贝函数let newObj = {}kaobei(newObj,obj)//深拷贝:修改拷贝的数据,对原数据没有影响newObj.hobby[0] = '111'console.log( newObj,obj)
4.2遍历DOM树
//arr:数据 father:父盒子function addElement(arr,father){//遍历数组,生成div>p添加到父元素中for(let i = 0;i<arr.length;i++){//(1)创建空标签let div = document.createElement('div')//(2)设置内容div.innerHTML = `<p>${arr[i].type || arr[i]}</p>`//(3)添加到父盒子father.appendChild(div)//如果菜单还有data,说明还有子菜单,则需要继续遍历添加if( arr[i].data ){addElement(arr[i].data,div)}}}let menu = document.querySelector('.menu')//调用函数addElement(arr,menu)
三、ES6新语法
1.let与const关键字
let与const关键字特点
1.变量必须先声明,后使用
2.块级作用域,大括号里是局部变量
let与const区别
let :变量 。可以修改变量的数据
const:常量。只能在声明的时候赋值一次,不可以修改
2.对象解构
2.1取出对象的属性 赋值给变量
let obj = {name: '王力宏',age: 18,sex: '男',hobby: '按摩',eat: function () {console.log('全都要');}}//相当于/* let name = obj.namelet age = obj.agelet sex = obj.sexlet hobby = obj.hobbylet eat = obj.eat--> function(){}*///1.取对象的值,赋值给变量let {name,age,sex,hobby,price,eat} = objconsole.log(name, age, sex, hobby, price, eat);
2.2取变量的值 赋值给对象的属性
//2.取变量的值, 赋值给对象的属性let uname = '路飞'let ages = 20let gender = '海贼王'let nengli = function () {console.log('橡胶果实');}let caoMao = {uname, //相当于 uname:unameages,gender,nengli() { //相当于 nengli:function(){}console.log('橡胶果实');}}
2.3解构赋值其他用法
//2.1 解构赋值默认值let {name,age=18,sex} = obj //age =18 表示如果对象没有age属性,age=18,有的话就是age =obj.age//2.2 自定义解构变量名let { sex:gender } = obj 相当于 let gender = obj.sex
3.数组解构
3.1取出数组的元素 赋值给变量
let arr = [10,20,30]let [n1,n2,n3,n4] = arr//相当于:// let n1 = arr[0]// let n2 = arr[1]// let n3 = arr[2]// let n4 = arr[3]console.log( n1,n2,n3,n4)//10,20,30,undefined
3.2取变量的值 赋值给数组的元素
let num1 = 66let num2 = 88let num3 = 100let arr1 = [num1,num2,num3]
4.函数参数解构
//今后的开发中,很多函数的参数是对象类型function fn( {uname,pword} ){// {uname,pword} = {uname:'admin',pword:'123456'}//函数参数进// let {uname,pword} = objconsole.log( uname,pword )}fn({uname:'admin',pword:'123456'})
5.箭头函数
//1.箭头函数语法 就是function简写let fn = () => {} // fn = function(){}//2.当函数的参数只有一个的时候,可以省略小括号let fn1 = a => {return a * 5}console.log(fn1(5))//3.当函数的参数只有一个,且函数体只有一行的时候,可以省略小括号,大括号,省略了大括号,里面的return关键字也必须省略let fn3 = b => b * bconsole.log(fn3(10))
6.箭头函数this指向
箭头函数this指向 : 箭头函数没有this
箭头函数中使用this,会访问上级作用域this
原因(作用域链):箭头函数没有this, 就会往上级作用域找
let obj = {name:'张三',age:20,eat:function(){//eat是function函数, eat里面的this指向objlet fn1 = function(){//fn1是function函数, this指向window (普通函数调用)console.log( this )//window}fn1()let fn2 = ()=>{//fn2是箭头函数, 访问上级作用域(eat函数)中的thisconsole.log( this )//obj}fn2()},learn:()=>{//learn是箭头函数,this指向上级(全局)中的this:windowlet fn1 = function(){//fn1是function函数, this指向window (普通函数调用)console.log( this )//window}fn1()let fn2 = ()=>{//fn2是箭头函数,访问上级作用域(learn)this : windowconsole.log( this )//window}fn2()}}obj.eat()obj.learn()
7.展开运算符 ‘ … ‘
作用:相当于遍历对象简写
应用场景:
连接数组
求数组最大值
//1.用于连接数组 : 页面上拉加载下一页的时候,就需要连接数组let arr1 = [10,20,30,40]let arr2 = [50,60,70,80]//ES5 : arr1.push.apply(arr1,arr2)// arr1.push(arr2[0],arr2[1],arr2[2],arr2[3])// arr1.push.apply(arr1,arr2)//ES6 : arr1.push(...arr2)arr1.push(...arr2)console.log(arr1)//2.用于求数组最大值let arr = [20,0,60,88,100,50]//ES5 : Math.max.apply(Math,arr)let max1 = Math.max.apply(Math,arr)console.log( max1 )//ES6 : Math.max(...arr)let max2 = Math.max(...arr)console.log( max2 )
