js高级第一天
箭头函数
箭头函数的体验
const func3 = () => {
console.log(33);
}
func3()
箭头函数传参
箭头函数只传入一个函数时,小括号可以省略 const func2 = a => {}
当传入的参数个数不等于1时,小括号都不可以省略 1.const func2 = () => {} 2.const func2 = (a,b) => {}
const func2 = a => {
console.log(a);
}
func2(2)
箭头函数返回值简写
简写返回值的写法,如果函数只有一行代码,那么大括号可以省略 同时 这一行的代码运行结果也会被直接返回
如果想要省略大括号,就不要换行,理论上可以换,但不美观
const func2 = (a) => a + 1
console.log(func2(2));
箭头函数返回对象
如果箭头函数在省略大括号的情境下,想要返回一个对象,固定语法,添加一个小括号
const func1 = () => ({ uname: '小黑' })
console.log(func1());
参数默认值写法
(msg = '闷') '闷'就是msg的默认值
如果调用函数时,没有传递,就使用默认值
如果传递了参数 就是使用传递的参数,而不会使用,默认值
const func1 = (msg = '闷') => console.log(msg);
// func1('好热')
func1() //闷
解构
数组解构
const arr = [1, 2, 3, 4]
// 获取 数组的 前两个数据
// 数组解构 关注 顺序
const [str1, str2] = arr
console.log(str1, str2);
变量解构
交换两个变量
let a = 100;
let b = 200;
//交换两个变量
[b, a] = [a, b]
console.log(a, b);// a=200 b=100
对象解构
let obj = {
uname: '小马',
age: 18,
sex: '男'
}
// 相当于let uname = obj.uname let age = obj.age
let { uname, age, sex } = obj
console.log(uname, age, sex);
对象简写
如果变量名称和对象属性名称一致,可以使用对象简写
注意函数简写,省略了:function
const uname = '小黑'
const age = 19
// const obj = {
// uname: uname,
// age: age
// }
// 简写
// 如果变量名称和属性名称一致,可以写成下列方式
const obj = {
uname, //uname:uname
age, //age:age
say() {
console.log('你好');
}
}
console.log(obj);
obj.say()
剩余运算符
是一种比较方便我们获取数据的方式
语法:...
数组中使用:
const arr = ['a', 'b', 'c', 'd'];
// 希望可以获取到 剩下所有 元素 都放在新的数组中
const [let1, let2, ...list] = arr;
console.log(list);//['c','d']
对象中使用:
const obj = { a: 1, b: 2, c: 3, d: 4 };
const { a, b, ...obj2 } = obj;
console.log(obj2);//[c,d]
传参数中使用:
// 假设需求 封装一个函数 自动帮我计算 传入数据的 总和
// calc(1);// 1
// calc(1,2);// 3
calc(1, 2, 3);// 6
// calc();
function calc(...params) {
// params 可以获取到所有 传递给 calc 的参数 封装到一个数组中
console.log(params); //[1, 2, 3]
// 对数组做什么业务 都可以 计算总和 计算 最大值 最小值
// 求和
let sum = 0
params.forEach(v => sum = sum + v)
console.log(sum);
}
值类型和引用类型:
js数据类型 分成了两种 1 值类型 2 引用类型
1 值类型 简单数据类型 字符串、数字、布尔类型、
2 引用类型 对象 、 数组
两者区别 体现 =
值类型 使用 = 复制
引用类型 使用 = 关联在一起
let a =1 ;
let b = a;
// b a 的一份复制 两个值 一样 但是两个数据是完全独立!
b=10;
// a 不会发生变化
console.log(a);
const obj = { username: '悟空' };
// 也使用 =
const newObj = obj; // newObj 看起来和 obj 数据一样 两个数据 本身一起! 修改了其中的任意一个,另外一个也会收到影响
newObj.username = '八戒';
console.log(obj); //{username: '八戒'}
复制引用类型-剩余运算符
对象:
// 复制一份 对象 , 修改新的数据之后 旧的数据 不要收到影响
const obj = { username: '悟空', height: 100 };
// const newObj=obj;
const newObj = { ...obj };
// const newObj = { username:"悟空",height:100 };
newObj.username = '八戒';
console.log(newObj); //{username: '八戒', height: 100}
console.log(obj); //{ username: '悟空', height: 100 }
数组:
const list = ['a', 'b'];
// const newList = list; //
const newList = [...list];
newList.push('c');
console.log(newList); //['a', 'b', 'c']
console.log(list); //['a', 'b']
数组方法
map
处理后的数组
返回 处理后的数组
map 数组的一个方法 也会遍历 数组 接收一个函数
const arr = ['a', 'b', 'c'];
// ['<li>a</li>','<li>b</li>','<li>c</li>']
const newArr = arr.map((value) => `<li>${value}</li>`);
console.log(newArr);
filter
过滤
filter 会遍历数组 返回 满足了你条件的(函数内 返回true!! ) 新的数组
const arr = [1, 3, 5, 7, 9];
// 返回 大于 3的数据 重新组成数组
const newArr2 = arr.filter((value) => value > 3);
console.log(newArr);//[5, 7, 9]
every
数组是否全符合
every 检测数值元素的每个元素是否都符合条件 全部都符合 返回 true 否则就返回false
every 对于空数组 也会直接返回true
some
只要有一个条件 都返回true
some 检测数组元素中 只要有一个条件 都返回true
find(用于对象数组)
用找满足条件的数组中一个元素
特点:找到了之后 不会再继续往下遍历
find 返回符合 条件的数组元素。
findIndex(用于对象数组)
符合条件的元素的下标
用法可以find很类似 在函数中 如果找到了 返回元素的下标
找不到 就返回 -1
includes(用于简单数组)
判断一个数组是否包含一个指定的值。
有就返回true 没有就返回false
indexOf (用于简单数组)
搜索数组中的元素,并返回它所在的位置
找到了 就返回元素的下标
没有找到了 返回 -1
join
负责把数组 转成 字符串
js高级第二天
Set对象
- Set 是一个对象 不会存放重复数据
- 数组转成 set对象 const set = new Set([])
- set对象 转成 数组 const arr=[...set]
- set对象 添加数据 使用add方法
// 存在旧的数组
const list = [1, 4, 5, 6, 7];
// 1 Set对象 需要被 new 出来使用
const set = new Set(list);
// 2 存放数据 调用 add方法
set.add(1);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(3);
// console.log(set);
// 把set对象 转成数组
const arr = [...set];
console.log(arr);//[1,2,3,4,5,6,7]
创建对象的多种方式
1. 创建对象的方式 字面量 => 字面意思
不方便维护 - 修改
const obj = { nickname: '八戒', height: 190 };
const obj1 = { nickname: '八戒', height: 190 };
const obj2 = { nickname: '八戒', height: 190 };
const obj3 = { nickname: '八戒', height: 190 };
const obj4 = { nickname: '八戒', height: 190 };
const obj5 = { username: '八戒', height: 190 };
2. 工厂函数 封装
方便维护和修改,但是不能实现继承
function p(name,a,b,c,d,e) {
return {
nickname:name,
a,b,c,d,e
}
}
3. 重点介绍 构造函数
构造函数
构造函数的特点
- 构造函数 本质 其实也是一个函数
- 作用 用来创建对象
- 常用系统自带构造函数(Set 构造函数、Array 构造函数、Object、String、Number、Boolean、Date)
- 只要它被new 它 就是构造函数
- 首字母是大写(规范)
例:Person 构造函数
per 被new出来的对象 per称为实例!
function Person() {}
// Person 就是一个构造函数 被new
const per = new Person();//per 被new出来的对象 per称为实例!
构造函数中的this
构造函数 默认情况下 就是返回了 this
this 等于你所new出来的实例 per
只要给构造函数中的this 添加 属性或者方法;那么 实例 自然拥有对应的属性和方法
function Person() {
this.username = '悟空'; // per也增加了一个属性
this.add = () => { };
this.clear = () => { };
}
const per = new Person();
per.username = '八戒';
const per2 = new Person();
console.log(per);//{username: '八戒', add: ƒ, clear: ƒ}
console.log(per2);//{username: '悟空', add: ƒ, clear: ƒ}
构造函数-弊端
构造函数里面的方法会存放在不同的地址中
例:
function Person() {
this.say = function () {};
}
const p1 = new Person();
const p2 = new Person();
console.log(p1 === p2); // 两个对象的比较 内存地址 false
console.log(p1.say === p2.say);// false 两个函数 存放在不同地址中
// const s1 = new Set();
// const s2 = new Set();
// console.log(s1 === s2);// false
// console.log(s1.add === s2.add); // true
// s1 和 s2 共享一个方法
// p1 和 p2 没有共享一个
对象在堆中的情况
字面量对象:
工厂函数:
构造函数:在构造函数中 当我们定义方法的时候 一般都不会只在在 构造函数中写死 ;让我们方法 都指向外部 单独声明的方法 多个实例去共享方法
构造函数基本使用
构造函数的时候 属性 分成了两种
- 函数类型的属性 ;一般都是写在外部(提取函数到构造函数外部,实现了多个实例共享一个函数(优化内存空间;弊端:污染全局变量(使用原型可避免))
- 非函数类型的属性;一般是写在内部
// 构造函数的方式 创建一个对象
// 姓名 属性
// 说出自己的姓名 方法
function say() {
console.log('这个是Person的一个方法', this.name);
}
function fly() {
console.log(this.name, '要起飞');
}
function Person(name, height) {
this.name = name;
this.height = height;
this.say = say;
this.fly = fly;
}
const p1 = new Person('八戒', 150);
// p1.say();
p1.fly();
构造函数 + 原型 搭配使用
原型 本质是一个对象 在我们创建构造函数的时候就拥有
在原型上添加的一些方法,可以直接被 实例所使用和共享
可以这么理解 构造函数=父亲 实例=孩子 原型=DNA
-
使用面向对象的方式来创建对象
4.1 构造函数内部 来定义 非函数类型的属性 如 姓名 身高 肤色 性别 4.2 原型来定义 函数类型的属性 函数
面对对象编程案例:
点击按钮图片放大
<button> 变大</button>
<script>
function MyImg(src) {
// body标签上能出现一张图片
const img = document.createElement('img');
img.style.transition = '2s';
// 设置 图片地址
img.src = src;
// 在body标签上看见这一张图片
document.body.append(img);
this.abc = img;
}
// 原型上写一写函数
MyImg.prototype.scale = function (num) {
// 获取到 构造函数中 创建的 img dom元素 - 提前把img dom 添加到 this的属性中
this.abc.style.transform = `scale(${num})`;
};
const myImg = new MyImg('./images/1.png'); // body标签上能出现一张图片
const myImg2=new MyImg("./images/1.png");
const button = document.querySelector('button');
button.addEventListener('click', function () {
// myImg.scale(2);//
myImg.scale(3); // 3 倍
myImg2.scale(5);
});
</script>
js高级第三天
构造函数+原型
构造函数 是一个函数 作用 创建对象的 用法 必须要new
原型 理解 DNA 在构造函数的原型上所定义的方法 用在实例中
实例 通过构造函数所创建出来的对象
构造函数中 关键字 this === 被new出来的实例
// 构造函数
function Person(name) {
// 实例对象 对象添加属性
// p1.name=name;
this.name = name;
}
// 方法定义在原型上
Person.prototype.scale = function () {
console.log(this.name, '放大');
};
// p1 实例 对象
const p1 = new Person('悟空');
const p2 = new Person('八戒');
p1.scale();
p2.scale();
原型实现方法的继承
儿子的构造函数.prototype.方法名称 = 父亲的构造函数.prototype.方法名称
function Person(name) {
this.name = name;
}
Person.prototype.say = function () {
console.log('父亲的say方法');
};
function YellowPerson(name, color) {
Person.call(this, name); // 属性的继承
this.color = color;
}
YellowPerson.prototype.say = Person.prototype.say;
YellowPerson.prototype.fly = function () {
console.log('儿子自己的方法 fly');
};
原型实现属性的继承
父亲的构造函数.call(this,参数。。。)
call的本质:属性的继承 在 儿子的构造函数中 调用 父亲的构造函数
function Person(name) {
this.username = name;
}
function YellowPerson(name) {
Person.call(this, name); // 属性的继承
}
const yp = new YellowPerson('悟空');
console.log(yp);
类的基本使用
es6 class面向对象(工作中常用)
// es6 新 简洁 class 面向对象
class Person {
name = '悟空';
color = '黄色';
say() {
console.log(this.name, this.color);
}
fly(){
console.log(this.name,"起飞");
}
}
// es5 原型链方式实现 面向对象
// function Person() {
// this.name="悟空";
// this.color="黄色";
// }
// Person.prototype.say=function(){
// console.log(this.name,this.color);
// }
const p1 = new Person();
p1.say();
p1.fly();
如果 属性 可以由外部传入 必须使用构造器
class Person {
// 构造器
constructor(name, color) {
// 当 Person被new的时候 这个构造器 就会被调用
console.log('person被new啦');
// console.log(name,color);
// this 还是指向 实例
this.name = name;
this.color = color;
}
say() {
console.log(this.name, this.color);
}
}
const p1 = new Person('悟空', '黄色');
console.log(p1);
类的方式来实现继承
extends
如果你写了 extends 而且 还写 constructor
那么在我们的 constructor 必须要调用super 固定语法!!
class Person {
constructor(name, color) {
this.name = name;
this.color = color;
}
}
class YellowPerson extends Person {
// 默认的代码
constructor(name, color, height, weight) {
super(name, color);// 调用父亲的构造器 给儿子 添加属性
this.height = height;
this.weight = weight;
}
}
const yp = new YellowPerson('悟空', '黄色', 100, 200);
console.log(yp);
检测数据类型
基本的数据类型 typeof
引用数据类 intanceof——检测 这个实例是不是被某个构造函数
class Person {}
class SuperPerson{}
const p1 = new Person();
const s1 = new SuperPerson();
console.log(p1 instanceof Person);// true
console.log(p1 instanceof SuperPerson); // false
this 指向
一般来说 this的指向 判断依据 谁调用了 函数 this 指向谁
1 当我们定义全局的函数的时候 本质是给window添加了一个 属性(函数类型)
2 当我们调用这个函数 的时候 abc() 本质 window.abc() -- window 可以被省略而已
箭头函数没有内部的this
1 箭头函数没有内部的this
2 当你的函数执行体代码中 有出现了 this 慎用 箭头函数!! - 遵循!!
bind 、call 、 apply 修改 this的指向
1 call 和 apply 会在调用原函数的同时也修改this的指向
2 bind会帮你修改this指向 但是 不会直接调用原函数 而是会返回一个 修改了this指向 的新函数
2.1
const fn = obj.say.bind(newObj); fn(1, 2);
3 call 和 apply 区别 传递参数的方式不同而已
3.1 obj.say.call(newObj,1,2)
3.2 obj.say.apply(newObj,[1,2]) // 参数必须要以数组的形式来传递
原型继承
用这种方式儿子原型直接指向父亲原型,修改儿子原型,父亲原型也会被修改,所以一般不用
// 让儿子的原型 指向 父亲的原型
// YellowPerson.prototype = Person.prototype;
改善:先复制一个父亲原型,再用儿子原型指向复制的父亲原型
// 对象复制
YellowPerson.prototype = { ...Person.prototype };
//
YellowPerson.prototype.constructor = YellowPerson;
const yp = new YellowPerson();
console.log(yp);
//给儿子一个方法,然后查看父亲的原型,验证修改儿子原型不会影响父亲原型
// YellowPerson.prototype.aabbcc = function () {};
// const p1 = new Person();
// console.log(p1);