本文件已定稿,最后修改时间 20240613 1:41


1、什么是JavaScript

“弱类型”的脚本语言

基于”原型”的脚本语言

2、JavaScript的构成

ECMAScript:核心语法、基本对象

DOM:文档对象模型

BOM:浏览器对象模型

3、JavaScript的输出语句

document.write() 在文档中打印内容 ,要用引号包起来

console.log() 在控制台打印内容

4、如何延迟加载js:defer

<script type="text/javascript" defer src='路径'></script>

defer:js脚本可以延迟到文档完全被解析和显示之后执行

5、如何异步加载js:async

<script type="text/javascript" async src='路径'></script>

async:立即执行脚本,但不妨碍页面其他的操作

简单粗暴:谁加载完了谁执行

6、js中的变量

命名规则:

  • 首位:字母、下划线、$
  • 严格区分大小写
  • 采用驼峰命名(第二个单词开始之后每一个单词首字母开头大写)
  • 声明变量:var

注释:

  • 公共的js文件

    /**
    *文件用途说明
    *作者姓名、联系方式
    *制作日期
    **/
  • 大的模块注释方法

    //====================
    // 代码用途
    //====================

7、规范

  1. 单引号优先(如果不是引号嵌套,不要用双引号)
  2. 变量命名:
    1. str、num、bol、obj、fun、arr:作用域不大的情况
    2. 循环 i、j、k

一、数据类型

  1. 基本数据类型

    string:字符串,基本上加入引号的都是字符串类型

    number:数值

    boolean:布尔

    undefined:未定义,表示缺少值,应该有一个值,但是还没有赋值

    null:表示没有对象,即该处不应该有值,特殊的object

    区别

    null表示无对象,把他转化成数值是0

    underfined表示”缺少值”,把他转换数值是NaN

  2. 引用数据类型【array、function】

    object

二、数据类型的转换

  1. 其他类型转【字符串类型】

    数据.toString()

    String(数据)

  2. 其他类型转【数值类型】

    Number(数据)

    parseInt(数据) => 整数

    parseInt(数据) => 小数

    字符串不是纯数字的都是NaN

    NaN【数值类型】:属性,代表非数字值得特殊值

  3. 其他类型转【布尔类型】

    Boolean(数据)

    数值:0—false、NaN—false、其他值—true、

    字符串:非空字符串—true、空字符串—false

    null—false、underfined—false

三、变量的存储机制和原理

  1. 内存生命周期(三个周期)
    1. 分配器:分配所需内存
    2. 使用期:读、写
    3. 释放期:不需要时将其释放
  2. JavaScript内存的生命周期
    1. 内存分配:分配所需要的暂时使用的内存大小
    2. 内存使用:读、写内存
    3. 内存回收:对于不需要使用的内存将其释放
  3. 栈内存、堆内存
    1. 栈内存:
      1. 基本类型(string、number、boolean、undefined、null)
      2. 按值访问
      3. 存储大小固定
      4. 系统会自动分配内存空间
      5. 空间小,运行效率高
      6. 先进后出
    2. 堆内存:
      1. 引用类型(object)
      2. 按引用访问
      3. 存储大小不固定
      4. 由代码进行指定分配
      5. 孔金阿达、运行效率相对较低
      6. 无需存储(根据引用直接获取)

四、数据类型隐式转换

  1. 布尔和数字或者纯布尔相加(+),布尔会自动转换成数值类型
  2. 字符串和任何类型(+),其他类型都会转换成字符串

五、函数

  1. 函数的定义

    1. 函数声明:

      语法格式:

      function 函数名(){
      函数体
      }
    2. 函数表达式:

      语法格式:

      var 变量名 = function(){

      }

区别:

​ 函数表达式:函数只能在声明之后调用,因为这种方式的函数,是在函数运行的阶段赋值给变量的

​ 函数声明:函数可以在声明函数的作用域任意范围内调用,因为这种方式,是在函数解析阶段赋值给函数名

  1. 函数的调用【使用】

    函数表达式或者函数声明是不能自己执行的,需要调用才可以执行

    调用:函数名()

  • 函数如果没有调用,则不会保存在内存中
  • 当函数调用完毕,其中函数的代码就会被系统内存回收
  1. 函数的参数

    function fun(形参1,形参2,形参3...){

    }
    fun(实参1,实参2,实参3...)
  2. arguments对象

    作用:就是操作实参

    arguments.length 就是实参的个数【长度】

  3. 匿名函数【没有名字的函数】

    匿名函数立即执行

    (function(){

    })
    1. 匿名函数的自我执行

      (function(形参1,形参2...){

      })(实参1,实参2...)

六、Js执行环境

  1. 什么是执行环境

    执行环境又被称为:执行上下文

    执行环境定义了变量或者函数有权或无权访问其他数据,决定了各自的行为

  2. 执行分类(3大类)
    1. 全局执行环境
      1. 是最外围的执行环境、在页面中,全局执行环境就是window对象
      2. 当一打开页面,会自动生成window对象,那么全局的变量或者函数都属于window对象的内容。那么window就是全局的。
      3. 回收机制:
        1. 某个执行环境中的所有代码执行完毕,保存在执行环境中的变量或者函数都会进行销毁(回收)
        2. 但是全局执行环境是到关闭浏览器或者当前页面才会被回收
    2. 函数的执行环境
      1. 当某个函数被调用时,首先会创建一个执行环境以及作用域链,然后使用arguments和其他参数来初始化这个执行环境
  3. 执行环境的生命周期
    1. 创建阶段

      1. 生成变量对象
      2. 建立作用域链
      3. 确定this指向
    2. 执行阶段

      1. 变量赋值
      2. 函数调用
      3. 执行其他代码
    3. 销毁阶段

      // 第一次页面加载创建全局执行环境
      // 先到创建阶段---->扫描全局的变量以及函数
      // 扫描结果是num = undefined
      // 执行阶段再运行赋值
      console.log(num)
      var num = 10;

七、BOM

  1. 浏览器对象模型

    围绕 ”浏览器“ 的一些操作

    BOM可以:

    1. 获取到浏览器的型号(手机型号)
    2. url操作
    3. 屏幕的大小尺寸
  2. location对象:操作浏览器当前的url
    1. href:本身是可以获取到当前的url、设置对应跳转的url

      localtion.href = 'url' 是在本页面进行的跳转,不是新窗口打开

      window.open(url,'_blank') 可以在新窗口打开

      <script>
      btn.onclick = function(){
      location.href = 'http:///www.xuexiluxian.cn';
      }
      </script>
      <body>
      <input type="text" id='userName'/>
      <input type="password" id='userPwd'/>
      <input type="button" value='登录' id='login'/>
      </body>
      <script>
      login.onclick = function(){
      var uName = userName.value;
      var uPwd = userPwd.value;
      if(uName=='admin' && uPws=='admin'){
      location.href='home.html';
      // window.open(url,'_blank');
      }else{
      alert('用户名或密码不正确');
      }
      }
      </script>
    2. search:设置或者获取,从问号(?),开始的url

      解码 decodeURIComponent 中文字体乱码,需要解码

      <script>
      document.title = decodeURIComponent(location.search);
      </script>

      image-20240525090131708

    3. hash:设置或者获取,从井号(#),开始的url

  3. history:操作浏览器窗口访问过的url
    1. back:返回上一页

      // home.html
      <body>
      <ul>
      <li id='js'>js</li>
      </ul>
      </body>
      <script>
      js.onclick = function(){
      loaction.href = 'list.html';
      }
      </script>
      // list.html
      <body>
      <div id='oReturn'> < </div>
      </body>
      <script>
      oReturn.onclick = function(){
      history.back();
      }
      </script>
    2. forward:前进下一页

    3. go:前往指定的页面

      1. go(-1) :返回上一页 back
      2. go(1) :前进下一页 forward
      3. go(0) :刷新
    1. userAgent:用户代理头的值、用的什么浏览器

    2. platform:返回运行浏览器的操作系统

      image-20240525092511679

  4. screen:客户端屏幕信息
    1. width:返回显示的屏幕宽度
    2. height:返回屏幕的高度

八、定时器

  1. setInterval:间歇调用,”后”,将定时任务处理的函数添加到执行队列到队尾
    1. 语法格式:

      setInterval(执行匿名函数,毫秒数)

  2. setTimeout:超时调用,”后”,将定时任务处理的函数添加到执行队列到队尾
    1. 语法格式:

      setTimeout(执行匿名函数,毫秒数)

  3. 清除定时器
    1. clearInterval——-setInterval

    2. clearTimeout———setTimeout

    3. 语法格式:

      clearInterval(清楚哪一个定时器)

      clearTimeout(清楚哪一个定时器)

九、js的单线程

同一时间只能做一件时间,这也就意味着所有的任务需要排队,前一个任务执行结束了,才可以继续执行下一个任务

  1. js语言为什么是单线程

    取决于用在什么地方、用户体验

    事件队列(定时器、ajax…):先进先出

    先执行主线程,再执行事件队列

获取id:document.getElementById('id值')
获取集合元素:document.getElementsByTagName('元素名称')

十、数组

  1. 什么是数组

    使用单独的变量名来存储”一系列”的值

  2. 数组可以

    存储一系列(大量)的值

  3. 使用数组
    1. 如何创建数组

      构造函数形式new Array('字符串',数值,布尔) 、如果只有一个参数,这个参数就是数组的长度【只限数值】

      字面量['字符串',数值,布尔]

    ​ 数组是一个对象、存储在堆内存中

    1. 数组属性:长度length

十一、数组方法

  1. concat():合并数组,最后返回一个新的数组

    数组.方法名称(参数)

    var arr = ['a','b','c'];
    var brr = ['1','2','3'];
    arr.concat(brr);
  2. reverse():反转数组的顺序,会改变原来的数组
  3. join('分隔符'):将数组转换成字符串

    将数组的元素组成一个字符串,用参数分隔符进行分割,默认以逗号分隔

  4. push():将参数添加到原数组的末尾,并且返回数组的长度
  5. unshift():将参数添加到原数组开头,并且返回数组的长度
  6. pop():数组末尾移除最后一项,返回移除的项
  7. shift():删除原数组第一项,返回移除的项
  8. slice(开始位置,结束位置):截取,返回新数组

    一个参数(正数):从当前下标(包括下标)开始往后截取

    两个参数(正数):从开始位置(包括开始位置)到结束位置(不包括结束位置)

  9. sort():按升序排列数组项
    sort(function(a,b){
    return a-b; // 从小到大
    return b-a; // 从大到小
    })
  10. indexOf(参数):查找,查找参数在数组中是否存在

    如果存在返回下标

    如果不存在返回-1

  11. splice():可以实现删除、插入、替换操作

    删除:2个参数,(1,2)从下标1开始,删除2个

    替换:3个参数,(0,1,4)从下标0开始,长度为1的数组元素替换成4

    插入:3个参数,(1,0,5)表示下标为1处添加一项5

十二、循环遍历数组

  1. forEach

    语法格式:

    数组.forEach(function(item,index){
    // item:数组每一项
    // index:数组的下标
    })

    缺点:不可以使用break和return

  2. map:里面支持return,并且返回新的数组
    var arr = ['a','b','c'];
    /*
    var brr = [];
    for(var i=0;i<arr.length;i++){
    brr.push(arr[i]+'0');
    }
    console.log(brr);
    */
    var brr = arr.map(function(item,index){
    return item+'0';
    })
    console.log(brr);
  3. filter:过滤,并且返回新的数组
    var arr = [18192022253326];
    /*
    var brr = [];
    for(var i=0;i<arr.length;i++){
    if(arr[i]>20){
    brr.push(arr[i]);
    }
    }
    console.log(brr);
    */
    var brr = arr.filter(function(item,index){
    return item>20;
    })
    console.log(brr);
  4. every:所有为true,返回true
  5. some:只要有一项为true,返回true

十三、字符串

  1. 字面量
    var str = '你好';
  2. 构造函数
    var str = new String('你好');

区别

  • 字面量形式存储在栈内存,构造函数形式存储在堆内存
    • typeof字面量返回 string
    • typeof构造函数返回 object
  • 为什么字面量的string、boolean、number也有属性和方法
    • string、boolean、number:原始的资料类型
    • new String、new Number、new Boolean:包装对象
    • 原始的资料类型向包装对象借用
  1. 字符串方法
    1. charAt(数值):返回指定”位置”的字符

      var str = 'abcdef';
      console.log(str[1]);
      console.log(str.chatAt(1));
    2. indexOf(字符):查找,有返回下标,没有返回-1

    3. replace(把什么,替换成什么):替换、只替换一处,并不是全部替换

      1. 全部替换:

        str.replace(/字符/g,'替换的内容');
    4. trim():去除前后空格

    5. toLowerCase():把字符转换成小写

    6. toUpperCase():把字符转换成大写

    7. split():把字符串转换成数组

    8. join():把数组转换成字符串

  2. 字符串截取
    1. slice(start,end)
    2. substring(start,end) 负数转换成0
    3. substr(start,length):start为开始位置,length为长度

上传文件判断后缀名

btn.onclick = function(){
// files.value就是文件的路径
var val = filea.value;
// 找到.的位置,也就是下标
var idx = val.indexOf('.');
// 截取.后面的内容
var fileName = val.slice(idx+1);
if(fileName!='jpg' && fileName!='png'){
console.log('文件有误');
}else{
console.log('上传正确');
}
}

手机号中4位隐藏

<body>
<input type="" name="" id='tel'> // 获取到value
<input type="button" value="替换" id='changeBtn'> // 添加事件
<div id='endTel'></div> // 放入最终值
</body>
var tel = document.getElementById('tel');
var changeBtn = document.getElementById('changeBtn');
var endTel = document.getElementById('endTel');
changeBtn.onclick = function(){
// 获取到input的value
var telVal = tel.value;
// 最终赋值
endTel.innerText = fHide(telVal,3,4,*);
}
function fHide(str,first,last,start){
// 参数1:input的value值
// 参数2:是数字3、开始的3位显示
// 参数3:是数字4、结束的4位显示
// 参数4:代表中间的内容要被替换成*
var len = str.length - first - last;
var sStart = '';
for(var i=0;i<len;i++){
sStart+='*';
}
return str.slice(0,start) + sStart + str.slice(-last);
}

十四、Math(数学)对象

  1. 取最大

    Math.max()

  2. 取最小值

    Math.min()

  3. 四舍五入

    Math.round()

  4. 返回数的绝对值

    Math.abs()

  5. 返回数的平方根

    Mmath.sqrt()`

  6. 向下取整

    Math.floor()

  7. 向上取整

    Math.ceil()

  8. 返回随机数

    Math.random()

    随机的公式:

    1. 不包含最大值,包含最小值 Math.floor(Math.random() * (max - min))+min
    2. 包含最大值,包含最小值 Math.floor(Math.random() * (max - min + 1))+min

随机验证码

<div>
<div>
<input type="" name="" id='txt'>
<span id='code'></span>
</div>
<div>
<input type="button" value="登录" id='btn'>
</div>
</div>
// 点击验证码可以切换
// 验证码是否正确
var code = document.getElementById('code');
var txt = document.getElementById('txt');
var btn = document.getElementById('btn');
// 生成验证码的函数
function fRandom(codeLen){
var str = 'abcdef1234567890';
var strCode = '';
for(var i = 0;i<codeLen;i++){
var n = Math.floor(Math.random() * str.length);
strCode += str[n];
}
// 给验证码盒子内容赋值,让其显示这个验证码
code.innerText = strCode;
}
fRandom(4)
// 点击验证码
code.onclick = function(){
fRandom(4)
}
// 点击登录判断
btn.onclick = function(){
if(txt.value === code.innerText){
location.href='http://www.xuexiluxian.cn/'
}else{
alert('验证码不正确');
}
}

十五、日期对象【new Date()】

  1. 日期对象的方法
    1. 对象.getFullYear()

    2. 对象.getMonth()

    3. 对象.getDate()

    4. 对象.getHours()

    5. 对象.getMinutes()

    6. 对象.getSeconds()

      var date = new Date();
      date.getSeconds();
  2. 时间戳

    从1970年1月1日至今的时间(毫秒)

    对象.getTime()

京东秒杀

<div>
<div>京东秒杀</div>
<div>
<div>
<strong>12:00</strong>
点场 倒计时
</div>
<div>
<span id='hour'>01</span>
<span id='minute'>01</span>
<span id='second'>01</span>
</div>
</div>
</div>
var hour = document.getElementById('hour');
var minute = document.getElementById('minute');
var second = document.getElementById('second');
// 什么时候停止秒杀
var date = new Date('2020-6-18 00:00:00');
function fCountDown(){
// 这是现在时间
var nowTime = new Date();
// 目标停止时间 减去 当前时间、算出来、差额时间
var times = (date - nowTime)/1000;
// 获取差额的小时
var h = parseInt(times/60/60%24);
h = h<10 ? '0'+h : h;
hour.innerText = h;
// 获取差额的分钟
var m = parseInt(times/60%60);
m = m<10 ? '0'+m : m;
minute.innerText = m;
// 获取差额的秒
var s = parseInt(times%60);
s = s<10 ? '0'+s : s;
second.innerText = s;
}
// 一开始就刷新页面
fCountDown();
setInterval(fCountDown,1000)

十六、DOM

document object model:文档对象模型

  1. 获取文档节点【元素】的方法
    • 获取id:document.getElementById('main')

    • 获取标签名:document.getElementsByTagName('li') 获取到的是集合元素

    • 获取class名:document.getElementsByClassName('class') 获取到的是集合元素

    • 通过选择器来获取一个节点:document.querySelector()

    • 通过选择器来获取所有节点:document.querySelectorAll()

      <div id='main' class='container'>
      我是main
      </div>
      console.log(document.querySelectorAll('#main')[0]);
      console.log(document.querySelectorAll('.container');
  2. 节点属性
    1. innerHTMLinnerText:给节点添加内容 innerText解析不了html标签
    2. nodeName:返回节点名称、用来做判断使用、返回大写字母
    3. firstElementChild:获取到第一个子元素节点
    4. lastElememtChild:获取到最后一个子元素节点
    5. parentNode:获取到父节点
  3. 节点方法(操作节点属性的方法)
    1. 获取:节点对象.getAttribute('属性名称'):返回对应属性名称的值
    2. 设置:节点对象.setAttribute('属性名称',‘对应的值)
    3. 删除:节点.removeAttribute('属性名称')
  4. 创建节点

    document.createElement('节点名称')

  5. 添加节点
    1. 追加 父节点.appendChild(子节点)

    2. 前置 父节点.insertBefore(添加的子节点,添加到谁前面)

      var add = document.getElementById('add');
      var uls = document.getElementById('uls');
      add.onclick = function(){
      // 创建li节点
      var newLi = document.createElement('li');
      var liLen = document.getElementByTagName('li').length;
      newLi.innerText = liLen;
      // 添加节点->追加
      uls.appendChild(newLi);
      // 添加节点->前置
      uls.insertBefore(newLi,document.getElementsByTagName('li')[0]);
      }
  6. 删除节点

    父节点.removeChild(子节点)

    <div>
    <ul>
    <li>
    1111
    <a href="javascript:;">删除</a>
    </li>
    <li>
    2222
    <a href="javascript:;">删除</a>
    </li>
    <li>
    3333
    <a href="javascript:;">删除</a>
    </li>
    <li>
    4444
    <a href="javascript:;">删除</a>
    </li>
    <li>
    5555
    <a href="javascript:;">删除</a>
    </li>
    </ul>
    </div>
    var uls = document.getElementById('uls');
    var oA = document.getElementsByTagName('a');
    var oAlen = oA.length
    for(var i = 0;i<oAlen;i++){
    oA[i].onclick = function(){
    uls.removeChild(this.parentNode);
    }
    }
  7. 获取样式表中的样式

    语法格式:getComputedStyle(节点,null).样式名称

  8. 获取元素的大小和偏移位置
    • 大小:
      • 计算width+padding+border、没有px单位,返回的是数值类型
        • 节点对象.offsetWidth
        • 节点对象.offsetHeight
      • 计算width+padding、没有px单位,返回的是数值类型
        • 节点对象.clientWidth
        • 节点对象.clientHeight
    • 偏移值:
      • 节点对象.offsetLeft (从左到右)
      • 节点对象.offsetTop (从上到下)
      • 如果节点没有定位的情况下:相对整个文档偏移
      • 如果节点有定位的情况下:相对于父节点偏移
  9. 滚动距离

    节点对象.scrollLeft

    节点对象.scrollTop

    回到顶部

    <head>
    <style type="text/css">
    *{
    margin: 0;
    padding: 0;
    }
    .is-fx{
    position: fixed;
    bottom0px;
    top: 50px;
    width: 150px;
    height: 150px;
    background: red;
    text-align: center;
    line-height: 150px;
    }
    </style>
    </head>
    <body style='height: 5000px;'>
    <div id='isFx' class='is-fx'>
    回到顶部
    </div>
    </body>

    <script>
    var isFx = document.getElementById('isFx');
    isFx.onclick = function(){
    document.documentElement.scrollTop = 0;
    }
    </script>

十七、事件

  • 什么是事件:事件指可以被JavaScript检测到的行为
    • 事情的起因
  • 都有哪些事件
    • 即鼠标点击、页面或图像载入、鼠标悬浮于页面的某个热点之上、在表单中选取输入框、确认表单、键盘按键等操作。
  • 事件在什么时候执行
    • 事件通常与函数配合使用,当事件发生时函数才会执行
  1. 事件流

    事件执行的顺序

    1. 历史原因:早期的IE事件传播方向为由上至下,即从document逐级向下传播到目标元素;而Netscape公司则是朝相反的方向传播,也就是从目标元素开始向上逐级传播最终至window后来ECMAScript在DOM2中对事件流进行了进一步规范,基本上就是两者的结合。
      1. 当事件发生时,最先得到通知的是window,然后是document,由上至下逐级依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。
      2. 接下来,事件会从目标元素开始起泡,由下至上逐级依次传播,直到window对象为止,这个过程就是冒泡,所以捕获比冒泡先执行。
    2. 事件流分为两种:事件捕获、事件冒泡
      1. 事件捕获:是从window开始向下传播,一直目标节点
      2. 事件冒泡:是从目标节点开始向上传播,一直到window
  2. 鼠标类事件
    1. onclick 单击事件

    2. ondblclick 双击事件

    3. oncontextmenu 右击事件、要 return false

    4. 屏蔽右击

      document.oncontextmenu = function(){
      return false;
      }
    5. onmousedown 鼠标按下、在拖拽的时候会用到

    6. onmouseup 鼠标释放、在拖拽的时候会用到

    7. onmouseover 鼠标经过

    8. onmouseout 鼠标离开

    9. onmousemove 鼠标悬浮、放大镜效果

  3. 键盘类事件
    1. onkeydown 键盘按下

    2. onkeyup 键盘按下

    3. 通过keyCode获得键值 e.keyCode

      txt.onkeydown = function(e){
      if(e.keyCode == 13){
      var lis = document.createElement('li');
      lis.innerHTML = txt.value;
      uls.appendChild(lis);
      txt.value = '';
      }
      }
  4. 其他类事件
    1. onload 加载完毕后立即执行的操作
    2. window.onload 网页加载完毕后
    3. onfocus 获取焦点
    4. onblur 失去焦点
    5. onscroll 滚动条事件
    6. onchange 内容改变时触发
  5. 事件处理程序-添加
    1. HTML事件处理程序 :把事件直接写在节点上

      <div onclick='alert(1)'>
      我是一个div
      </div>
      <div onclick='fNum(20,5)'>
      我是一个div
      </div>
      <script>
      function fNum(num1,num2){
      alert(num1 + num2);
      }
      </script>

      缺点:代码耦合

    2. DOM 0级事件处理程序:

      main.onclick = function(){}

      缺点:同样元素的同样事件会被覆盖

    3. DOM 2级事件处理程序:

      dom对象.addEventListener(事件名称,函数,false|true)

      注:事件名称:不需要加入on

      ​ false:冒泡

      ​ true:捕获

  6. 事件处理程序-删除
    1. DOM 0级删除事件

      dom对象.事件名称 = null

    2. DOM 2级删除事件

      dom对象.remove EventListener(事件名称,函数,false|true)

      注:要使用一个内存的

      function fn(){
      alert('2级')
      }
      main.addEventListener('click',fn,false)
      main.removeEventListener('click',fn,false)
  7. 事件对象-事件委托
    1. 事件对象:e

      mian.onclick = function(e){
      console.log(e);
      }
    2. 事件对象的属性

      1. 事件对象.target:目标,返回对应的dom对象
      2. clientX : 当前鼠标的位置距离浏览器左侧的距离
      3. clientY: 当前鼠标的位置距离浏览器顶部的距离
    3. 事件委托

      1. 优点:性能好、即使后添加的内容也有效

        // 无事件委托
        var lis = document.getElementById('lis');
        var liLen = lis.length;
        for(var i=0;i<liLen;i++){
        lis[i].onclick = function(){
        this.style.background = 'red';
        }
        }
        var btn = document.getElementById('btn');
        btn.onclick = function(){
        var newLi = document.createElement('li');
        newLi.innerHTML = '后添加的';
        uls.appendChild(newLi);
        }
        // 有事件委托
        var btn = document.getElementById('btn');
        var uls = document.getElementById('uls');
        btn.onclick = function(){
        var newLi = document.createElement('li');
        newLi.innerHTML = '后添加的';
        uls.appendChild(newLi);
        }
        uls.onclick = function(e){
        if(e.target.nodeName == 'LI'){
        e.target.style.background = 'red'
        }
        }
  8. 阻止冒泡-阻止默认行为
    1. 阻止事件冒泡

      事件对象.stopPropagation()

    2. 阻止默认行为

      事件对象.preventDefault()

    案例:拖拽

    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    * {
    margin: 0;
    padding: 0;
    }

    .drag {
    position: absolute;
    width: 100px;
    height: 100px;
    background: pink;
    border-radius: 20px;
    cursor: pointer;
    }
    </style>

    </head>

    <body>
    <div id="drag" class="drag"></div>
    </body>
    <script>
    // 三个事件
    // 鼠标按下:onmousedown
    // 鼠标移动:onmouseover|onmousemove
    // 鼠标方式:onmouseup
    var drag = document.getElementById('drag');
    drag.onmousedown = function (e) {
    // 按下时候鼠标位置距离浏览器左侧的距离 - 盒子左侧距离浏览器的位置
    var x = e.clientX - drag.offsetLeft;
    // 按下时候鼠标位置距离浏览器顶部的距离 - 盒子顶部距离浏览器的位置
    var y = e.clientY - drag.offsetTop;
    document.onmousemove = function (e) {
    // 鼠标距离浏览器左侧的距离值
    var l = e.clientX - x;
    // 鼠标距离浏览器顶部的距离值
    var t = e.clientY - y;
    if (l < 0) {
    l = 0;
    }else if (l > document.documentElement.clientWidth - drag.offsetWidth) {
    l = document.documentElement.clientWidth - drag.offsetWidth
    }
    if (t < 0) {
    t = 0;
    }else if (t > document.documentElement.clientHeight - drag.offsetHeight) {
    t = document.documentElement.clientHeight - drag.offsetHeight
    }
    drag.style.left = l + 'px';
    drag.style.top = t + 'px';
    }
    }
    drag.onmouseup = function () {
    document.onmousemove = null;
    }
    </script>

    </html>

    案例:放大镜

    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>放大镜</title>
    <style>
    * {
    margin: 0;
    padding: 0;
    }

    .u-l {
    float: left;
    }

    .mian {
    margin: 150px;
    }

    .s-img {
    position: relative;
    width: 400px;
    height: 400px;
    }

    .s-img img {
    width: 100%;
    height: 100%;
    }

    .s-img span {
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    width: 200px;
    height: 200px;
    background: #fff;
    opacity: 0.5;
    }

    .p-img {
    position: relative;
    display: none;
    margin-left: 30px;
    width: 400px;
    height: 400px;
    overflow: hidden;
    }

    .p-img img {
    position: absolute;
    left: 0;
    top: 0;
    }
    </style>
    </head>

    <body>
    <div class="main" id="main">
    <!-- 小图 -->
    <div class="s-img u-l" id="sImg">
    <img src="images/400.jpg" alt="">
    <span class="lens" id="lens"></span>
    </div>
    <!-- 大图 -->
    <div class="p-img u-l" id="pImg">
    <img src="images/800.jpg" alt="" id="picImg">
    </div>
    </div>
    </body>
    <script>
    // 小盒子
    var sImg = document.getElementById('sImg');
    // 阴影
    var lens = document.getElementById('lens');
    // 大盒子
    var pImg = document.getElementById('pImg');
    // main节点
    var main = document.getElementById('main');
    // 大图片
    var picImg = document.getElementById('picImg');
    // 给小盒子加入鼠标移入事件,让阴影和大盒子显示
    sImg.onmouseover = function () {
    lens.style.display = 'block';
    pImg.style.display = 'block';
    }
    sImg.onmousemove = function (e) {

    // 当前鼠标的位置 - 盒子距离浏览器左侧的偏移 - 阴影宽度的一半
    var x = e.clientX - main.offsetLeft - lens.offsetWidth / 2;

    var y = e.clientY - main.offsetTop - lens.offsetHeight / 2;
    if (x < 0) {
    x = 0;
    } else if (x > sImg.offsetWidth - lens.offsetWidth) {
    x = sImg.offsetWidth - lens.offsetWidth
    }
    if (y < 0) {
    y = 0;
    } else if (y > sImg.offsetHeight - lens.offsetHeight) {
    y = sImg.offsetHeight - lens.offsetHeight
    }
    // 阴影位置
    lens.style.left = x + 'px';
    lens.style.top = y + 'px';
    // 大图片位置
    picImg.style.left = -x * 2 + 'px';
    picImg.style.top = -y * 2 + 'px';
    }
    sImg.onmouseout = function () {
    lens.style.display = 'none';
    pImg.style.display = 'none';
    }
    </script>

    </html>

十八、正则表达式

  1. 什么是正则表达式

    规则表达式

  2. 正则的使用
    1. 定义

      字面量://

      构造函数:new RegExp()

    2. 区别

      new RegEep() 放入变量

  3. 正则的方法
    1. test():检测一个内容是否与正则匹配

      如果匹配返回true

      如果不匹配返回false

    2. exec():检测一个内容是否与正则匹配

      如果匹配返回数组

      如果不匹配返回null

  4. 元字符
    元字符 含义
    [] 匹配中括号内的任意一个字符、验证手机号 [abc]
    [^] 除了中括号内任意字符、 [^abc]
    [0-9] 匹配数字0-9范围的
    [a-z] [A-Z] [a-zA-Z]
    \d 匹配数字[0-9]
    \D 匹配非数字
    \w 匹配数字、字母、下划线 [a-zA-Z0-9_]
    \W 匹配非数字、字母、下划线
    \s 匹配空格
    \S 匹配非空格
    \b 匹配边界
    \B 匹配非边界
    . 匹配除了换行符以外的任意字符
  5. 转义(\)

    /\./ 失去原有功能

  6. 选择符

    |:或

  7. 修饰符
    修饰符 含义
    i 不区分大小写 /[a-z]/i = /[a-zA-Z]/
    g 全文匹配
    m(不常用)
    var reg = /菜B|大爷/g;
    if(reg.test(val)){
    val = val.replace(reg,'*');
    }
  8. 字符串方法可以配合正则去用

    replace

    match:类似于exec、查找返回对应的值【值是数组】、没有找到返回null、支持全局

  9. 限定符

    ^ 开始

    $ 结束

    验证手机号的时候:11位数字

    // 以数字1开头
    var reg1 = /^1/;

    // 以数字1开始,以数字结束
    // 数字1后面必须是一位的数字
    var str1 = /^1\d$/;
  10. 重复
    符号 含义
    {n} 重复n次
    {n,} 重复最少n次、最多不限
    {n,m} 重复最少n次、最多m次
    * 重复最少0次、最多不限
    + 重复最好1次、最多不限
    ? 重复最好0次、最多1次
  11. 贪婪模式
    var reg1 = /\d{3,6}/g;
    var str1 = '123456789';
    console.log(str1.replace(reg1,'*'));
    // ******789
  12. 非贪婪模式(懒惰模式)
    var reg1 = /\d{3,6}?/g;
    var str1 = '123456789';
    console.log(str1.replace(reg1,'*'));
    // ***456789
  13. 分组

    () 把部分内容组合在一起

  14. 字符类:来获取分组

    $1 第一个分组

    $2 第二个分组

    $3 第三个分组

  15. 前瞻 和 后顾

    js正则没有后顾

    1. 正向前瞻:(?=):匹配符合的

      // 看一看 \d(数字)后面的是不是字母,是字母匹配到
      var reg1 = /\d(?=[a-z])/g;
      var str1 = '1a2b*%3cdddd5';
      console.log(str1.replace(reg1,'*'));
      // *a*b*%*cdddd5

      /(?=.*\d)/ 开始字符后必须是数字

    2. 负向前瞻:(?!):匹配不符合的

      // 看一看 \d不是字母,可以匹配到
      var reg1 = /\d(?![a-z])/g;
      var str1 = '1a2b*%3cdddd5';
      console.log(str1.replace(reg1,'*'));
      // 1a2b*%3cdddd*

案例:验证表单

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
input {
outline: none;
}
.register {
margin: 0 auto;
width: 500px;
}
.reg-item {
width: 398px;
height: 50px;
margin: 30px 0;
border: 1px solid #ccc;
}
.reg-item label {
display: inline-block;
width: 87px;
height: 50px;
line-height: 50px;
text-align: center;
}
.reg-item input {
width: 288px;
border: none;
}
.reg-error {
color: red;
padding-top: 3px;
font-size: 12px;
}
</style>
</head>
<body>
<form class="register">
<div class="reg-item">
<div>
<label>手机号</label>
<input type="text" name="phone" placeholder="请输入手机号" ID="tel">
</div>
<div class="reg-error">
<span><!-- *输入有误 --></span>
</div>
</div>
<div class="reg-item">
<div>
<label>用户名</label>
<input type="text" name="phone" placeholder="请输入用户名" id="userName">
</div>
<div class="reg-error">
<span><!-- *只能输入4-20位,且只能包含字母、数字、下划线 --></span>
</div>
</div>
</form>
<script>
var tel = document.getElementById("tel");
var userName = document.getElementById("userName");
var telError = document.querySelector(".reg-error:nth-child(1) span");
var userNameError = document.querySelector(".reg-error:nth-child(2) span");
tel.oninput = function() {
var reg = /^1[34578]\d{9}$/;
fMag(this,reg,'请输入正确的手机号');
}

userName.oninput = function() {

var reg = /^[a-zA-Z0-9_]{4,20}$/;
fMag(this,reg,'请输入4-20位,且只能包含字母、数字、下划线');
}
// 后续提示信息
function fMag(that,reg,errormsg){
var span = that.parentNode.parentNode.children[1].querySelector("span");
if(reg.test(that.value)){
span.style.color = "green";
span.innerHTML = "*正确";
}else{
span.style.color = "red";
span.innerHTML = errormsg;
}
}
</script>
</body>
</html>

案例:验证表单+验证码

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}

input {
outline: none;
}

.register {
margin: 0 auto;
width: 500px;
}

.reg-item {
width: 398px;
height: 50px;
margin: 30px 0;
border: 1px solid #ccc;
}

.reg-item label {
display: inline-block;
width: 87px;
height: 50px;
line-height: 50px;
text-align: center;
}

.reg-item input {
width: 288px;
border: none;
}

.reg-error {
padding-top: 3px;
font-size: 12px;
color: orange;
}

.reg-success {
position: relative;
}

.success {
position: absolute;
right: 0;
background: pink;
height: 50px;
width: 80px;
text-align: center;
line-height: 50px;
cursor: pointer;
letter-spacing: 3px;

}
</style>
</head>

<body>

<form class="register">
<div class="reg-item">
<div>
<label>手机号</label>
<input type="text" name="phone" placeholder="请输入手机号" ID="tel">
</div>
<div class="reg-error">
<span><!-- *输入有误 --></span>
</div>
</div>
<div class="reg-item">
<div>
<label>用户名</label>
<input type="text" name="phone" placeholder="请输入用户名" id="userName">
</div>
<div class="reg-error">
<span><!-- *只能输入4-20位,且只能包含字母、数字、下划线 --></span>
</div>
</div>
<div class='reg-item'>
<div class='reg-success'>
<label>验证码</label>
<input type="" placeholder="请输入验证码" id="code">
<span class='success'>1234</span>
</div>
<div class='reg-error'>
<span id="codeError"><!-- *只能输入4位,必须有数字--></span>
</div>
</div>
</form>


<script type="text/javascript">
//验证码===》随机(点击可以换) 4位数字
var tel = document.getElementById("tel");
var userName = document.getElementById("userName");
var telError = document.querySelector(".reg-error:nth-child(1) span");
var userNameError = document.querySelector(".reg-error:nth-child(2) span");
var success = document.querySelector(".reg-success span");
var code = document.getElementById("code");
tel.oninput = function () {
var reg = /^1[34578]\d{9}$/;
fMag(this, reg, '请输入正确的手机号');
}
userName.oninput = function () {
var reg = /^[a-zA-Z0-9_]{4,20}$/;
fMag(this, reg, '请输入4-20位,且只能包含字母、数字、下划线');
}
code.oninput = function () {
var reg = /^\d{4}$/
fMag(this, reg, '请输入4位数字')
// console.log(this.value)
// console.log(success.innerHTML)
// 和验证码匹配
var codeError = document.getElementById("codeError");
console.log(codeError)
// 判断验证码是否正确
if (this.value === success.innerHTML) {
codeError.style.color = "green";
codeError.innerHTML = "*正确";
} else {
codeError.style.color = "red";
codeError.innerHTML = "验证码错误";
}
}
// 页面加载刷新验证码
success.onclick = function () {
// 点击验证码刷新
this.innerHTML = Math.random().toString().substr(2, 4);
}
// 后续提示信息
function fMag(that, reg, errormsg) {
var span = that.parentNode.parentNode.children[1].querySelector("span");
// 对验证码实时验证
success.onclick = function () {
// 点击验证码刷新
this.innerHTML = Math.random().toString().substr(2, 4);
if (this.innerHTML == that.value) {
span.style.color = "green";
span.innerHTML = "*正确";
} else {
span.style.color = "red";
span.innerHTML = "验证码错误";
}
}
if (reg.test(that.value)) {
span.style.color = "green";
span.innerHTML = "*正确";
} else {
span.style.color = "red";
span.innerHTML = errormsg;
}

}

</script>

</body>

</html>

案例:手机号钝点

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p id="tel"></p>
</body>
<script>
var tel = document.getElementById('tel')
function fTelFormat(tel) {
return tel.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3')
}
tel.innerHTML = fTelFormat('18511773322')
console.log(fTelFormat('18511773322'))
</script>
</html>

十九、作用域

  1. 作用域

    作用的区域或者作用的范围

    全局作用域,全局就是window

    在全局作用域下写的变量:没有区别,都属于window对象的属性

    var str1 = '123’;
    window.str2 = '123';
    str3 = '123';

    在局部作用写变量

    // 声明局部变量
    var str1 = '123’;
    // 声明全局变量
    window.str2 = '123';
    // 声明全局变量
    str3 = '123';
  2. 作用域链

    从内部向外链:从当前作用域开始找,如果找不到向外作用域找,当找到返回,

  3. 悬挂变量声明(变量提升)

    解释:js提升所有的变量声明,将他们移到其作用域的开头

  4. 顺序、优先级

    变量 > 函数 > 参数 > 变量提升

    function c() {
    var b = 1;
    function a() {
    console.log(b); // undefined
    var b = 2;
    console.log(b); // 2
    }
    a();
    console.log(b); // 1
    }

二十、严格模式:use strict

  1. 使用方式
    1. 针对于整个文件【全局】

      文件开头(第一行)写入 use strict

      <script>
      'use strict'
      </script>
    2. 针对单个函数【局部】

      函数内开头(第一行)写入 use strict

      function fun(){
      'use strict'
      }
  2. 作用
    1. 变量声明问题:var | window、如果写法是:str = 123; 就报错

    2. 禁止this关键字指向全局对象

    3. 重名问题,函数不能有重名的参数

    4. arguments对象不能赋值

二十二、递归函数:自己调用自己

注:一定要有结束条件,如果没有结束条件就变成死循环

  1. 数组扁平化

    [‘a’,’b’,’c’,[‘d’,’e’,[‘f’,’q’]]]

    把多维数组变成一维

    function fun(arr) {
    // 弄一个空数组
    var result = [];
    for (var i = 0;i < arr.length;i++) {
    if (typeof arr[i] == 'object') {
    // ['d','e']
    // ['a','b','c'].合并(['d','e'])
    result = result.concat(fun(arr[i]));
    }else {
    result.push(arr[i]);
    }
    }
    }
    console.log(fun(['a','b','c',['d','e']]));
  2. 斐波那契算法

    有一对兔子,从生出的第三个月起每个月会生一对兔子,小兔子长到第三个月后每个月也会生一对兔子,假如兔子不死,那么第N个月有多少对兔子?

    分析:1 1 2 3 5 13 21 …

    function fun(n) {
    if (n <= 0) {
    return 0;
    }
    if (n <= 2) {
    return 1;
    }
    // 第n个月兔子的总对数 = 第n-1个月的总数+第n-2个月的总数
    return fun(n-1) + fun(n-2);
    }
  3. 走楼梯

    一共10级楼梯,每次可以走一步或者可以走二步,求一共多少种走法

    function fun(n) {
    if (n == 1) {
    return 0;
    }else if (n == 2) {
    return 2;
    }else if(n > 2){
    return fun(n-1) + fun(n-2);
    }
    }

二十三、闭包

  1. 块级作用域

    只有var没有块级作用域,let和const有块级作用域

  2. 作用域和作用域链

    当函数声明的时候,函数会通过内部属性,scope来记录创建范围

  3. 闭包
    1. 什么是闭包

      闭包是一个函数加上到创建函数的作用域的连接,闭包就是“关闭”了函数的自由变量

      简单理解:

      有两个函数,作用域是连接关系【scope】,变量不自由,会停留在内存中,不会销毁

      function fun(n) {
      return function(m) {
      n += m;
      return n;
      }
      }
      var f = fun(5);
      f(1)
  4. 闭包可以做什么?无意间共享环境
    var lis = document.getElementsByTagName('li');
    for (var i = 0;i < lis.length;i++) {
    lis[i].onclick = function() {
    console.log(i);
    }
    }
    // 此处打印会是3 3 3,而期望打印0 1 2 ,因为在打印变量i时内部没有i他会向外找i当找到i时已经执行完了
    var lis = document.getElementsByTagName('li');
    for (var i = 0;i < lis.length;i++) {
    (function() {
    var idx = i;
    lis[i].onclick = function() {
    console.log(idx);
    }
    })
    }
    // 自执行函数

二十三、undefined和null区别-instanceof

  1. 回顾数据类型
    1. 原始数据类型(基本数据类型)

      字符串、数值、布尔、undefined、null

    2. 引用数据类型

      对象:object

    3. 基本和引用的区别:每个对象都有唯一的标识,并且(严格地)等于自身。

      var arr1 = [1,2,3];
      var arr2 = [1,2,3];
      console.log(str1 === str2);
      // false
  2. 区别

    undefined:未定义

    null:没有对象

    先设计的null,后设计的undefined

    JavaScript的最初版本是这样区分的:null是一个表示 ”无“ 的对象(空对象指针),转为数值时为0;undefined是一个表示 ”无“ 的原始值,转为数值时为NaN。

    注意null的问题:typeof null 返回 ‘object’ 是一个无法修复的错误

  3. 检测类型
    1. typeof:检测基本类型

    2. instanceof:检测引用类型、对象、返回布尔类型

      // 语法格式
      检测的数据类型 instanceof 所属构造函数名称

二十四、对象

  1. 字面量形式

    var obj = {}

    // 获取对象的属性对应的值
    var obj = {
    userName:'张三',
    age:18,
    }
    console.log(obj.userName);
  2. 构造函数形式

    注:构造函数的首字母要大写

    function Fun() {
    this.userName = '张三',
    this.run = function() {
    return 123;
    }
    }
    var obj = new Fun();
    console.log(obj.userName);
    console.log(obj.run());
  3. Object.create()

    创建一个新的对象,使用现有的对象来提供创建的对象的原型

    var obj = Object.create(Object.prototype);
    console.log(obj);
  4. 设置属性
    var obj = {
    age:18,
    5:'你好',
    };
    obj.userName = '张三';

    检测对象是否有该属性

    1. in:属性名称 in 对象

      'userName' in obj;
      // 返回布尔值
    2. hasOwnProperty:对象.hasOwnProperty

      判断对象自身是否有某个属性

      obj.hasOwnProperty('sex');
    3. 区别

      in 可以检测对象自身属性也可以检测原型的属性、hasOwnProperty无法检测原型

  5. 删除属性

    delete 对象.属性

    注:对象即使没有这个属性,也不会报错,是返回undefined

  6. get-set

    get:读

    set:写

    var obj = {
    name:'张三',
    get changeName() {
    return this.name;
    },
    set changeName(val) {
    this.name = val;
    },
    }
    obj.changeName = '李四';
    console.log(obj.changeName); // 张三 // 李四
  7. 序列化对象

    对象 转化成 字符串:JSON.stringify()

    字符串 转化成 对象:JSON.parse()

  8. 遍历对象
    1. for...in

      key:就是属性名【键名】

      obj[key]:就是值【键值】

      var obj = {
      a:1,
      b:2,
      c:3,
      fun:function() {
      retuen 111
      },
      };
      for(var key in obj) {
      console.log(key); // a b c fun
      console.log(obj[key]); // 1 2 3 function(){return 111}
      }
    2. Object.keys()、Object.values()

      var obj = {
      a:1,
      b:2,
      c:3,
      fun:function() {
      retuen 111
      },
      };
      console.log( Object.keys(obj) );
      console.log( Object.values(obj) );
      // 返回数组
  9. 合并对象
    1. Object.assign(target,obj1,obj2...)

      target:合并对象,复制目标对象

      var obj1 = {
      a:1,
      }
      var obj2 = {
      b:2,
      }
      Object.assign( obj1,obj2 );
      console.log( obj1 ); // { a:1, b:2 }

      var o = Object.assign( {},obj1,obj2 );
      console.log( o ); // { a:1, b:2 }
  10. this指向

    this 指的是函数运行时所在的 “环境”

    原理:js语言设计 this,是跟内存的数据结构有关系,函数可以在不同的环境运行执行,所以就需要一种机制,能够在函数体内获取当前函数的运行环境。

    this 的设计目的就是在函数体内,指向函数当前的运行环境。

    补充:引擎会将函数单独保存在内存中

    var x = 1;
    var obj = {
    x:2,
    run:function() {
    // 要是想让this指向函数,添加下面的代码
    // var that = this;
    return function() {
    return this.x; // 这里的this 代表window了,值为1
    // return that.x;
    };
    },
    }
    console.log( obj.run()() )
    // 等同于
    var f = obj.run();
    console.log( f() );
  11. 改变this指向–call、apply、bind

    是所有函数都具有的方法

    函数也是对象,函数具有方法

    1. call(参数1,参数2,参数3...)

      参数1:调用函数时,内部this的具有值

      剩余的参数(参数2,参数3…)就是函数的参数

      var x = 1;
      var obj = {
      x:2,
      run:function(val) {
      return this.x + val;
      },
      };
      console.log( obj.run('你好') );
      var f = obj.run;
      console.log( f.call(obj,'大家好') );
    2. apply(参数1,[参数值1,参数值2,参数值3])

      参数1:调用函数时,内部this的具有值

      参数2:是一个数组,其中数组每一个值代表了函数的参数

      console.log( f.apply(obj,['大家好']) );
      console.log( Math.max(...[3,6,8,99,55]) );          // 99
      console.log( Math.max.apply(null,[3,6,8,99,55]) ); // 99
    3. bind(参数1,参数2,参数3...)

      参数1:调用函数时,内部this的具有值

      剩余的参数(参数2,参数3…)就是函数的参数

      注:bind会返回一个函数,所以要加一个()

      console.bind( f.call(obj,'大家好')() );

二十五、对象模式

  1. 工厂模式
    // 这是一个厂子
    function fun() {
    // 这是人
    var o = new Object();
    o.name = '张三';
    // 最终要返回一个对象
    return o;
    }
    var obj = fun();
    console.log(obj);
    // 这是一个厂子
    function fun(cName) {
    // 这是人
    var o = new Object();
    o.name = cName;
    // 最终要返回一个对象
    return o;
    }
    var obj1 = fun('张三');
    var obj2 = fun('李四');
    console.log( obj1,obj2 );
  2. 构造函数

    就是普通函数、只不过首字母要大写,函数内可以有 this,这个 this 指向 new 出来的对象

    function fun() {
    // 普通函数
    }
    function Fun() {
    // 构造函数
    }
    // 构造函数
    function Fun() {

    }
    var obj = new Fun(); // 实例化
    console.log( obj );
  3. 原型模式(prototype)
    1. 函数拥有prototype属性|对象
    2. 共享的属性和方法放在prototype中,不共享的放在构造函数中
    3. new 缺点:无法共享属性和方法
    function Fun() {
    // 不共享
    this.run = function() {
    return 111;
    }
    }
    // 共享
    // Fun.prototype.person = function() {
    // return 222;
    // }
    Fun.prototype = {
    person:function() {
    retuen 222;
    }
    }
    var obj1 = new Fun();
    var obj2 = new Fun();
    console.log( obj1.run === obj2.run ); // false
    console.log( obj1.person === obj2.oerson ); // true
  4. 函数与对象的原型关系

    函数有:prototype

    对象有:__proto__

    function Fun() {
    this.name = '张三';
    }
    var obj = new Fun();
    // Fun 是一个函数
    // obj 是一个对象
    console.log( obj.name );

  5. new 具体做了什么事
    1. 创建一个对象 new Object()

    2. 原型赋值【指向共同一个原型对象】

      对象.__proto__ = Fun.prototype

    3. 改变this指向

  6. 浅拷贝和深拷贝
    1. 什么叫拷贝

      复制

      var a = 10;
      var b = a;
      console.log( a,b ); // 10 10
      a = 200;
      console.log( a,b ); // 200 10
      // 引用类型,引用传递 
      var o = {a:1};
      var m = o;
      console.log( o.a,m.a ); // 1 1
      o.a = '你好';
      console.log( o.a,m.a ); // 你好 你好
    2. 浅拷贝

      只复制一层对象,当对象的属性是引用类型时,实质上复制的其引用,当引用指向的值发生变化的时候,原对象的属性也会跟着变化。

      var obj = {
      a:1,
      b:{
      a:'你好'
      }
      }
      function fun(obj) {
      var m = {};
      for(var k in obj) {
      m[k] = obj[k]
      }
      return m;
      }
      var createObj = fun(obj);
      console.log( createObj.b ); // {a:"你好"}
      console.log( createObj.b.a ); // 你好
      console.log( obj.b.a ); // 你好

      createObj.b.a = '222'
      console.log( createObj.b.a ); // 222
      console.log( obj.b.a ); // 222

      Object.assign()

      var o = {
      a:1,
      b:{
      a:'你好'
      }
      }
      var m = Object.assign({},o); // {a:1, b:{a:'你好'}} {a:1, b:{a:'你好'}}
      m.b.a = '不好';
      console.log( 0,m ) // {a:1, b:{a:'不好'}} {a:1, b:{a:'不好'}}
    3. 深拷贝

      在拷贝的时候,创建新的对象,并把原对象所有的属性都深拷贝到新对象,原属性如果是对象,也会重新创建新的对象并拷贝到新对象属性中,这样旧对象和新对象就是互相独立的,互不影响。、

      1. JOSN.parse() + JOSN.stringify

        var o = {
        a:1,
        b:{
        a:'你好'
        }
        }
        var m = JOSN.parse(JOSN.stringify(o));
        console.log( o,m ); // {a:1, b:{a:'你好'}} {a:1, b:{a:'你好'}}
        m.b.a = '不好';
        console.log( o,m ); // {a:1, b:{a:'你好'}} {a:1, b:{a:'不好'}}
      2. 递归

        var o = {
        a:1,
        b:{
        a:'你好'
        }
        }
        function fun(obj) {
        var m = {};
        if(typeof obj == 'object') {
        for(var k in obj) {
        if(obj.hasOwnProperty(k)) {
        if(typeof obj[k] == 'object') {
        m[k] = fun(obj[k]);
        } else {
        m[k] = obj[k];
        }
        }
        }
        }
        return m;
        }
        var createObj = fun(obj);
        console.log( createObj.b ); // {a:1, b:{a:'你好'}}
        console.log( obj.b ); // {a:1, b:{a:'你好'}}
        createObj.b.a = '不好';
        console.log( createObj.b ); // {a:1, b:{a:'不好'}}
        console.log( obj.b ); // {a:1, b:{a:'你好'}}

二十六、原型链–继承

每一个对象那个都有原型(__ proto __),这个原型还有属于自己的原型,最终形成了原型链。原型链最顶端是null。

为什么设计原型:继承、让对象的属性和方法实现共享

函数:prototype

对象:__ proto __

image-20240605235507875

如果要查找对象的属性或者方法,我们先要去对象中查找,

如果没有查找到,要去对象的原型中查找

如果还没有查找到,要去当前对象的原型的原型中查找

以此类推……直到找不到,返回undefined

  1. 继承

    儿子 继承 父亲

    Child.prototype = new Parent();

    function Parent() {
    this.name = '张三';
    }
    function Child() {
    this.age = 18;
    }
    // 把父对象给子原型、实现了原型继承
    Child.prototype = new Parent();
    var obj = new Child();
    console.log( obj.name );

    image-20240606000652423

    function Hero() {
    this.name = 'nihao';
    this.sayMe = function() {
    alert('this is nihao');
    }
    }
    Hero.prototype.name = 'hellow';
    Hero.prototype.sayMe = function() {
    alert('this is hellow');
    }
    var hero = new Hero();
    console.log( hero.name ); // nihao
    console.log( hero.sayMe ); // function() {alert('this is nihao');}
    function Foo() {
    getName = function(){
    alert(1);
    }
    return this;
    }
    Foo.getName = function() {
    alert(2);
    }
    Foo.prototype.getName = function() {
    alert(3);
    }
    var getName = function() {
    alert(4);
    }
    function getName() {
    alert(5);
    }
    Foo.getName(); // 2
    getName(); // 4
    Foo().getName(); // 1
    getName(); // 1
    new Foo().getName(); // 1

    image-20240606002840738

  2. 借用构造函数

    字面量的字符串,new String()

    var str1 = '123'          // string
    var str2 = new String() // 对象
    str1 借用了new String的属性和方法

    每次生成一个对象,对象本身的属性和方法不共享

    改变this指向:call、apply、bind

    function Parent() {
    this,name = '张三'
    this.arr = [1,2,3];
    }
    function Child() {
    // 让Parent的this指向于对象
    Parent.call(this);
    this.age = 20;
    }
    // obj1.arr[0] = '你好' obj1会被修改,obj2不会
    var obj1 = new Child();
    var obj2 = new Child();
    console.log( obj1.name,obj2.name );

    image-20240606084402296

  3. 组合继承

    还有很多继承方式:寄生继承

    原型:

    • 共享属性和方法
    • 无法向父构造函数传递参数

    借用构造函数:

    • 可以向父构造函数传递参数
    • 不可以共享

    组合继承:

    • 既可以传递参数,也可以实现该有的共享性
    function Parent(cName) {
    this.name = cName;
    }
    Parent.prototype.run = function() {

    }
    function Child(cName) {
    this.age = 20;
    // 借用构造函数
    Parent.call(this,cName);
    }
    // 原型
    Child.prototype = new Parent();

    Child obj1 = new Child('111');
    Child obj2 = new Child('222');
    console.log( obj1.name,obj2.name );
    console.log( obj1.run === obj2.run );

    image-20240606090330333

二十七、前端性能优化

  1. 一个网站打开速度多少合适

    PC:4s内 移动端:3s内

  2. 浏览器的渲染过程

    视觉变化【js操作】–> style –> layout【布局】 –> point【绘制】 –> composite【合并】

  3. 当在浏览器输入一个url,按回车会经历什么步骤
    1. 通过浏览器的解释器,把文本【代码】,解析成html
      1. dom树
      2. css树
    2. 然后进行合并,并且渲染
  4. layout 布局 –> 造成回流【css改变动画】

    增加/删除元素

    移动/改变大小元素:offsetLeft、scrollTop、style.width

    修改浏览器大小和字体大小

  5. js优化需要注意

    原型链

二十八、debugger和try

ReferenceError:非法或者不能识别的引用数值

SyntaxError:发生语法解析错误

TypeError:操作类型错误

try … catch:让错误代码不影响后续代码进行

二十九、jQuery

  1. jQuery使用
    1. jquery引入
      <script type = "text/javascript" src = 'js/jquery.js'></script>
    2. 开头格式
      $(function(){
      $('ul li').css('background','pink');
      })
  2. jQuery中的选择器
    1. 基本选择器
      • #id $('#id名称')
      • .class $('.class名称')
      • element $('div')
      • * 几乎不用
      • selector1,selector2,selectorN $('div,span,p...')
      • :first 选择到第一个
      • :not(:selector) 去除所有与给定选择器匹配的元素
      • :even 匹配到所有索引变量偶数的元素,从0开始计数
      • :odd 匹配到所有索引变量奇数的元素,从0开始计数
      • :eq(index) 匹配一个给定的索引的元素,从0开始计数
      • :gt(index) 匹配所有大于给定索引值的元素,从0开始计数
      • :last 选择到最后一个
      • :lt(index) 匹配所有小于给定索引值的元素,从0开始计数
    2. 层级选择器
      • ancestor descendant 在给定的祖先元素下匹配所有的后代元素
      • parent > child 在给定的父元素下匹配所有的子元素
      • prev + next 匹配兄弟的下一个,下一个兄弟
      • prev ~ siblings 匹配下所有【平级关系】兄弟
    3. 内容选择器
      • :contains(text) 含有这个文本的节点,模糊搜索

        <ul>
        <li>1123你好23232</li>
        <li>11不好2</li>
        <li>aff我有100万好不好dfdfd</li>
        <li>aff23232d</li>
        <li>aff23232d</li>
        <li>kfjdf</li>
        <li></li>
        </ul>
        <script type = "text/javascript" src = 'js/jquery.js'></script>
        $(function(){
        $('ul li:contains(好)').css('background','pink');
        })
      • :empty 选取到不含子元素的元素

        $('ul li:empty').css('background','pink');
      • :has(selector) 选取到只有一个子元素

      • :parent 选取到含有某一个元素的元素

    4. 可见性选择器
      • :hidden 匹配所有不可见元素,或者type为hidden的元素
      • :visible 匹配所有可见的元素

      一般在判断的时候使用可见性选择器

      <ul>
      <li>苹果</liOPPO>
      <li>OPPO</li>
      <li>VIVO</li>
      <li>小米</li>
      <li>索尼</li>
      <li id="more">更多</li>
      </ul>
      $(function(){
      // 选择到所有的Li,大于索引2的隐藏掉,并且排除掉最后一个
      var lis = $('ul li:gt(2):not(:last)').css('display','none');
      $('#more').click(function(){
      // 如果是显示 的就隐藏掉,否则就显示
      if (lis.is(":visible")) {
      lis.css('display','none');
      $('#more').text('收起');
      } else {
      lis.css('display','block');
      $('#more').text('更多');
      }
      })
      })
  3. 对象之间的转换
    1. jquery对象转换为dom对象

      $('#main')[0] || $('#main').get(0 )

    2. dom对象转换为jquery对象

      var mian = document.getElementById('main')

      $(main) 这里是转换

  4. 节点查找的方法
    1. 子节点

      children() 查找的是子节点

      find() 查找所有指定后代元素

    2. 父节点

      parent() 查找到父节点

      parents('元素') 查找到指定的祖先元素

    3. 兄弟节点

      next() 下一个兄弟,不包括自己

      nextAll() 下所有兄弟,不包括自己

      prev() 上一个兄弟,不包括自己

      prevAll() 上所有兄弟,不包括自己

      siblings() 上下所有兄弟,不 包括自己

      $('#lis').nextAll().css('background','blue);

  5. CSS类
    1. addClass() 添加class

      $('#main').addClass('o');
    2. removeClass() 删除class

      如果不加参数,删除所有class的值

      如果加参数,删除指定class的值

      $('#main').addClass('o').removeClass();
    3. toggleClass() 做切换的,如果存在(不存在)就删除(添加)一个类

  6. 过滤方法

    eq()

    first()

    last()

    eq、first、last方法和选择器的功能是一模一样的

    filter 筛选出与指定表达式匹配的元素集合

    is 根据选择器、DOM元素或jQuery对象来检测匹配元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true

    slice 字符串或者数组的slice完全一样

  7. 插入节点
    1. 内部插入

      append(content|fn) 与appendChild类似

      // 添加到内部的最后
      $('#main').append('<h1>这是h1</h1>')

      appendTo(content)

      prepend(content|fn)

      // 添加到内部的前面
      $('#main').prepend('<h1>这是h1</h1>')

      prependTo(content)

      语法:

      1. append、prepend =====》 父元素.方法名称(子元素)
      2. appendTo、prependTo ====》 子元素.方法名称(父元素)
    2. 外部插入

      after(content|fn) 平级插入,插入在当前的下面

      before(content|fn) 平级插入,插入在当前的上面

      insertAfter(content)

      insertBefore(content)

      语法:

      1. after、before =====》 当前元素.方法名称(插入语元素)
      2. appendTo、prependTo =====》 子元素.方法名称(父元素)
  8. 删除节点和属性
    1. 删除节点

      js原生中用 removeChild 删除节点

      jquery中使用 remove() 来删除节点

      $('#uls a').click(function(){
      $(this).parent().remove();
      })
    2. 属性

      1. attr

        获取匹配的元素集合中的第一个元素的属性的值 或 设置每一个匹配元素的一个或多个属性

        js原生中设置属性或者获得属性的值用 setAttributegetAttribute 方法

        jquery用 attr() 来获取或者设置属性、1个参数是获取属性的值,2个参数是设置属性

      2. prop

        获取匹配的元素集合第一个元素的属性(property)值或设置每一个匹配元素的一个或多个属性

  9. 文本值

    html() js原生中的 innerHTML

    text() js原生中的 innerText

    val() js原生中 value

    获取:

    • 选择器.方法名称

    赋值:

    • 选择器.方法名称(赋值的内容)
  10. 尺寸
    • height([val|fn])

    • width([val|fn])

      • 只是单纯的返回width和height
    • innerHeight()

    • innerWidth()

      • width + padding
    • outerHeight([soptions])

    • outerWidth([options])

      • width + padding + border

      • 如果参数为true,则:width + padding + border + margin

  11. 位置
    • offset().left 当前元素距离浏览器左侧的偏移量

    • offset().top 当前元素距离浏览器顶部的偏移量

    • scrollTop

    • scrollLeft

  12. 事件
    // js原生的事件
    var main = document.getElementById('main');
    main.onmouseover = function() {
    alert(1);
    }
    // jquery事件的写法区别
    $('#main').mouseover(function(){
    alert(1);
    })
    1. 事件绑定

      bind(type,[data],fn)

      // 无法执行
      $('#txt').input(function() {
      alert(1);
      })
      // 可以执行
      $('#txt').bind('input',function() {
      alert(1);
      })
    2. 事件委托

      $(父元素).on('事件名称','子元素',函数)

    3. 事件对象

      eve.pageX 类似于js原生的 e.clientX

      eve.pageY 类似于js原生的 e.clientY

      鼠标距离浏览器左侧【顶部】的距离

      event.preventDefault() 阻止默认行为

      event.stopPropagation() 阻止冒泡

  13. 循环遍历

    方式一:

    $(选择器).each(function(index,item){})

    方式二:

    $.each(要遍历的对象,function(index,item){ // 循环体 })

    区别:

    当遍历一个jquery对象的时候可以用方式一

    当遍历一个对象或者数组的时候,可以用方式二、

  14. jQuery自带动画
    1. 基本动画

      show()

      hide()

      可以加入参数,就是动画完成的毫秒数

    2. 滑动动画

      slideDown([s],[e],[fn])

      slideUp([s,[e],[fn]])

    3. 淡入淡出

      fadeIn()

      fadeOut()

    注意stop可以清空队列

    $(this).find('ul').stop().slideUp();
  15. 自定义动画

    animate(要改变的样式,毫秒数,回调函数)

    animate({
    margin:'10px',
    padding:'10px',
    color:'#000'
    ...
    },500,function() {
    alert(1);
    })
    <div id='main'class='main'> 111 </div>
    $(function() {
    $("#main").aminate({
    'padding':'100px',
    'margin':'20px'
    },500,function() {
    alert(1);
    })
    })

    无缝滚动

  16. jQuery插件写法

    插件:让代码更具有复用性

    1. 插件机制的方法

      $.fn.extend(object) 扩展 jQuery

      元素集来提供新的方法(通常用来制作插件)

      • $('ul li').扩展一个方法()、局部插件

      $.extend(object) 扩展jQuery对象本身、$扩展方法、全局插件

    2. 如何写jquery插件

      先引入jQuery再引入插件

      <script type="text/javascript" src='juqery-1.11.min.js'></script>
      <script type="text/javascript" src='jquery.nav.js'></script>
    3. 插件的命名规范

      jquert.插件名称.js

    4. 插件内部写法

      1. 开始是匿名函数自执行

        // 全局
        (function() {
        $.extend({
        'nav':function(){
        alert(1);
        return this;
        }
        })
        })();
        <script>
        $(function(){
        // 使用插件
        $.nav();
        })
        </script>
        // 局部
        (function() {
        $.fn.extend({
        'nav':function(){
        $(this).find('li').click(function(){
        $(this).hide();
        })
        return this;
        }
        })
        })();
        <script>
        $(function(){
        // 使用插件
        $('ul').eq(2).nav();
        })
        </script>

三十、json格式

  1. 什么是json

    存入数据的格式,轻量级交换数据的一种格式

    // 普通对象格式
    var obj = {
    userName:'张三',
    age:18,
    arr:['a','b','c'],
    'margin-left':'20px'
    }
    console.log(obj['margin-left']);
  2. json数据存放
    1. json中不能有单引号

    2. json中的key必须要加入双引号

    3. json中是数据,不能写函数

      // 完美的json格式
      {
      "userName":"张三",
      "age":20,
      "arr":["a","b","c"],
      "o":{
      "a":10
      }
      }

三十一、ajax

  1. 什么是ajax

    一种创建”快速” “动态”的网页技术

  2. 原生js操作ajax
    1. http请求方式

      GET:用户获取数据,get是在url上传递数据,存储量较少,安全性较低

      POST:用户上传数据,post容量几乎是无限的

    2. 异步操作

      同步

      异步

    3. 操作ajax
      1. 创建ajax对象

        new XMLHttpRequest()

        var xhr = new XMLHttpRequest()
      2. 连接服务器

        ajax对象.open(请求方式[get|post],请求的url,异步|同步)

        异步:true

        同步:false

        xhr.open('GET','data.json',true)
      3. 发送请求

        ajax对象.send(给后端的数据,如果没有数据就写null)

        xhr.send(null)
      4. 接收返回值

        ajax对象.onreadystatechange:事件、当请求被发送到服务器时,我们需要执行基于响应的操作

        ajax对象.readyState:请求的状态码

        • 0(未初始化)open还没有调用
        • 1(载入)已经调用send,正在发送请求
        • 2(载入完成)send完成了,已经收到全部响应了
        • 3(解析)正在解析内容
        • 4(完成)响应内容解析完成,可以在客户端用了

        ajax对象.status:返回请求结果码

        • 200成功
        • 404未找到
        • 500服务器错误

        返回内容:ajax对象.reponseText

      // 创建ajax对象
      var xhr = new XMLHttpRequest();
      // 连接服务
      xhr.open('POST','http://39.101.217.150:8075/banner/list',true);
      // 发送请求
      xhr.send(null);
      // 接收返回值
      xhr.onreadystatechange = function() {
      if(xhr.status == 200 && xhr.readyState == 4) {
      var data = JSON.parse(xhr.responseText);
      console.log(data);
      }
      }

三十二、jQuery操作ajax

  1. $.ajax(url,[settings])
    $.ajax({
    // url:请求的路径
    url:'http://39.101.217.150:8075/banner/list',

    // 默认为true异步请求,false同步请求
    async:

    // 发送信息至服务器时内容编码类型
    contentType:

    // 前端给后端的数据
    data:

    // 预期服务器返回的数据类型
    dataType:

    // 请求方式 默认:get
    type:"POST"

    // 请求成功后的回调函数
    success:function(data) {
    console.log(data);
    }
    })
  2. 跨域

    前端:jsonp

    后端:cors