JavaScript高级(三)
一、set
1.set对象 是es6 才推出
2.解释:永远不会有重复元素的对象,可以理解为不重复的数组
3.set是一个对象,不是一个数组
4.实现 使用set转成数组的时候,需要考虑 (set对象转-数组 数组 - 转成对象)
①数组 - 转成对象 new Set(beforeArr)
②set对象转-数组 const arr=[...set];
5.关键代码
①关键代码
// 0 有时候 先设置一个初始数组 里面已经存在一些数据
// 在创建set的对象的时候,把数组传给它
const beforeArr = ["a", "b", 3, 4];
// 1 set对象 需要被new 出来
const set = new Set(beforeArr); // 数组转成set对象
// 2 给set添加数据的时候 使用 add方法
set.add(1);
set.add(2);
set.add(2); // 发现有重复数据了,自己内部过滤
set.add(2); // 发现有重复数据了,自己内部过滤
set.add(2); // 发现有重复数据了,自己内部过滤
set.add(2); // 发现有重复数据了,自己内部过滤
// 3 打印set 看一下
console.log(set);
②关键代码
// 4 set 转成 数组(map、forEach。。。)
const arr = [...set];
console.log(arr);
6.案例-set去重
①关键代码
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join("");
ul.innerHTML = html;
}
input.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
// 数组转成set对象
let set = new Set(arr);
// 给set添加数据的时候 使用 add方法
set.add(this.value);
// set对象转-数组
arr = [...set];
// arr.push(this.value);
render();
}
});
②完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
/>
<title>02-set去重案例</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
</head>
<body>
<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") {
// 去重处理
let set = new Set(arr);
set.add(this.value);
arr = [...set];
// arr.push(this.value);
render();
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join("");
ul.innerHTML = html;
}
</script>
</body>
</html>
二、this指向
1.func1(); // this = window 定义在全局的函数 理解为window的一个属性
2.window.func1(); // this = window 定义在全局的函数 理解为window的一个属性
// const obj = {
// name: "悟空",
// say() {
// console.log(this);
// },
// };
// obj.say(); // this = ? // obj
function Person() {
this.name = "悟空";
}
Person.prototype.say = function () {
console.log(this);
};
const p1 = new Person();
p1.say(); // this = p1
console.log(p1);
3.bind-call-apply修改this指向
(1)bind call apply 都可以修改this的指向
①call
const obj = {
name: "老王",
skill() {
console.log(this.name + " 翻墙");
},
};
const person = {
name: "大郎",
};
// call 方式来修改this的指向
obj.skill.call(person); // 大郎 借用老王的方法
②apply
const obj = {
name: "老王",
skill() {
console.log(this.name + " 翻墙");
},
};
const person = {
name: "大郎",
};
// apply 方式来修改this的指向
obj.skill.apply(person); // 大郎 借用老王的方法
③bind
const obj = {
name: "老王",
skill() {
console.log(this.name + " 翻墙");
},
};
const person = {
name: "大郎",
};
// bind 方式来修改this指向
// bind 不会直接调用skill函数 而是 返回一个新的函数
// 需要我们主动的调用新的函数- 调用skill()
const func = obj.skill.bind(person);
func();
(2)bind call apply 都可以修改this的指向-总结
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)传递参数的时候不同写法上 (下一节课再来讲解)
4.bind-call-apply传递参数
(1)传递参数1
const obj = {
name: "老王",
skill(a, b) {
console.log(this.name + " " + a + " " + b);
},
};
const person = {
name: "大郎",
};
// obj.skill.call(person, 1, 2); // 传参
// obj.skill.apply(person, [1, 2]); // 数组
const func = obj.skill.bind(person);
func(1, 2); //
(2)传递参数2
// const max = Math.max(1, 2, 3, 4);
// console.log(max);
// const arr = [1, 2, 3, 4];
// 借用 Math.max方法 目的不是修改this指向
// 而是 计算数组最大值
const arr = [1, 2, 3, 4];
console.log(Math.max(...arr));
(3)传递参数3
①obj.skill.call(person,参数1,参数2)
②obj.skill.apply(person,[参数1,参数2])
③const func = obj.skill.bind(person);
func(参数1,参数2)
5.箭头函数-this指向(在js中,顶级的对象 就是window)
(1)在js中,顶级的对象 就是window1
// 定义一个函数 形式是箭头函数的
// const func = () => {
// console.log(this);
// };
(2)在js中,顶级的对象 就是window2
// const obj = {
// name: '悟空',
// say: () => {
// console.log(this);
// },
// };
obj.say(); // window
(3)在js中,顶级的对象 就是window3
// const obj1 = {
// name: '悟空1',
// obj2: {
// name: '悟空2',
// say: () => {
// console.log(this);
// },
// },
// };
// obj1.obj2.say();
(4)在js中,顶级的对象 就是window4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
/>
<title>06-箭头函数-this指向.html</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
</head>
<body>
<button>点击我 我就改变颜色</button>
<script>
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>
</body>
</html>
(5)总结
① 大部分情况,对于普通函数,this 等于这个函数的调用者(例外 - bind、call、apply)
②大部分情况,对于箭头函数,this 等于window;箭头函数和this 一起用的话,要慎用!!
例外(面向对象用法,)
三、es5和es6
1.es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。
2.es5和es6面向对象区别
(1)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>
(2)es6面向对象
<body>
<script>
// es6 面向对象 引出新的语法 类 class
class Person {
// 方法 constructor 在es6 构造函数
// constructor 会在 new Person的时候触发
constructor(name) {
// console.log("开始创建对象啦");
this.name = name;
}
// 直接写行为
say() {
console.log("say方法被调用啦 " + this.name);
}
}
// 一样new一个对象
const p1 = new Person("悟空1");
const p2 = new Person("悟空2");
// console.log(p1);
// p1.say();
console.log(p1.say === p2.say);
// 属性
// 行为
class SuperMan {
constructor() {
// 对象有什么属性都写在 这里
this.name = "超人";
this.color = "blue";
}
// 行为
say() {
console.log("说话");
}
fly() {
console.log("会飞");
}
sing() {
console.log("唱歌");
}
}
// es6 继承写法 稍后会讲解
</script>
3.es5和es6继承
(1)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>
(2)es6继承
<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>
4.es6-案例
(1)使用es6的class 实现以下功能
①父类 Element
class Element {}
②属性 this.dom
this.dom = dom;
③方法 append
append(parentSelector) {}
(2)定义两个子类 都要继承父亲的属性和方法
①ElementDouble
class ElementDouble extends Element {}
②ElementSingle
class ElementSingle extends Element {}
③然后 通过编写代码 把以下程序运行起来
<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/01.jpg");
imgModel.append("div");
</script>
5.es6-class和箭头函数
<script>
// 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);
</script>
6.es6-三种定义方法的写法-最优
<script>
class Person {
// 性能最好 推荐方式!!
say1() {
console.log("say1");
}
say2 = function () {
console.log("say2");
};
say3 = () => {
console.log("say3");
};
}
const p1 = new Person();
const p2 = new Person();
p1.say1();
p1.say2();
p1.say3();
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方法不是同一个-性能不好
</script>
7.es5-原型链
<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>
<script>
/*
原型链
一个对象 它可以通过 prototype 来 找到被它继承父亲的方法
如果一个对象从底层触发 可以通过 prototype 一层一层往上找到 继承的关系 = 原型链
// 作用
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=[];
// js 真垃圾 !!
// DNA 存在于你整个家族 不只是父亲和儿子
Array.prototype.forEach = function () {
console.log("老子罢工了");
};
Array.prototype.map = function () {
console.log("老子罢工了");
};
const arr = [1, 2, 3];
arr.forEach(); // forEach 循环 到了你这个项目 这个知识用不了
// 对于新入门小小员工来说 毁灭性的打击
// 10多年代码 用不上 心态。。。。
// arr.map()// 以前我学都是啥 想不开 你要有责任!!
</script>