基础知识点

98 阅读14分钟

什么是JS

为什么有js呢首先是为了对网页交互,还有一个原因是节省从客户端到服务器数据传输的时间才出现了这门语言,这门语言运行在浏览器上,将结果传到数据库就再返回就可以了--总的来说就是为了提升用户体验感;然后别人看网景公司这种解决方案很好,就模仿代码给自家浏览器模仿去写,就导致了每个浏览器都需要程序员写一份代码(兼容性),很苦逼,就有了ECMA公司后面统一语法标准--也就是ECMAScript

Js是一门单线程语言,也是-支持面向对象的跨平台脚本语言-使用一个内存空间运行代码-同一时间只能执行一行代码--(结合同步异步一起看)

进程:类似任务管理器,有很多进程,每个进程(软件)都会占用CPU和内存--就是内存中预留的空间,用来运行软件的-就是一块内存空间-假如一个进程空间最小是是4kb,一个软件是1kb,那这个软件也要占用4kb,就会造成浪费,为了节省内存就出现了线程

线程:比进程更小的空间

脚本语言:依赖别的语言才能运行,html必须在浏览器中才能运行,JS嵌套在html中才能运行

跨平台:可以在不同平台上运行-windows;linux;安卓等

支持面向对象 :使用面向对象的思想编程

js的三种写法

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JS的三种写法</title>
</head>
<body>
  <!-- 行内写法 -->
  <button onclick="alert(456)">按钮</button>
</body>
<script src=".js/外联写法.js"></script>
<script>
  // 内联写法
  alert(123);
</script>
</html>

JS的输出

让浏览器展示指定内容,有5中方式

1.弹窗
alert(123显示具体的内容);
一般做为提示使用

2.将内容显示在body中
document.write(内容)
动态控制body中的内容

3.以弹窗的形式询问用户是否继续
confirm(内容)

4.以弹窗的形式让用户输入
prompt(提示信息)

5.在控制台调试
console.log(内容)

变量

变量就是计算机内存中存储数据的容器-类似于碗var

同步异步

同步:一行代码要执行,必须等待上一行代码执行结束,才能进行 - 简单说就是要等待-会影响用户体验

异步:两行代码同时在执行-跳过了等待的时间去一起执行

异步代码具体过程:Js是单线程语言,本身和异步代码是冲突的,但是Js中有异步代码,具体原理是一次将同步代码执行,当碰到异步代码时,Js暂时不执行,将异步代码交给浏览器处理--浏览器是多线程软件-其中有一个线程叫webAPI,用来专门处理Js异步代码-等待时间

demo

<script>
  //同步:代码要等待上一行代码结束,然后再执行
  // console.log('你好JS');
  //异步:不等上一行,先执行,互不干扰

  setInterval(function(){//异步-Js解析代码时,遇到这个异步代码后,将这个异步代码交给浏览器
    console.log(1);
  },1000)//浏览器拿到这个异步代码后,等待1s到了,将需要执行的代码放在一个队列中,让需要执行的代码等待,等JS将当前线程的代码执行完毕后,JS来到这个队列中查看,拿出一部分代码放到线程中执行
  //共三方-JS单线程-队列-浏览器
  //浏览器觉得需要执行了就丢到队列中排队,JS单线程执行完当前任务后就去队列中拿一个线程的任务执行--类似去去吃饭排队叫号,每个桌子(餐号)就是一个线程,但是餐厅只有一个桌子╮(╯▽╰)╭
  
  for(var a = 1;a<100;a++){//同步
    console.log('for循环次数'+a);
  }
  console.log(2);//同步-然后立马执行这句代码

  //结论:异步代码一定会在所有同步代码执行结束之后才会执行,定时器的时间其实是并不精准的
</script>

为什么有BOM-DOM-ECMAScript

根本原因是浏览器过多-各个浏览器仿造JS语言产生各自浏览器的脚本语言-导致程序员开发时比较苦逼,后来ECMA公司-欧洲的一个啥协会把大家约在一起对所有语言进行了统一--就是把JS语言划分为三个标准

标准

1语法标准-所有语言在进行运算时,或者说在定义变量时,标准都是一样的,写法都是一样的。ECMAScript-描述了Js语言的基本语法、数据类型的标准

2BOM--操作浏览器标准。浏览器对象模型操作网浏览器的一系列方法

3DOM--操作文档标准。文档对象模型操作网页元素的一系列方法

BOM-操作浏览器-browser object model - 浏览器对象模型

模型例如飞机模型-不管是用什么材质做的,看起来像飞机那就是飞机模型,还比如-手机模型,汽车模型等---跟材料无关,指的是一种结构

对象模型用对象组成的结构(用对象组成的)

浏览器对象模型使用对象组成的结构对浏览器进行操作

具体解释: image.png

首先,操作浏览器的对象叫window,浏览器的所有操作都是由window完成的。但是浏览器的操作有很多,这些操作都让window操作负担太大,所以在window中就有了子对象--

navigator-用来记录浏览器信息的对象;

history-历史记录-用来操作页面前进和后退;

location操作浏览器的地址栏-刷新/跳转;

document操作文档

还有其他子对象-其他方法-其他属性--不常用例如获取浏览器宽高等

DOM-操作html文档--重点

网页上所有的动态效果都是由Dom操作完成的

全称: Document object model ==> 文档对象模型 ==>用一套对象组成的模型来操作文档

文档:html文档--(写得html结构就是html文档)

Dom的学习就是学习如何使用js的对象结构操作html文档

html文档都是由标签组成的,dom就是在学习如何用js操作标签

标签的组成:标签名;内容;属性;样式;大小;位置;子标签;父标签;兄弟标签;类名

Dom-获取标签

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<style>
  #var{
    border: 10px solid red;
  }
</style>
<body>
  <ul id="var" class="uu">
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body>
<script>
  //可以使用id名来获取标签,id名可以代表这个标签,但是它有缺陷,不能使用关键字。不影响修饰样式
  //为了避免关键字情况,无论它的id名是什么,我们都要能获取到才行

  //获取标签--id
  //window.document.querySelector(css选择器) --返回满足选择器的第一个标签
  var ul = document.querySelector('#var')//使用字符串获取id
  console.log(ul);//控制台输出ul标签 
  
  //获取标签--class
  var ul = document.querySelector('.uu')//使用字符串获取class
  console.log(ul);//在控制条输出ul标签

  //获取标签--标签名
  var ul = document.querySelector('ul')//使用字符串获取标签名
  console.log(ul);

  //获取标签--后代li
  var li = document.querySelector('ul li')//使用字符串获取li-但是这样写只能获取第一个

  //如果想一次性获取多个相同标签,就需要使用document.SelectorAll(css选择器)
  var lis = document.querySelectorAll('ul li')
  console.log(lis);//获取到集合--所有满足条件的都获取到了 

  //这个获取到的集合,有长度,有下标,所以也可以遍历
  for (var a = 0;a< lis.length ;a++){ 
    console.log(lis[a]);//遍历输出lis
    //添加事件
    lis[a].onclick = function(){
      console.log(666);
    }
  }
</script>
</html>

了解其他获取标签方法

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<style>
  #var{
    border: 10px solid red;
  }
</style>
<body>
  <ul id="var" class="uu" name="myul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body>
<script>
  document.getElementById('ID名')
  console.log(document.getElementById('var'));//使用这个方法不用加#
  //这个方法也是只能获取到第一个满足条件的标签,假如下面还有其他带有相同id-var的标签获取不到

  document.getElementsByClassName('类名') //- 只要标签有这个类名就都可以获取到
  //因为类名在页面中就不是唯一的了-获取的就是集合
  console.log(document.getElementsByClassName('uu'));//这样是集合,需要确定下标才能获得具体的
  console.log(document.getElementsByClassName('uu')[0]);

  //document.getElementsByTagName('标签名')
  console.log(document.getElementsByTagNameNS('ul'));//使用标签名获取的也是集合,也需要具体下标
  console.log(document.getElementsByTagNameNS('ul')[0]);

  //document.getElementsByName('name属性的值')
  console.log(document.getElementsByName('myul'));//也是集合
</script>
</html>

获取html基本结构标签

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<style>
  #var{
    border: 10px solid red;
  }
</style>
<body>
  <ul id="var" class="uu" name="myul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body>
<script>
  //获取到html标签
  console.log(document.documentElement);
  
  //body标签
  console.log(document.body);

  //head标签
  console.log(document.head);

  //网页标题
  console.log(document.title);//获取标题
  document.title = '这是我的网页,我修改我的标题'//设置网页的标题

</script>
</html>

回流和重绘

window对象

window不需要定义,因为浏览器中本来就有这个对象,直接console.log(window);在浏览器就会打印这个对象,里面有很多方法/属性/子对象--不带f的就是对象,例如document,history,location等;--带f的是方法,例如定义的函数等

全局中的this代表window

window代表浏览器窗口,window代表全局

<script>
  //我定义a = 10 之后, 打印的window就有a:10 ;我定义b = 20; 打印window就有 b = 20;
  var a = 10;
  var b = 20;
  console.log(window);
  //我们在全局中定义的变量其实就是window的属性
  console.log(a);
  console.log(window.a);//console.log(a);的完整写法╮(╯-╰)╭
  //我们在全局中定义的函数其实就是window的方法
  function a(){}
  console.log(window);
  a()
  window.a()//调用a()的完整写法

  //为什么可以这样呢?因为我们全局中所有的变量和函数都需要使用window, 甚至其他子对象使用的时候也需要使用window
  //既然所有的操作都需要用window, 为了简便,我们就可以省略window
</script>

this关键字

假如点击每一个<li></li>想获取到当前<li>的内容,如果没有this关键字,就只能自调用函数外面套一层,然后实现下标,如果使用this就可以让代码变得更简单,比如↓

<body>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body>
<script>
  //点击每个<li>,输出<li>的内容,用this,就可以↓
  var lis = document.querySelectorAll('li')//先获取所有li
  for (var a = 0; a<lis.length;a++){//遍历他
        lis[a].onclick = function(){
          console.log(this.innerText);//输出内容1/2/3
        }
  }
</script>

this关键字,在任何位置都可以使用,在不同位置代表的含义是不同的,比如console.log(this)就会输出window,也就是全局,如果跑到事件中就会有所不同

全局中

this关键字默认代表window

局部--函数内

普通函数--window---(递归函数中也属于普通函数)

<script>
  function fn(){
    console.log(this);
  }
  fn()//使用函数名()调用的这种函数就叫普通函数--代表window
  function fun(){
    fn()
  }
  fun()//在这个函数中调用fn,代表的也是--window,因为是当作普通函数调用的
</script>
递归函数demo
<script>
  function factorial(n) {
      if (n === 0) {
        return 1;  // base case, 阶乘的终止条件
      }
      return n * factorial(n - 1);  // 递归调用自身
    }
    console.log(factorial(5));  // 输出 120
</script>

自调用函数--window

<body>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body>
<script>
  (function(){//自调用函数中this代表的也是window
    console.log(this);
  })() 

  document.querySelector('ul').onclick = function(){
    (function () {//在点击事件中放自调用函数,this代表是也是--window
      console.log(this);
    })() 
  }
</script>

事件函数 - 事件源 - 标签

<script>
  function fn(){
    console.log(this);
  }
  //这里的this代表的就是-事件源 - 也就是标签ul
  document.querySelector('ul').onclick = fn //fn代表是事件函数
</script>

对象的方法- 当前对象

<script>
  function fn(){
    console.log(this);
  }
  var obj ={//定义一个对象
    name:'张三',
    eat:fn
  }
  obj.eat()//如果是在对象的方法中调用函数-那这个this就代表obj这个对象了
</script>

定时器函数 - window

<script>
  function fn(){
    console.log(this);
  }
  setTimeout(fn,1000)//定时器1秒后执行,fn函数的this代表window
</script>

总结

全局:window

普通函数 + 自调用函数 + 定时器函数:window

事件函数: 触发事件的标签

对象方法: 当前对象

this的理解

死记硬背的:

全局this:window

对象方法:对象

可以理解的

普通函数的this

<script>
function aaaaa(){
  console.log('定义的函数'+this);
}
// console.log(window);//定义的函数会出现在window中,而调用定义的函数的全称为window.aaaaa(),也就等同于aaaaa()调用,所以普通函数的this代表window
window.aaaaa()
</script>

定时器函数中的this

<script>
//定时器函数属于window的方法,所以全称为↓
window.setTimeout(function(){
  console.log(this);
},1000)
</script>

自调用函数的this

<script>
//自调用函数如果有名字,那么他的第一个括号就代表他的名字--()() == fn()
(function (){//这里的function后没有名字是因为他本身就代表了他的名字
  //所以自调用函数其实也就是匿名函数,如果自调用函数有名字,那他其实就是普通函数的调用方式,
  //所以自调用函数和普通函数是一样的,都代表window
  console.log(this);
})()
function fn(){//普通函数
  console.log(this);
}
</script>

事件函数的this

<script>
//事件函数
//为什么事件函数的this可以代表标签,因为事件绑定的语法,相当去给document对象添加了方法onclick,所以对象方法中的this就代表这个对象
document.onclick = function(){
  console.log(this);//document
}
</script>

ES6

let

const

Promise

export default - 导出默认成员

回调函数

当一个函数被当作参数使用的时候,这个函数就叫做回调函数

回调函数的使用意义:在一个异步函数外,无法预知其中的异步代码什么时候结束,如果我们希望在异步函数结束后执行一段同步代码,就只能同步代码放在一个函数中,当作参数,将函数参数交给异步代码后,在其内部,当异步代码结束后,调用函数参数。只有在函数内部才知道异步代码什么时候结束。简答说就是让部分同步代码在异步代码结束后执行.

比如在封装的--动画函数;分页插件;防抖节流函数;ajax函数中都有用到

回调地狱

在一些比较复杂的业务逻辑中,有多个异步代码需要按照一定的顺序执行时,就需要有多个回调函数嵌套在一起执行,这就造成了后期这个代码难以维护。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>111</title>
</head>
<style>
  .box{
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    left: 0;
    top: 0;
  }
</style>
<body>
  <div class="box"></div>
</body>
<script src="./utils.js">
  //这里是自己封装的动画函数
</script>
<script>
//回调地狱demo
const box = document.querySelector(".box")//获取这个div
box.onclick = function(){//给这个div添加点击事件
  // animate(box,{//这里需要调用之前自己封装的animate()动画函数
  //   left:800
  // })
  // animate(box,{//如果希望先往右800再执行这里的往下300,就不能这样写,因为这两个函数会同时执行,因为这两个调用的函数是异步的,是不堵塞的
  //   top:300
  // })
  

  //所以想达到我预期的顺序效果,就需要将第二步执行的函数放在第一段代码的回调函数中进行
  animate(box,{//这里需要调用之前自己封装的animate()动画函数
    left:800
  },()=>{
    animate(box,{
      top:300
    },()=>{
      animate(box,{
        left:400
      },()=>{
        animate(box,{
          top:150
        })
      })
    })
  })
}
//在我的函数中,虽然达到了预期的效果,但是代码会无限嵌套下去,就造成了回调地狱
</script>
</html>

Promise--ES6提供,专门解决回调地狱

将回调地狱的嵌套代码,改成链式操作

Promise的语法

<script>
  new Promise(function(resolve,reject){//new之后,就得到了promise对象
    //  promise对象.then(function(){
    //    then当中的函数,是当上面的resolve调用后会执行
    //  })

    //  promise对象.catch(function(){
    //    catch当中的函数,是当上面的reject调用后会执行
    
    //  })

    
    //在这里可以调用resolve/reject这两个参数,二选一,会执行对应的then/catch函数
    //通常要执行的操作就放在这里
    //resolve-then的语意是-成功
    //reject-catch的语意是-失败--在不符合语意的场景使用也能执行成功(功能相同),但是会有报错
  })
</script>

在类似回调地狱demo中展示

<style>
    .box{
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    left: 0;
    top: 0;
  }
  </style>
</head>
<body>
    <div class="box"></div>
</body>
<script src="./utils.js"></script>
<script>
  const box = document.querySelector(".box")//获取这个div
  box.onclick = function(){
    let p1 = new Promise(function(resolve,reject){
      animate(box,{
        left:600
      },()=>{
        //按照回调地狱的demo,这里本来该放另一段代码
        //但现在是在Promise中,所以我们直接调用resolve/reject
        resolve()//调用resolve就相当于调用then中的函数
      })
    })

    p1.then(function(){
      console.log('执行在p1中resolve()位置调用的then函数')
      animate(box,{
        top:200
      })
    })
  }
</script>

Promise的链式操作 day27

Promise发送ajax

Promise封装ajax

Promise的静态方法

ASYNC/AWAIT

async-await的语法

awync-await解决回调地狱

awync-await让多个请求按照顺序执行