ES6-函数参数默认值
定义函数的同时,可以给形参一个默认值
目前浏览器 支持的js的代码版本
主要都支持 es5 (for if while 函数 forEach ) 版本
新的语法 es6 (提供了更加简单强大的代码更能力) 提高我们的开发效率
示例
// es6函数参数默认值
// 你好 默认值
function show(msg = '你好', str = '大家好'){
console.log(msg,str);
}
show() // 没有传递参数 输出 你好 大家好
show('大家不好') // 没有传递参数 输出 大家不好 大家好
show('大家不好','我吐了呀') // 没有传递参数 输出 大家不好 我吐了呀
set( )
永远不会有重复元素的对象
可以理解为不重复的数组
set对象 是es6 才推出 主要的功能 去重处理
set是一个对象,不是一个数组!!
实现 使用set转成数组的时候,需要考虑 (set对象转-数组 数组 - 转成对象)
数组 - 转成对象 new Set(beforeArr)
set对象转-数组 const arr=[...set];
set( )
<input type="text" />
<ul></ul>
<script>
const input = document.querySelector('input');
const ul = document.querySelector('ul');
let arr = ['a', 'b'];
render();
input.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
const set = new Set(arr);
set.add(this.value);
arr = [...set];
render();
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join('');
ul.innerHTML = html;
}
</script>
对象简写
在定义对象的时候,如果属性名和变量名一直,那么可以实现简写
示例
// 简写 如果变量的名字和属性的名字 一致的话,对象可以简写
// const obj = {
// // 属性名 和 属性值
// username: 123,
// };
const username = 123;
const color = 'red';
const say = function () { };
function show() { }
// 很常用
const obj = {
username, // username:username
color, // color : color
say,
show,
height: 100,
};
obj.height = 200;
// console.log(obj);
// 对象中方法的简写
const person = {
show: function () {
console.log("show");
},// 常规写法
// es6 关于 方法简写
say() {
console.log("say");
} // es6 关于 方法简写
}
person.show();
person.say();
/*
小结:
1 变量名如果和你的对象的属性名一致 可以简写
let username='悟空'
const obj = { username }
2 对象的方法 简写
const obj ={
say(){ // 简写的方法
}
}
*/
解构
提供更加方便获取数组中元素或者对象中属性的写法
<div data-index="100" data-num="200">div</div>
<script>
// dataset = { index:100}
// const dataset= document.querySelector('div').dataset;
// const { index,num } = document.querySelector('div').dataset;
// console.log(dataset);
// const {index}=dataset;
// console.log(index);
// console.log(num);
// const arr = ['悟空', '八戒', '龙马', '三藏'];
// const a = arr[0];
// const b = arr[1];
// const c = arr[2];
// const d = arr[3];
// 数组解构
// const [a,b,c,d]=arr;
// const [a, b, c, d] = ['悟空', '八戒', '龙马', '三藏',"沙僧"];
// console.log(a, b, c, d);
// 对象的解构
// const obj = {
// username: '悟空',
// height: 100,
// };
// 声明两个变量 来获取obj的两个属性
// low 代码!!!
// const username = obj.username;
// const height = obj.height;
// 对象解构
// const { username, height } = obj;
// console.log(username, height);
// 解构 + 默认值
// const arr = [1,100];
// const [a,b ] = arr; a = 1 b=undefined
// const [a, b = 2] = arr;
// console.log(a, b); // a =1 b = 2
// b = 2 默认值 (你没有,就使用我,你有,使用你的)
// const [a, b = 2] = arr;
// console.log(a,b);
const obj = {
username: 100,
height: 500,
};
const { username, height = 200 } = obj;
console.log(username, height);
/*
小结
1 解构 对象 和 数组上
对象
const { username,height } = {username:"悟空",height:200}
数组
const [a,b]=[100,200];
2 解构 + 默认值
如果 右边的对象中没有height 属性 那么 height变量 = 1000
const { username,height=1000 } = {username:"悟空",height:200}
// c 在右边找不到对应的数据 c 就使用默认值 300
const [a,b,c=300]=[100,200];
*/
</script>
拓展运算符-剩余运算符-延展运算符
通过 ...
符号来获取剩下的参数
函数内获取
function show(a, ...all) { // 只能放最后
console.log(a);
console.log(all);
}
show(1);// 1 []
show(1, 2, 3);// 1 [2,3]
// 获取剩下 用在函数的形参上
// 计算数据和的功能
// calc(1,2)// 1 + 2
// calc(1,2,3) // 1 + 2 + 3
// calc(1,2,3,4) // 1 + 2 + 3 + 4
function calc(...args) {
// args 数组 装载这所有传给calc的参数
// console.log(args);
let sum = 0;
args.forEach((value) => (sum += value));
console.log(sum);
}
calc(1, 2); // ? [1,2]
calc(1, 2, 3); // [1,2,3]
calc(1, 2, 3, 4); // [1,2,3,4]
数组内获取
const [a, ...rest] = [1, 2, 3, 4, 5];
console.log(a); // 1
console.log(rest);// [2, 3, 4, 5]
const [...a]=[1,2,3,4];
console.log(a);// [1,2,3,4]
console.log(a.map);
const lis = document.querySelectorAll('li');// lis 伪数组 没有map方法
const newList = [...lis]; // 如何理解 ? 转成真正的数组
console.log(newList.map);
// 获取剩下 用在函数的形参上
对象内获取
const obj={
name:"悟空",
skill:"72变",
say(){}
}
const {name,...others}=obj;
console.log(name); // 悟空
console.log(others); // {skill: "72变", say: ƒ}
// 获取剩下 对象
const { a, ...c } = { a: 1, b: 2, c: 3 };
const { a,b,c ,...d } = { a: 1, b: 2, c: 3 };
console.log(c);// ? {b:2,c:3}
console.log(d); // ?
剩余运算符
1 数组中 const [a,b,...c]=[1,2,3,4,5,6,7]; c =[3,4,5,6,7]
应用场景 伪数组转真正的数组
2 对象中 const { a,...d } = { a: 1, b: 2, c: 3 }; // d = {b:2,c:3 }
3 函数的形参中
calc(1, 2, 3); function calc(...args) {} // args = [1,2,3]
计算数字总和
计算数据和
练习题目
getMax(1,2,3) // 输出3
getMax(1,4) // 输出4
getMax(1,20,4) // 输出20
getMax(1,20,4,30,2) // 输出30
// 计算最大值的写法
function getMax(...args) {
// args= 数组 接收 所有传递给 getMax方法的 参数
// console.log(args);
// 计算最大值 的
let max = args[0];
args.forEach((value) => {
if (value > max) {
max = value;
}
});
console.log(max);
}
// getMax(1);
// getMax(1, 2);
// getMax(1, 2, 3);
// getMax(11, 33, 2, 3);
// Math对象 自己就封装过 计算最大值和最小值的代码
// console.log(Math.max(1,3,4,2));// 4
// console.log(Math.min(1,3,4,2));// 1
function getMax2(...args) {
// Math.max(1,3,4,2)
// args=[1,3,4,3]
// Math.max([1,3,4,3]) => Math.max(1,3,4,2)
// 剩余运算符的
console.log( Math.max(...args));
}
// getMax2(1,2,3);
// getMax2(1,2,33);
// console.log(Math.max(...[1,3,4,3])); // Math.max(1,3,4,2)
getMax2(1,2,3,4); // 体现的思想 不再是 剩余 。 展开-延展-拓展 思想
// 计算最大值的写法
function getMax(...max){
console.log(Math.max(...max));
}
getMax(1, 2, 3)
getMax(1, 4)
getMax(1, 20, 4)
getMax(1, 20, 4, 30, 2)
展开 ... 对象的用法
// 展开 ... 用法
const obj = {
username: '悟空',
height: 200,
};
const newObj = obj;// 对象是引用类型 写 = 将 obj的地址 给了一份 newObj 两个变量指向的地址同样的 同一个对象
newObj.color = 'yellow';
console.log("新的对象",newObj);
console.log("旧的对象",obj);
const obj = {
username: '悟空',
height: 200,
};
// 新创建一个对象 这个对象 具有 所有 obj的属性
// 同时 还有多一个属性,color
const newObj = { ...obj, color: 'yellow' }; // 给newObj 开辟新的内存空间
// const newObj={ username:"悟空",height:20}; // 给newObj 开辟新的内存空间
newObj.username = '八戒';
newObj.weight = 100;
console.log(obj);
console.log(newObj);
展开运算符 对数组操作
const arr = ['a', 'b', 'c'];
// 在数组的后面 新增一个 元素 'd'
const newArr=[...arr,'d'];
console.log(newArr);
const arr = ['a', 'b', 'c'];
// 在数组宅前面 新增一个属性 w
const newArr = ['w', ...arr];
console.log(newArr);
JQ的演示
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.js"></script>
<script>
// 简单 比js高级 简单多了 不是一个量级!!
$(function () {
$("li").click(function () {
// 1 点击 激活选中 其他li标签排他
// $(this).css("backgroundColor","red").siblings().css("backgroundColor","#fff");
// 2 点击 渐变 显示和消失
// $(this).fadeToggle()
// 3 手风琴
// $(this).slideUp();
})
})
</script>
函数的四种调用模式
根据函数内部this的指向不同,可以将函数的调用模式分成4种
- 函数调用模式
- 方法调用模式
- 构造函数调用模式
- 上下文调用模式(借用方法模式)
函数调用模式
如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window
<script>
function func1() {
console.log(this);
}
// func1(); // this = window 定义在全局的函数 理解为window的一个属性
// window.func1(); // this = window 定义在全局的函数 理解为window的一个属性
// const obj={
// name:"悟空",
// say(){
// console.log(this);
// }
// }
// obj.say();// this = ?
function Person() {
this.name = '悟空';
}
Person.prototype.say = function () {
console.log(this);
};
const p1 = new Person();
p1.say(); // this = p1
console.log(p1);
</script>
方法调用模式
当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象
const obj = {
sayHi:function(){
console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
}
}
obj.sayHi();
<script>
// 在js中,顶级的对象 就是window
// 定义一个函数 形式是箭头函数的
// const func = () => {
// console.log(this);
// };
// func();
// const obj = {
// name: '悟空',
// say: () => {
// console.log(this);
// },
// };
// obj.say(); // window
// const obj1 = {
// name: '悟空1',
// obj2: {
// name: '悟空2',
// say: () => {
// console.log(this);
// },
// },
// };
// obj1.obj2.say();
const button = document.querySelector('button');
// button.addEventListener('click', function () {
// console.log(this); // this = button
// });
button.addEventListener('click', ()=> {
console.log(this);// this = 谁
});
/*
大部分情况,对于普通函数,this 等于这个函数的调用者
(例外 - bind、call、apply)
大部分情况,对于箭头函数,this 等于window
箭头函数和this 一起用的话,要慎用!!
例外(面向对象用法,)
*/
</script>
构造函数调用模式
如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上
function Person(){
console.log(this);
}
Person();//this指向什么?
const p = new Person();//this指向什么?
方法借用模式
也叫上下文模式,分为 apply 与 call
call
call方法可以调用一个函数,并且可以指定这个函数的this
指向
const RichWumon = {
name: "富婆",
say: function () {
console.log(this.name, " 我要重金求子");
}
}
const obj = {
name: "屌丝"
}
RichWumon.say(); // 富婆
RichWumon.say.call(obj); // 屌丝
apply
就是apply()
方法接受的是一个包含多个参数的数组。而call()
方法接受的是若干个参数的列表
const obj = {
name: '小明',
skill(a, b) {
console.log(this.name + ' ' + a + ' ' + b);
}
}
const person = {
name: '小红',
};
obj.skill.apply(person, [5, 6]) // 传参用数组方式填写
bind方法
bind()方法创建一个新的函数, 可以绑定新的函数的this指向
const name = '张三';
function Fn(){
this.age = 1;
console.log(this.name + this.age);
}
Fn(); // 张三 1
// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
let obj = {
name:'小强',
}
const newFn = Fn.bind(obj);
newFn(); // 小强 1
bind-call-apply修改this指向
<script>
/*
1 bind call apply 都可以实现修改this指向
2 代码写法上有区别
1 obj.skill.call(person);
2 obj.skill.apply(person);
3 const func = obj.skill.bind(person);
func();
3 传递参数
1 obj.skill.call(person,参数1,参数2)
2 obj.skill.apply(person,[参数1,参数2])
3 const func = obj.skill.bind(person);
func(参数1,参数2)
*/
const obj = {
name: '小明',
skill(a, b) {
console.log(this.name + ' ' + a + ' ' + b);
}
}
const person = {
name: '小红',
};
obj.skill.call(person, 5, 6) // 传参
obj.skill.apply(person, [5, 6]) // 传参用数组方式填写
const func = obj.skill.bind(person) //
func(8, 9)
// obj.skill.call(person,1,2);// 传参
// obj.skill.apply(person, [1, 2]); // 数组
// 在早些时候 我们是这样来计算 数组最大值和最小值
// const max = Math.max(1, 2, 3, 4);
// console.log(max);
// const arr=[1,2,3,4];
// 借用 Math.max方法 目的不是修改this指向
// 而是 计算数组最大值
// const max = Math.max.apply(null,arr);
// 这种
// const arr=[1,2,3,4];
// console.log(Math.max(...arr));
</script>
bind-call-apply传递参数
<script>
/*
1 bind call apply 都可以修改this的指向
2 分别演示 修改this指向
call obj.skill.call(person)
apply obj.skill.apply(person)
bind
const func = obj.skill.bind(person);
func();
3 传递参数的时候不同写法上
*/
const obj = {
name: '老王',
skill() {
console.log(this.name + ' 翻墙');
},
};
const person = {
name: '大郎',
};
// call 方式来修改this的指向
// obj.skill.call(person);// 大郎 借用老王的方法
// apply 方式来修改this的指向
// obj.skill.apply(person); // 大郎 借用老王的方法
// bind 方式来修改this指向
// bind 不会直接调用skill函数 而是 返回一个新的函数
// 需要我们主动的调用新的函数- 调用skill()
const func = obj.skill.bind(person);
func();
</script>
ES6 面向对象
es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。
- class
- 属性
- 方法
- 继承 extends
- 构造函数 constructor
- 方法重写 override:子类方法覆盖父类,super.父类方法()
- 父类的构造函数 super :子类有构造方法且使用this前,必须使用super()
es5的面向对象
<script>
// es5 写一个 构造函数 首字母是大写
// 当我们new 一个 对象的时候 Person 代码会被执行
function Person(name) {
// console.log("开始创建对象啦");
this.name = name;
}
// 定义行为 引出 原型
Person.prototype.say = function () {
console.log('say方法被调用啦 ' + this.name);
};
// new 一个对象
const p1 = new Person('悟空1');
const p2 = new Person('悟空2');
// console.log(p1);
console.log(p1.say === p2.say);
</script>
```
ES6面向对象 新的方式 class
<script>
// es6 面向对象 引出新的语法 类 class
// constructor 会在 new Person的时候触发
class Person {
constructor(name) {
// console.log("开始创建对象啦");
this.name = name
}
// 直接写行为
say() {
console.log('say方法调用' + this.name);
}
}
// 一样new一个对象
const p1 = new Person('卡卡罗特')
const p2 = new Person('贝吉塔')
console.log(p1);
console.log(p2);
// 属性
// 行为
class SuperMan {
constructor() {
// 对象有什么属性都写在 这里
this.name = '悟天'
this.color = 'yellow'
}
// 行为
say() {
console.log('会变身');
}
fly() {
console.log('超赛三');
}
sing() {
console.log('超赛神');
}
}
const w1 = new SuperMan()
console.log(w1);
</script>
以前es5-继承
<script>
function Person(name) {
this.name=name;
}
Person.prototype.say=function(){
console.log("say方法我调用啦 "+ this.name);
}
Person.prototype.fly=function(){
console.log("父亲 起飞");
}
function Student(name,color) {
Person.call(this,name);// 继承属性
this.color=color;
}
Student.prototype.say=Person.prototype.say;// 继承方法
Student.prototype.fly=Person.prototype.fly;// 继承方法
const s1=new Student("学生","red");
console.log(s1);
s1.say();
</script>
现在的ES6继承
<script>
// ES6
class Person {
// 属性
constructor(name) {
this.name = name;
}
// 行为
say() {
console.log('say方法我调用啦 ' + this.name);
}
fly() {
console.log('父亲的起飞');
}
}
// 表示学生要继承父亲
// extends 直接就实现了继承父亲的方法
// 写了 extends 还写了 constructor 那必须在 constructor 调用方法 写 super();
class Student extends Person {
constructor(name, color) {
// 写 super(); 代表继承父亲的哪个属性
super(name); // 父亲的构造函数 =es5 Person.call(this,name);
this.color = color;
}
// fly(){
// console.log("儿子 起飞");
// }
// fly = null; // 用儿子的新的null 去覆盖父亲的fly没有父亲的fly
}
const s1 = new Student('学生', 'red');
s1.say();
s1.fly();
/*
Must call super constructor in derived class before accessing 'this' or returning from derived constructor
1 如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super();
2 如果你只写了 extends 但是你没有写constructor 不需要管super
继承要继承父亲的属性和父亲的行为
1 只实现了继承父亲的行为 还没有实现继承父亲的属性 (super 表示可以继承父亲的属性)
*/
</script>
案例
使用es6的class 实现以下功能
1 父类 Element
1 属性 this.dom
2 方法 append
2 定义两个子类 都要继承父亲的属性和方法
1 ElementDouble
2 ElementSingle
3 然后 通过编写代码 把以下程序运行起来
<script>
class Element {
constructor(tagName) {
const dom = document.createElement(tagName);
this.dom = dom;
}
append(parentSelector) {
document.querySelector(parentSelector).appendChild(this.dom);
}
}
class ElementDouble extends Element {
constructor(tagName, content) {
super(tagName);
this.dom.innerText = content;
}
}
class ElementSingle extends Element {
constructor(tagName, src) {
super(tagName);
this.dom.src = src;
}
}
const divModel = new ElementDouble('div', '这个是div');
divModel.append('body');
const imgModel = new ElementSingle('img', './images/b_01.jpg');
imgModel.append('div');
</script>
以后就很少看到 es5 原型了
但是以后看别人的代码 可能有es5 原型 prototype 也有es6的class
假如让我来选择技术类型 我会优先选择es6 但是别人怎么选的 你没有办法控制 你能做只有一个 都懂!!
es6-class和箭头函数
es6 属性的定义 写法有两种
1 直接在构造函数内 constructor this.name=name
2 可以写在 大括号内
3 方法 三种写法
class Person {
// color = 'yellow';
// height = 180;
// weight = 200;
constructor(name) {
this.name = name;
// this.color = 'yellow';
// this.height = 180;
// this.weight = 200;
}
// 写法一
// say() {
// console.log('say 方法被调用了 ' + this.name);
// }
// 写法二
// say = function () {
// console.log('say 方法被调用了 ' + this.name);
// };
// // 写法三
say = ()=> {
// 箭头函数中的this , 绝大部分指向 window
// 例外 用在 es6的class 充当 方法 this 指向 p1 实例
console.log('say 方法被调用了 ' + this.name);
};
}
const p1 = new Person('悟空');
p1.say();
// console.log(p1);
三种写法 哪个性能比较好
class Person {
// 性能最好 推荐方式!!
say1() {
console.log('say1');
}
say2 = function () {
console.log('s2');
};
say3 = () => {
console.log('s3');
};
}
const p1 = new Person();
const p2 = new Person();
console.log(p1.say1 === p2.say1); // true p1 和 p2 say1方法是同一个-节省内存
console.log(p1.say2 === p2.say2); // false p1 和 p2 say2方法不是同一个-性能不好
console.log(p1.say3 === p2.say3); // false p1 和 p2 say3方法不是同一个-性能不好
es5-原型链
原型链
一个对象 它可以通过 prototype 来 找到被它继承父亲的方法
如果一个对象从底层触发 可以通过 prototype 一层一层往上找到 继承的关系 = 原型链
<script>
// 1 创建数组的方式 有两种
// const arr = ['a', 'b', 'c']; // 字面量 常用-直接和简单的写法
// 2 数组 也是可以被new
// const arr = new Array('a', 'b', 'c');
// console.log(arr);
function Person() {}
const p1 = new Person();
// 在 Person的原型上添加一个方法
Person.prototype.show = function () {
console.log('自己添加的方法');
};
// p1.show();
// 给js内置的Array数据 原型也添加一个方法试试
Array.prototype.show = function () {
console.log('自定义的数组方法');
};
const arr = new Array('a', 'b', 'c');
// const arr = ['a', 'b', 'c'];
// arr.show();
// 利用原型对象的方式,在任意的构造函数上添加想要的行为
// 任意的构造函数 包括 自己定义的构造函数
// 也包括 js中 -内置就有的构造函数 Array
// arr.forEach
// arr.push()
// arr.map()
// arr.filter
// 对象的创建也分两种清空
// const ojb={};// 字面量 常用 直接 简单
const obj = new Object(); // 利用构造函数的方式来创建对象
Object.prototype.show = function () {
console.log('对象 自己的show方法');
};
obj.show();
</script>
作用
1 如果我需要给 某个数据 (字符串、数组、对象) 统一添加一个方法 ,可以直接在原型上添加
2 初学者 不要乱在原型上定义方法 - 影响巨大
*/
// const obj = {
// username: '悟空',
// say() {
// console.log('这个是say方法');
// },
// };
// // 万物皆对象
// Object.prototype.show = function () {
// console.log('这个是原型上的show方法');
// };
// // 你看要 dom对象 大哥大
// console.dir(document.querySelector("div"));
// const arr = [];
// console.log(arr);
// arr.show();
// console.log();
// Math.show()
// const str="123";
// console.dir(str.show);
// str.show();
// console.log(obj);// 直接看到定义在自己身上的属性和方法 看不见定义在 原型对象上的属性和方法
// console.log([]);
// const arr=[];
// arr.push
// console.log(arr);
// obj.say();
// obj.show();
// const arr1=[];
// const arr2=[];
// const arr3=[];
// DNA 存在于你整个家族 不只是父亲和儿子
Array.prototype.forEach=function(){
console.log("老子罢工了");
}
Array.prototype.map=function(){
console.log("老子罢工了");
}
const arr=[1,2,3];
arr.forEach(); // forEach 循环 到了你这个项目 这个知识用不了