JS高级 第三天
一、set数组去重
<script>
const beforeArr = [`a`,`b`,`c`]
const set = new Set(beforeArr)
set.add(1)
set.add(2)
set.add(2) // 发现重复 内部自动过滤
console.log(set);
const arr = [...set] // 把set 转换成数组
console.log(arr);
</script>
运用set进行数组去重案例
<script>
let ul = document.querySelector(`ul`)
let inp = document.querySelector(`input`)
let arr = [`文本1`, `文本2`]
render()
inp.addEventListener(`keydown`, function (e) {
if (e.key === `Enter`) {
let set = new Set(arr)
set.add(inp.value)
arr = [...set]
render()
}
})
function render() {
let lis = arr.map((Value) => `<li>${Value}</li>`).join(``)
ul.innerHTML = lis
}
</script>
总结:
1.set方法,用new调用
2.set是对象,需要转换成数组
二、this指向
普通函数 this
<script>
function func() {
console.log(this);
}
func() // this 指向winodw 这是一个定义在全局变量的函数 window.func1()
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);
</script>
箭头函数 this
<script>
const func1 = () => {
console.log(this);
}
func1()
const obj1 = {
name:`悟空`,
say:()=>{
console.log(this);
}
}
obj1.say()
const obj2 = {
name:`悟空`,
obj3:{
name1:`悟空2`,
say:()=>{
console.log(this);
}
}
}
obj2.obj3.say()
const button = document.querySelector(`button`)
button.addEventListener(`click`,function(){
console.log(this); // this 指向 button
})
button.addEventListener(`click`,()=>{
console.log(this); // this 指向 winodws
})
</script>
总结(大部分情况):
1.普通函数 this等于函数调用者
(例外:bind call apply)
2.箭头函数 this等于window
(例外:面向对象中用法 存在例外)
3.箭头函数和this 一起用要慎用!!!
三、call,apply,bind
三种方式修改this的区别
<script>
const obj = {
name:`老王`,
skill(){
console.log(this.name+` 翻墙`);
}
}
const person = {
name:`大朗`
}
obj.skill.call(person) // call 修改this指向 大朗借用了老王的方法
obj.skill.apply(person) // apply 大朗借用老王方法
const func = obj.skill.bind(person) // bind 不会直接调用skill方法 而是返回一个新的函数
func() // 主要调用新函数 - 调用skill()
</script>
三种方式传递参数的区别
<script>
const obj = {
name:`老王`,
skill(a,b){
console.log(this.name+``+a+``+b);
}
}
const person = {
name:`大朗`
}
obj.skill.call(person,1,2) // 之前所学call借调方法
obj.skill.apply(person,[1,2]) // apply 传递参数 必须用数组形式
const func = obj.skill.bind(person)
func(1,2) // 在新的函数上直接传参
</script>
总结:
1.bind call apply 都可以实现 修改this指向
2.注意使用上代码的区别,bind需要返回一个新的函数再调用
3.传递参数上代码的区别:apply传参要用数组类型,bind在调用的新函数内传参
以前使用apply 计算数组最值方法
<script>
const arr = [1,2,3,4,5]
// null this是第一个参数 这里不需要修改this 所以传入null
let max = Math.max.apply(null,arr)
console.log(max);
</script>
四、es6面向对象
es5-es6区别
<script>
function Person(name) {
this.name =name
}
Person.prototype.say = function(){
console.log(this.name+`调用`);
}
const p1 = new Person(`悟空`)
console.log(p1);
p1.say()
</script>
<script>
class Person{
// 指构造函数=es5 Person内区域
constructor(name) {
this.name = name
}
//行为 如同原型对象,行为 = person.prototype.say
say(){
console.log(this.name+`调用`);
}
}
const p1 = new Person(`悟空1`)
const p2 = new Person(`悟空2`)
console.log(p1,p2);
console.log(p1.say===p2.say); // true 不浪费内存
</script>
总结:
1.es6通过一个关键字 class 来确定
2.属性行为都写在这个class方法内
3.class是方法,不是对象 不用逗号隔开
继承区别
<script>
function Person(name) {
this.name = name
}
Person.prototype.say = function(){
console.log(this.name+`调用`);
}
Person.prototype.fly = function(){
console.log(this.name+`起飞`);
}
function Son(name,color) {
Person.call(this,name)
this.color = color
}
Son.prototype.say = Person.prototype.say
Son.prototype.fly = Person.prototype.fly
const s1 = new Son(`儿子`,`red`)
console.log(s1);
s1.say()
s1.fly()
</script>
<script>
class Person {
constructor(name){
this.name = name
}
say(){
console.log(this.name+`调用`);
}
fly(){
console.log(this.name+`起飞`);
}
}
//extends 就表示 继承
class Son extends Person {
// 如果写了构造和extends必须加super 不加super 报错 Must call super
constructor(name,color){
super(name) // 父亲的构造函数 = Person.call(this,name)
this.color = color
}
}
const s1 = new Son(`儿子`,`red`)
console.log(s1);
s1.say()
s1.fly()
</script>
总结:
1.es6中继承注意写extends不写constructor 就不需要写super
2.如果写了extends还写了constructor 就必须写super
3.super()=Person.call(this,name)
es6继承封装案例
<script>
class Element {
constructor(dom) {
dom = document.createElement(dom)
this.dom = dom
}
append(ParerntSelect) {
document.querySelector(ParerntSelect).appendChild(this.dom)
}
}
class ElementDouble extends Element {
constructor(dom, text) {
super(dom)
this.dom.innerText = text
}
}
class ElementSingle extends Element {
constructor(dom, src) {
super(dom)
this.dom.src = src
}
}
const divModel = new ElementDouble(`div`, `文字内容`)
divModel.append(`body`)
const imgModel = new ElementSingle(`img`, `./img/01.jpg`)
imgModel.append(`div`)
</script>
对比es5封装
<script>
function Element(Node) {
const dom = document.createElement(Node)
this.dom = dom
}
Element.prototype.append = function (ParentNode) {
document.querySelector(ParentNode).appendChild(this.dom)
}
function ElementDouble(Node, text) {
Element.call(this, Node)
this.dom.innerText = text
}
ElementDouble.prototype.append = Element.prototype.append
//儿子二 构造的函数
function ElementSingle(Node, src) {
Element.call(this, Node)
this.dom.src = src
}
ElementSingle.prototype.append = Element.prototype.append
const divModel = new ElementDouble(`div`, `文字内容`)
divModel.append(`body`)
const imgModel = new ElementSingle(`img`, `./img/01.jpg`)
imgModel.append(`div`)
</script>
es6补充-es5原型链
<script>
class Person {
constructor(name) {
this.name = name
}
// 写法二 无区别
color = `yellow`
height = 180
weight = 200
say() {
console.log(this.name + `调用`);
}
tall = function () {
console.log(this.color+`写法二`);
}
// this配合箭头函数 大多数情况指向winodw 这里配合面对对象是例外
make =()=>{
console.log(this+`这里this指向调用者`);
}
}
const p1 = new Person(`悟空1`)
const p2 = new Person(`悟空2`)
p1.say()
p1.tall()
p1.make()
console.log(p1.say === p2.say); // true
console.log(p1.tall===p2.tall); // false
console.log(p1.make===p2.make); // false
</script>
总结:
1.属性定义写在构造函数内 this.name = name
2.属性定义写在大括号内 name = “悟空”
3.方法写法1:say(){}
4.方法写法2:say=function(){}
5.方法写法3:say=()=>{}
6.箭头函数中this例外情况,用在es6的calss充当方法 this 指向 p1 实例
7.方法写法1性能最好,其余会有占内存浪费性能问题
原型链本质:
一个对象,可以通过prototype来找到被它继承父亲的方法
一个对象从底层触发,通过prototype 一层一层 往上找到继承的关系
原型链作用:
需要给某个数据(字符串,数组,对象) 统一添加一个方法,可以直接在原型上添加,这样就可以复用
<script>
// 万物皆对象 这样这个方法就会在对象原型内,可以复用
Object.prototype.show = function(){
console.log(`我创的`);
}
// 数组也是可以被new 的
const arr = new Array(`a`,`b`,`c`)
// 也就代表,JS内置的数组可以使用原型
Array.prototype.show = function(){
console.log(`爷自创`);
}
arr.show() // 所以arr就调用这个方法 arr.push arr.map 等方法都是如此。
console.log(arr);
// 对象的创建也分两种清空
// const ojb={};// 字面量 常用 直接 简单
const obj = new Object(); // 利用构造函数的方式来创建对象
Object.prototype.show = function () {
console.log('对象 自己的show方法');
};
obj.show();
console.dir(document.querySelector(`div`))
</script>
总结:
1.可以利用原型对象的方式,在任意的构造函数上添加想要的行为
2.任意的构造函数 包括自己定义的构造函数
3.也包括JS内置就有的构造函数 Array等 (arr.push();arr.map()....)
4.如果改了内置构造函数的原型对象上的行为(方法),后果很严重!!
<script>
Array.prototype.forEach=function(){
console.log("老子罢工了");
}
Array.prototype.map=function(){
console.log("老子罢工了");
}
const arr=[1,2,3];
arr.forEach(); // 不能正常使用了 被修改为如上
</script>
Ajax
一、服务器
本质:当我们上网看到的内容,在网络中的一台电脑上,这台电脑叫服务器。
作用:存储一个网站的文件(HTML css js 图片。。。)
1、资源:
本质:服务器上的网页、图片等文件都称为资源,资源代指服务器上存储的内容。通俗讲我们从网络上看到的内容都叫资源
2、数据
本质:网页中的数据,也是服务器对外提供的一种资源。
服务器多数情况都使用数据表方式存储数据
3、客户端
本质:前端开发中,客户端特指Web浏览器
作用:将互联网中的Web资源加载,并且呈现到浏览器给用户使用
前端其实也就是围绕客户端做操作
4、资源与URL地址
本质:表示服务器上每个资源的确切位置,每个资源对应独一的URL地址
作用:对数据操作(增删改查),也对应不同URL地址(不能搞混)
5、客户端与服务器通信
本质:
请求:客户端通过网络找到服务器要资源的过程
响应:服务器把资源通过网络发送给客户端
6、Ajax
本质:Ajax是浏览器中的技术,实现客户端网页请求服务器的数据
使用场景:
总结:
1.服务器本质就是一台电脑
2.前端开发中,客户端指浏览器
3.网页中资源存储在服务器中
4.URL对服务器数据操作需要找到对应的URL地址
5.请求是由客户端发送的,响应是由服务器做出的
6.有数据的地方就有Ajax,数据是网页的灵魂
二、请求方式
1.同步-异步
<body>
<h1></h1>
<h2></h2>
<script>
// 同步执行的代码 按顺序 马上得出结果
console.log(document.querySelector(`body`));
console.log(document.querySelector(`div`));
// 异步执行的代码 虽然是0 输出 1 3 延时器
console.log(1);
setTimeout(() => {
console.log(`延时器`);
}, 0)
console.log(3);
setInterval(() => {
document.querySelector('h1').innerText = Date.now();
}, 10);
setInterval(() => {
document.querySelector('h2').innerText = Date.now();
}, 10);
</script>
</body>
总结:
1.同步代码结果会马上得到,按顺序一件一件做事(核酸排队)
2.异步代码结果不会马上得到,可以同时做多件事(三个大妈共同输出吵架)
2.Ajax请求数据5种方式
总结:
1.操作服务器数据除了使用URL,还需要指定请求方式
2.根据操作性质不同,请求的方式也不同
三、基础用法
axios
本质:专注于数据请求的库
语法:
<script>
axios({
method:`get`,
// 直接问后端要 我们只负责用对代码 然后请求成功
url:`http://www.itcbc.com:3006/api/getbooks`
// then 是axios封装的一个代码 服务器把数据返回,里面的代码就会触发
// result 是一个形参 任意改
}).then((result)=>{
// 别人怎么定义 我们就怎么拿 因为这里底层套了两层data
const arr = result.data.data // 数据里的 id bookname 等是固定的
console.log(arr);
render(arr)
})
function render(arr) {
let html = arr.map((value)=>`<tr>
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
</tr>`).join(``)
document.querySelector(`tbody`).innerHTML = html
}
</script>