前端js基础

1.递归函数

一个函数调用了自身,并设置了结束条件,这个函数才是正确的递归函

案例:斐波那契数列,1,1,2,3,5,5......第一位和第二位必然是1,从第三位开始都是前两位的和,求数列n位?

function(n){
    if(n === 1 | n === 2){
        return 1
    }
    return fn(n-1) + fn(n-2)
}

2.作用域

全局作用域:一个页面就是一个全局作用域

私有作用域:只有函数可以生成私有作用域

使用包括:定义 使用 赋值

变量定义机制:

定义在哪一个作用域下的变量,就是哪一个作用域下的私有变量,只能在该作用域及其后代作用域中使用;

变量赋值机制:

当给一个变量赋值的时候,如果自己作用域内有该变量,那么给自己赋值,如果自己作用域没有该变量,那么给父级作用域变量赋值,如果父级还没有就载父级的变量赋值,以此类推,直到window(全局作用域)都没有这个变量,那么就这个变量定义为全局变量,再进行赋值;

变量访问机制:

当需要获取一个变量的值的时候,首先在自己作用域中查找,如果有直接使用,停止查找;如果没有,访问父级该变量,如果还没有,继续访问再父级,直到全局作用域都没有就报错。

 3.预解析  (let  const  不会参加预解析)

在所有代码执行之前,对代码进行通读并解释

解析var关键字,会把var关键字声明的变量进行提前说明,但不进行赋值;

解析了声明式函数,会把函数名进行提前声明,并且赋值为一个函数;

预解析无节操:在代码中,不管if条件是否为true,if语句里边的内容依然会进行预解析,在函数体内,return后边的代码虽然不执行,但会进行预解析,当var 声明变量与声明式函数重名时,预解析阶段以函数为主;

4.数组方法

new Array()

数组.push(数据):向数组尾部追加数据,返回数组最新长度

pop:删除数组的最后一位数据,返回被删除数据

unshift: 在数组最前面插入数据,返回最新长度

shift:删除数组最前面的一个数据,返回被删除数据

reverse:反转数组,返回反转后的数组

sort:把每一个数据的一位一位的看待进行排序,返回排序后的数组

升序排列:

arr.soort(function(a,b){
  
  {return a - b})

splice(开始索引,多少个)

splice(开始索引,多少个,要插入的数据)

截取数组,并选择性是否插入内容,返回一个新的数组,内容是截取出来的数组,无截取内容将返回空数组

以下方法不会改变原始数组,以返回值的形式给到结果

arr.concat(数据,数组,...) 数组拼接,返回拼接好的数组

join('连接符') : 不写连接符,默认用逗号,使用连接符把数组中的每一项连接成为一个字符串,返回连接好的字符串

slice(开始索引,结束索引):截取数组,包前不包后,负值相当于负值+length,返回截取出来的新数组

indexOf(数据,开始索引) 开始索引选填,默认是0,从开始索引检索该数组是否有该数据,有就返回第一次出现索引位置,没有该数据返回-1

lastIndexOf(数据,开始索引) 从开始索引向前检索该数组是否有该数据,有就返回第一次出现索引位置,没有该数据返回-1

arr.forEach(function(item,index,arr))  用来遍历,返回undefined

map 映射数组,返回一个新数组,并且和原数组长度保持一致,映射条件以return形式书写

filter 过滤数组,返回原数组内满足条件的项组成的新数组,条件以return形式书写

every 判断数组的每一项是不是都满足条件,每一项都满足条件返回true,否则返回false,判断条件以return形式书写(对于空数组调用.every方法会返回true。这是因为在空数组上没有任何元素会导致回调函数返回false,所以.every方法的默认行为是返回true。)

some 判断数组中是不是有满足条件的,有任意一个满足条件的返回true,全不满足条件返回false

find 查找数组中某一数据,返回满足条件的第一个元素的值,而不是数组,查找形式以return书写

arr.reduce(function(prev,item,index,arr)) 多了一个参数,prev是初始值或每一次叠加后的结果

5.字符串方法

str.charAt(索引) 返回该索引位置对应字符,如果没有用该索引位置,就返回空字符串

charCodeAt(索引) 该索引位置对应的字符的编码(十进制)

toUpperCase() 把所有字母转成大写,返回转换好的字母

toLowerCase() 把所有字母转成小写,返回转换好的字母

substr(开始索引,多少个) 截取字符串,返回截取出来的字符串

substring(开始索引,结束索引)截取字符串,包前不包后,返回截取出来的字符串

slice(开始索引,结束索引)截取字符串,包前不包后,可以负整数,返回截取出来的字符串

replace(换下字符串,换上字符串) 使用换上字符串替换掉换下字符串,只替换出现的第一次,返回替换好的字符串

1.基本替换(只替换第一个匹配项):"Hello world".replace("world", "JavaScript"); 

 // "Hello JavaScript"

2.使用正则表达式进行全局替换:Hello world, hello JavaScript".replace(/hello/gi, "hi")

// "Hi world, hi JavaScript"

3.使用函数作为替换值:"apple banana apple".replace(/apple|banana/g, function(match) { return match.toUpperCase(); });

str2.replace(regex, match => `<span style="color:red">${match}</span>`);

split('切割字符串') 按照切割字符串,把字符串割开,放在一个数组里,返回切割成的新数组(不传递会把字符串当做一个整体,传递一个空的字符串'',会一位一位的切割)

concat(字符串) 字符串拼接 返回拼接好的字符串

indexOf(字符,开始索引) 检测该字符在字符串内的索引位置,并返回,如果没有该字符内容返回-1

lastIndexOf(字符,开始索引) 从后向前检测该字符在字符串内的索引位置,并返回,如果没有该字符内容返回-1

trim() 去除字符串首位空白内容,返回去除空白内容后的字符串

6.对象

一个键值对的集合,是一个复杂数据类型

创建对象:字面量方式 var obj = {key:value}(可以创建带有数据的对象)

内置构造函数方式  var obj = new Object()

点语法:

增   对象名.键名 = 值

删  delete 对象名.键名

改  对象名.键名 = 值

查 对象名.键名

数组关联语法:

增   对象名['键名'] = 值

删  delete 对象名['键名']

改  对象名['键名'] = 值

查 对象名['键名']

7.数字常用方法

Math.random()  获取0-1的随机整数,包0不包1,并返回

round(number) 四舍五入取整后的结果

ceil (number) 向上取整以后的结果

floor (number) 向下取整以后的结果

abs(number)  取绝对值以后的结果

pow(底数,指数)取幂后的结果

sqrt(number) 该数字的算术平方根

max() min() 取n个数字中的最大值、最小值

PI 近π的值

number.toFixed(保留几位小数)  返回字符串类型

parseInt(数字,几进制)  把数字当几进制使用转成十进制

8.时间方法

new Date() 获取当前终端时间信息

时间对象.getFullYear() 返回时间对象内的年份信息

getMonth  0表示1月

getDate

getHours

getMinutes

getSeconds

getMilliSeconds

getDay 返回周几,0代表周一

getTime 返回该时间对象的时间戳

9.BOM (操作浏览器的属性和方法)

BOM的顶级对象是window,所有和BOM相关的内容都是window.xxx... ,window可以省略

innerWidth  /  innerHeight  窗口尺寸包含滚动条在内

location  window的一个成员,里边存储的都是地址栏的相关内容

location.href   得到当前页面地址栏的完整信息(属于url编码格式的地址)

location.href = 'abc' 可以用来修改当前地址栏

location.reload()  刷新当前页面,不能写在打开页面就执行的地方

history.back() 回到上一个历史记录页面

history.forward() 去下一个历史记录页面

history.go(数字) 历史记录页面跳转,0是重新打开当前页面,负数是历史回退,正数是历史前进

open('地址') 开启新的标签页,打开指定地址

close('地址') 关闭当前标签页

onload = ()=>{} 页面资源加载完成后触发

onresize = ()=>{} 页面可视窗口大小改变触发

onscroll = ()=>{} 页面滚动条位置改变时触发

scrollTo(卷去的宽度,卷去的高度)    浏览器滚动到

scrollTo({top: y, left: x, behavior: 'smooth'})    浏览器滚动到(可以通过第三个成员实现平滑滚动)

浏览器卷去高度和宽度:

document.documentElement.scrollTop    当前页面有DOCTYPE标签时使用

document.body.scrollTop      当前页面无DOCTYPE标签时使用

document.documentElement.scrollLeft   当前页面有DOCTYPE标签时使用

document.body.scrollLeft      当前页面无DOCTYPE标签时使用

10.DOM 操作文档流的属性和方法(操作页面元素)

获取元素

document.documentElement   html

document.head   head

document.body   body

document.getElementByClassName('')  返回值是伪数组

document.querySelect('选择器')  返回满足条件的第一个元素

元素.innerText    元素内的所有文本内容(读写属性)

元素.innerHtml    元素内的所有内容,以字符串形式返回(读写属性)

表单元素.value 

操作元素属性

元素.属性名      读写原生属性

元素.getAttribute('属性名')   获取自定义属性值

元素.setAttribute('属性名','属性值')   设置自定义属性

元素.removeAttribute('属性名')   删除自定义属性

classList   记录了元素的所有类名 

元素.classList.add('要添加的类名')

元素.classList.remove('要删除的类名')

元素.classList.toggle('要切换的类名') 由此类名就删除,没有就增加

11.元素尺寸和偏移

元素.offsetWidth / Height  元素尺寸:内容+padding+border区域的尺寸

clientWidth / Height  元素尺寸:内容+padding区域的尺寸

offsetLeft  / Top 元素相对于参考元素的左边 / 上边的距离(元素偏移量参考元素是定位父级)

12.this指向

全局使用this是window,在函数内this是该函数的执行上下文,函数内的this和函数如何定义,在哪定义没关系,只看函数是如何调用的,箭头函数除外;

普通调用:    函数名()   该函数的this指向window

对象调用  对象名.函数名()   该函数的this指向点前边的内容

定时器处理函数  this指向window

事件处理函数    事件源.on事件类型 = 事件处理函数  this指向事件源

自执行函数  this指向window 

强行改变this指向

call()  修改函数的this指向,立即调用函数,参数1是函数内的this指向,从参数2开始依次给函数传实参

apply()  修改函数的this指向,改变函数传递参数的方式,立即调用函数,参数1是函数内的this指向,从参数2是数组或伪数组都可以里边的每一项依次给函数传参

bind()  修改函数的this指向,不会立即调用函数,返回一个新的函数,参数1是函数内的this指向,从参数2开始依次给函数传参

13.Promise

Promise是js中进行异步编程的一种新的解决方案(旧的方案是单纯的使用回调函数)

从语法上来说,Promise是一个构造函数

从功能上来说,Promise对象用来封装一个异步的操作并可以获取成功或者失败的结果值

Promise 也有三个状态

=> 继续: pending  (待办的)

=> 成功: fulfilled(已履行)

=> 失败: rejected (拒绝了)

const p = new Promise((resolve,reject) => {
        let n = rand(1, 100);
        if(n <= 30){
                resolve();  //将Promis对象的状态设置为成功

        }else{
                reject();  //将Promis对象的状态设置为失败
        }

} );

p.then(()=>{alert('中奖')},()=>{alert('未中奖')})

 Promises调用传值

const p = new Promise((resolve,reject) => {

        let n = rand(1, 100);

        if(n <= 30){

                resolve(n);  //将Promis对象的状态设置为成功

        }else{

                 reject(n);  //将Promis对象的状态设置为失败

        }

} );

p.then((value)=>{alert('中奖号码为' + value)},(reason)=>{alert('未中奖号码为' + reason)})

14.export与export default
 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。export与export default均可用于导出常量、函数、文件、模块等
可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
在一个文件或模块中,export、import可以有多个(export 可以导出多个命名模块),export default仅有一个

  • 输出单个值,使用export default
  • 输出多个值,使用export
  • export default与普通的export不要同时使用
  • 通过export方式导出,在导入时要加{ },export default则不需要

(1)export的输出与import输入

  1. export function output() {

  2. // ...

  3. }

  4. import {output} from './example'

(2)export default的输出与import输入

  1. export default function output() {

  2. // ...

  3. }

  4. import output from './example'

15.void

指定方法类型,表示没有返回值,方法体中不能return

function aa(): void {
  console.log(1);
}

//如果方法有返回值,可以加上返回值的类型
function bb(): number {
  return 1;
}

16.闭包

+ 概念: 函数内的函数

+ 特点:

1. 延长变量的声明周期

=> 优点: 变量生命周期延长了

=> 缺点: 需要一个 闭包 结构

2. 可以在函数外部访问函数内的私有变量

=> 优点: 访问和使用变得更加灵活了

=> 缺点: 需要一个 闭包 结构

3. 保护变量私有化

=> 优点: 变量不会污染全局

=> 缺点: 外部没有办法使用, 如果需要使用, 得写一个 闭包 结构

+ 出现:

=> 需要一个不会销毁的函数执行空间

=> 函数内 直接 或者 间接 返回一个新的函数

=> 内部函数要使用着外部函数的私有变量

=> 我们管 内部函数(fnB) 叫做 外部函数(fnA) 的 闭包函数

function fnA() {
// 外部函数的 私有变量
var num = 100
var str = 'hello world'

function fnB() {
return num
}

return fnB
}

const res = fnA()

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

闭包函数:声明在一个函数中的函数,叫做闭包函数。

闭包特点

  让外部访问函数内部变量成为可能;

  局部变量会常驻在内存中;

  可以避免使用全局变量,防止全局变量污染;

  会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

闭包的创建:­­­
闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,互不干扰。闭包会发生内存泄漏,每次外部函数执行的时 候,外部函数的引用地址不同,都会重新创建一个新的地址。但凡是当前活动对象中有被内部子集引用的数据,那么这个时候,这个数据不删除,保留一根指针给内部活动对象。

闭包的应用场景
结论:闭包找到的是同一地址中父级函数中对应变量最终的值最终秘诀就这一句话,每个例子请自行带入这个结论!

/* 例子1 */

function funA(){
  var a = 10;  // funA的活动对象之中;
  return function(){   //匿名函数的活动对象;
        alert(a);
  }
}
var b = funA();
b();  //10
/* 例子2 */

function outerFn(){
  var i = 0; 
  function innerFn(){
      i++;
      console.log(i);
  }
  return innerFn;
}
var inner = outerFn();  //每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同,都会重新创建一个新的地址
inner();
inner();
inner();

var inner2 = outerFn();

inner2();

inner2();

inner2(); //1 2 3 1 2 3

17.构造函数

构造函数也是一个函数,只不过使用的时候需要和 new 关键字连用
书写构造函数首字母大写(规范),为了和普通函数做一个区分
构造函数的调用必须和 new 关键字连用(规范)
书写构造函数的意义, 就是为了批量创建对象
构造函数内不要写 return
return 一个基本数据类型的时候, 写了白写
return 一个复杂数据类型的时候, 构造函数白写
构造函数内的 this
因为函数调用和 new 关键字连用,this 会指向自动创建出来的那个对象
又因为这个对象会被自动返回, 赋值给本次调用是前面的那个变量
this 指向 new 前面定义的变量
构造函数自动创建对象的过程, 叫做 实例化的过程,构造函数创建出来的对象, 起名叫实例对象
构造函数内的 this 指向当前实例

18.原型原型链

每一个函数天生自带一个属性, 叫做 prototype, 是一个对象数据类型
构造函数也是一个函数, 所以构造函数也有 prototype
这个天生自带的 prototype 内有一个叫做 constrictor 的属性,表名我是谁自带的 prototype,指向自己的构造函数
是一个对象, 就可以向里面添加一些成员
每一个对象天生自带一个属性, 叫做 __proto__, 指向所属构造函数的 prototype
实例对象也是一个对象, 所以实例对象也有 __proto__
对象访问机制:当你需要访问一个对象的成员的时候, 首先, 会在对象自己本身身上查找, 如果有, 直接使用, 停止查找,如果没有, 会自动去自己的 __proto__ 上查找

原型: 每个函数天生自带的 prototype 对象数据类型
作用: 由构造函数向 原型上 添加方法, 提供给该构造函数的所有实例使用
为了解决构造函数将方法书写在构造函数体内时造成的资源浪费

原型链:
概念: 用 __proto__ 串联起来的对象链状结构
作用: 为了对象访问机制服务(当你访问一个对象成员的时候, 为你提供一些服务)
只是 __proto__ 串联起来的对象链状结构, 千万不要往 prototype 上靠

19.switch

 switch (要判断的变量) {
    case 情况1:
      情况1要执行的代码
      break
    case 情况2:
      情况2要执行的代码
      break
    case 情况3:
      情况3要执行的代码
      break
    default:
      上述情况都不满足的时候执行的代码
  }
  var week = 1
  switch (week) {
    case 1:
      alert('星期一')
      break
    case 2:
      alert('星期二')
      break
    case 3:
      alert('星期三')
      break
    case 4:
      alert('星期四')
      break
    case 5:
      alert('星期五')
      break
    case 6:
      alert('星期六')
      break
    case 7:
      alert('星期日')
      break
    default:
      alert('请输入一个 1 ~ 7 之间的数字')
  }

20.复杂数据

基本数据类型, 直接存储在 栈内存 中
复杂数据类型, 数据存储在 堆内存 中, 把地址赋值给 栈内存 中的变量
复杂数据类型, 因为变量内存储的是地址, 所以赋值的也是 地址
赋值以后, 两个变量操作一个 数据存储空间
使用任何一个变量修改空间内的数据, 另一个变量看到的也是变化以后的
复杂数据类型, 是 地址 和 地址 之间的比较

21.冒泡排序

第一个数字和第二个数字进行比较, 如果第一个比第二个大, 就交换位置
以此类推, 直到数组遍历完毕, 最大的一定在最后面
重复执行第一轮的操作, 直到所有数字排好
    for (var i = 0; i < arr.length - 1; i++) {
      for (var j = 0; j < arr.length - 1 - i; j++) {
        if (arr[j] > arr[j + 1]) {
          var tmp = arr[j]
          arr[j] = arr[j + 1]
          arr[j + 1] = tmp
        }
      }
    }

22.查询字符串传&json

查询字符串-queryString: 'name=zhangsan&password=123456&gender=男'
json格式字符串: '{ "name": "Jack", "age": 18 }'
json的key和value必须使用双引号包裹, 纯数字和布尔值可以不用
JSON.stringify() 把js的数据类型转换成 json
JSON.parse() 把json格式转换成 js 的数据类型

23.事件

事件绑定:

1. DOM 0级 事件

=> 语法: 事件源.on事件类型 = 事件处理函数

=> 注意: 给一个事件源的同一个事件类型, 只能绑定一个事件处理函数

2. DOM 2级 事件(事件侦听器 / 事件监听器)

2-1. 标准浏览器

  => 语法: 事件源.addEventListener('事件类型', 事件处理函数)

  => 特点:

    -> 可以给同一个事件源的同一个事件类型绑定多个事件处理函数

    -> 多个事件处理函数, 顺序绑定, 顺序执行

2-2. IE 低版本

  => 语法: 事件源.attachEvent('on事件类型', 事件处理函数)

  => 特点:

    -> 可以给同一个事件源的同一个事件类型绑定多个事件处理函数

    -> 多个事件处理函数, 顺序绑定, 倒序执行

事件解绑

1. DOM 0级 事件解绑

=> 语法: 事件源.on事件类型 = null

=> 因为赋值符号, 当你给这个事件类型赋值为 null 的时候

  -> 会把本身的事件处理函数覆盖

  -> 当你再次出发行为的时候, 没有事件处理函数执行

  -> 相当于解绑了事件

2. DOM 2级 事件解绑

2-1. 标准浏览器解绑

  => 语法: 事件源.removeEventListener('事件类型', 事件处理函数)

2-2. IE 低版本解绑

  => 语法: 事件源.detachEvent('on事件类型', 事件处理函数)

+ 注意:

  => 当你使用 DOM 2级 事件解绑的时候

  => 因为函数是一个复杂数据类型, 所以你在绑定的时候

  => 需要把函数单独书写出来, 以函数名的形式进行绑定和解绑

鼠标事件

1. click: 鼠标左键单击

2. dblclick: 鼠标左键双击

3. contextmenu: 鼠标右键单击

4. mousedown: 鼠标按下(任何一个按键按下)

5. mouseup: 鼠标抬起

6. mousemove: 鼠标移动(光标只要位置变换就会触发)

7. mouseover: 鼠标移入(光标从外面进入事件源范围内)

8. mouseout: 鼠标移出(光标从事件源内部离开)

9. mousenter: 鼠标移入

10. mouseleave: 鼠标移出

键盘事件

  + 依赖键盘行为触发的事件

  + 注意:

    1. 所有元素都可以绑定键盘事件, 但是不是谁都能触发

      => 一般可以有 window / document / 表单元素 触发

    2. 触发键盘事件, 一般不去考虑中文输入法

1. keydown: 键盘按下事件

  => 键盘上任何一个按键按下都会触发

2. keyup: 键盘抬起事件

  => 键盘上任何一个按键抬起都会触发

3. keypress: 键盘键入事件

  => 必须要按下可以真实键入内容的按键或者回车键

  => 键入的内容必须和按下的内容一致

表单事件

1. focus: 聚焦事件

2. blur: 失焦事件

3. change: 改变事件

  => 要求 聚焦 和 失焦 的时候, 内容不一致, 才会触发

4. input: 输入事件

  => 只要表单元素输入内容或者删除内容, 就会实时触发

5. reset: 重置事件

  => 事件需要绑定给 form 标签

  => 由 form 标签内的 reset 按钮触发

6. submit: 提交事件

  => 事件需要绑定给 form 标签

  => 由 form 标签内的 submit 按钮触发

触摸事件(移动端事件) 

      1. touchstart

        => 触摸开始: 表示手接触到屏幕的瞬间

      2. touchmove

        => 触摸移动: 表示手在屏幕上移动的时候

      3. touchend

        => 触摸结束: 表示手离开屏幕的瞬间

事件对象信息 - 鼠标事件

  + 坐标点

1. clientX 和 clientY

  => 光标相对于浏览器可视窗口左上角的坐标位置

2. pageX 和 pageY

  => 光标相对于文档流左上角的坐标位置

3. offsetX 和 offsetY

24.冒泡和捕获

事件的目标冒泡和捕获

事件冒泡: 在事件传播的过程中, 从 目标 到 window 的过程

事件捕获: 在事件传播的过程中, 从 window 到 目标 的过程

  => 在 IE 低版本内只能按照冒泡的顺序来执行

  => 在标准浏览器下, 事件默认在冒泡阶段执行

  => 可以选择在捕获阶段执行

事件目标: 准确触发事件的那个元素

如何获取事件目标

  + 在事件对象内有一个固定的信息表示本次事件的事件目标

  + 标准浏览器: 事件对象.target

  + IE 低版本: 事件对象.srcElement

  + 兼容: 我们自己定义一个变量来兼容

    => var target = e.target || e.srcElement

如何在捕获阶段执行事件

  + DOM 0级 事件绑定没有办法修改

  + DOM 2级 事件绑定才可以修改事件的执行阶段

    => 通过 addEventListener() 的第三个参数来决定

    => 默认是 false, 表示冒泡阶段

    => 选填是 true, 表示捕获阶段

 阻止事件传播: 不让事件继续传播, 不会触发父级结构的事件函数了

          -> 标准浏览器: stopPropagation()

          -> IE 低版本: cancelBubble = true

  阻止默认行为: 不让元素默认的行为出现

          -> 标准浏览器: preventDefault()

          -> IE 低版本: returnValue = false

  事件委托: 把自己的事件委托给共同的结构父级

25.正则

 如何创建一个正则表达式

        1. 字面量方式创建

          => 语法: var reg = /abcd/

        2. 内置构造函数创建

          => 语法: var reg = new RegExp('abcd')

 正则表达式的常用方法

      1. test() 匹配

        => 语法: 正则表达式.test('要检测的字符串')

        => 返回值: 一个布尔值

          -> 如果该字符串符合正则的规则, 那么就是 true

          -> 如果该字符串不符合正则的规则, 那么就是 false

      2. exec() 捕获

 1. exec() 捕获

        => 语法: 正则.exec(字符串)

        => 作用: 从 字符串中 把满足正则条件的部分获取出来

        => 返回值:

          -> 原始字符串中没有符合正则要求的字符串片段

            + null

          -> 原始字符串中有符合正则要求的片段

            + 正则没有 () 也没有 全局标识符g

              + 返回值是一个数组

              + 索引 0 是从字符串中捕获出来的满足正则条件的第一个内容

              + 注意: 不管捕获多少次, 每次都是从原始字符串的索引 0 开始检索

            + 正则有全局标识符 g

              + 返回值是一个数组

              + 索引 0 是从字符串中捕获出来的满足正则条件的第一个内容

              + 注意: 第二次捕获是从第一次的结束位置开始向后查询, 直到最后捕获不到为止, 再下一次的时候, 又从字符串的 索引0 开始检索

            + 有 ()

              + 返回的是一个数组

              + 索引 0 是从字符串中捕获出来的满足正则条件的第一个内容

              + 从索引 1 开始, 依次是每一个小括号的单独内容

              + 注意: 按照小括号的开始标志, 来数是第几个小括号

 正则表达式的符号 - 基本元字符

      正则表达式的组成部分

        1. 元字符

          => 所有的文本内容

          => 特殊符号, 用符号表示一类内容

        2. 标识符

          => 书写在正则的外面, 用来修饰正则表达式的

      基本元字符

        1. \d   表示 一位 数字

        2. \D   表示 一位 非数字

        3. \s   表示 一位 空白内容(空格/缩进/制表符/...)

        4. \S   表示 一位 非空白内容

        5. \w   表示 一位 数字(0-9)字母(a-zA-Z)下划线(_) 中的任意一个

        6. \W   表示 一位 非数字字母下划线 中的任意一个

        7. .    表示 一位 非换行以外的任意内容

        8. \    表示 转义符

          -> 把有意义的符号转换成没有意义的普通文本

          -> 把没有意义的文本转换成有意义的符号

 元字符 - 边界符号

      1. ^   表示 字符串 开始

      2. $   表示 字符串 结尾

      + 注意: 当 ^ 和 $ 一起使用的时候, 表示的是从开头到结尾

  元字符 - 限定符

        + 注意: 一个限定符只能修饰符号前面的一个内容的出现次数

      1. *     表示出现 0 ~ 多次

      2. +     表示出现 1 ~ 多次

      3. ?     表示出现 0 ~ 1 次

      4. {n}   表示出现 指定 多少次

      5. {n,}  表示出现 至少 多少次

        => {0,} 等价于 *

        => {1,} 等价于 +

      6. {n,m} 表示出现 n ~ m 次

        => {0,1} 等价于 ?

*

      元字符 - 特殊符号

      1. ()

        => 意义1: 一个整体

        => 意义2: 单独捕获(欠着)

      2. |

        => 意义: 或者的意思

        => 注意: 或的边界, 要么是 (), 要么就到正则的边界

      3. []

        => 意义: 包含

        => 注意: 一个 [] 内可以写多个内容, 但是一个 [] 只占一个字符位置, 表示 [] 内的任意一个都行

        => [0-9] 等价于 \d

        => [0-9a-zA-Z_] 等价于 \w

      4. [^]

        => 意义: 非

        => 注意: 一个 [^] 内可以写多个内容, 但是一个 [^] 只占一个字符位置, 表示 [^] 内的任意一个都不行

        => [^0-9] 等价于 \D

        => [^0-9a-zA-Z_] 等价于 \W

      5. - 中划线

        => 意义: 到 至

        => 注意: 需要和 [] 或者 [^] 连用

        => 注意: 需要 ASCII 编码连着的才可以使用

/*

      标识符

        + 书写在正则表达式的外面, 专门用来修饰整个正则表达式的符号

      1. i (ignore)

        => 表示忽略大小写不计

      2. g (global)

        => 全局: 欠着

字符串方法

        + 正则常用方法: 正则.xxx()

        + 字符串常用方法: 字符串.xxx()

      1. replace()

        => 语法:

          -> 字符串.replace('换下字符', '换上字符')

          -> 字符串.replace(正则表达式, '换上字符')

        => 返回值: 替换好的字符串

          -> 当你的第一个参数传递字符串的时候, 只能替换一个

          -> 当你的第一个参数传递正则表达式的时候, 只能替换一个

          -> 但是如果你的正则表达式有全局标识符 g, 那么有多少替换多少

      2. search()

        => 语法:

          -> 字符串.search(字符串片段)

          -> 字符串.search(正则表达式)

        => 作用: 在原始字符串内查找指定内容

        => 返回值:

          -> 原始字符串内有指定内容, 那么就是这个内容的索引

          -> 原始字符串内没有指定内容, 那么就是 -1

      3. match()

        => 语法:

          -> 字符串.match(字符串片段)

          -> 字符串.match(正则表达式)

        => 返回值: 从原始字符串中捕获满足条件的片段

        => 注意: 如果你的参数传递的是字符串或者没有全局标识符g的正则, 那么和 exec 返回值一模一样

          -> 当你的正则有全局标识符 g 的时候, 那么返回值是一个数组

          -> 能从原始字符串内捕获多少, 数组里就有多少内容

26.class

ES6的类语法: ES6 书写构造函数的方式

语法:
class 类名 {}  class是定义类的关键字
1. construcor () {}
  => 等价于 ES5 的构造函数体
2. 原型上的方法
  => 直接在 constructor 的后面书写
  => 方法名 () {}
  => 表示是添加在原型上的方法
3. 类 的 静态方法和属性
  => static 方法名 () {}
  => static 变量 = 值
=> 如果你想写一个方法将来给实例使用, 那么就写成原型方法
=> 如果你想写一个方法将来给类自己使用, 那么就写成静态方法
=> 如果你想写成原型方法, 那么就直接写 ( 方法名 () {} )
=> 如果你想写成静态方法, 那么就直接写 ( static 方法名 () {} )
+ 在使用上
=> 如果你写的就是 ( 方法名 () {} )
=> 那么将来你使用的时候, 要依赖这个类的 实例对象 去调用
-> const p1 = new Person()
-> p1.方法名()
=> 获取在方法内以 this 的形式来调用
-> 方法名 () { this.xxx }
=> 如果你写的是 ( static 方法名 () {} )
=> 那么将来使用的时候要依赖 类名 去调用
-> 类名.方法名()

class Person {
  constructor (name, age) {
    this.name = name
    this.age = age
  }
  sayHi () {
    console.log('hello world')
  }
  sayHi () {}
  static fn1 () { console.log('我是 Person 类的一个静态方法') }
  static a = 100
}

27.ajax

a: async 异步
j: javascript 脚本语言
a: and 和
x: xml 严格的 html 格式

var xhr = new XMLHttpRequest() //创建 ajax 对象
xhr.open('请求方式', '请求地址', 是否异步) // 配置本次请求的信息,默认是异步的
xhr.send() // 把配置好的请求发送出去
xhr.onload = function (console.log(xhr.responseText)) { 代码 } //  配置一个请求完成的事件.同步拿不到响应的方式,所以可以和发送换位置

GET 和 POST 的区别
GET 偏向获取,POST 偏向提交
携带信息的位置不一样
=> GET: 直接在请求地址后面以 查询字符串 的形式进行拼接
=> POST: 是在 请求体 内进行信息的携带
携带信息的大小不一样
=> GET: 原则上可以携带任意大小的数据, 但是会被浏览器限制(IE: 2KB)
=> POST: 原则上可以携带任意大小的数据, 但是会被服务器限制
携带信息的格式不一样
=> GET: 只能携带 查询字符串 格式
=> POST: 可以携带很多格式(查询字符串/json/二进制流/...), 但是需要在发送请求的时候特殊说明一下
安全问题
=> GET: 明文发送, 相对不安全
=> POST: 暗文发送, 相对安全

const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8888/test/third?name=Jack&age=18')
xhr.onload = function (){
  const res = JSON.parse(xhr.responseText)
  console.log(res)
}
xhr.send()

const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:8888/test/fourth')
xhr.onload = function () {
  const res = JSON.parse(xhr.responseText)
  console.log(res)
}
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
 //查询字符串: application/x-www-form-urlencoded
 //json格式: application/json
 //二进制流: mutilpart/data
xhr.send('name=前端小灰狼&age=18')

xhr.onreadystatechange = function () {
// ajax 状态码改变的时候触发
}
ajax 状态码:ajax对象.readyState 
0: 表示创建 ajax 对象成功
1: 表示配置请求信息成功
2: 表示请求已经发送出去, 并且服务器给回的响应已经到了 浏览器
3: 表示浏览器正在解析响应报文, 并且把真实响应体内容逐步赋值给 xhr 的 responseText
4: 表示浏览器解析响应报文完成, xhr 对象内已经有完整的响应体内容了

http状态码:xhr.status,用来描述本次请求的状态
100 ~ 199 => 表示连接继续
200 ~ 299 => 表示各种意义的成功
=> 200 标准成功
=> 201 创建成功
=> 204 删除成功
=> ...
3. 300 ~ 399 => 表示重定向
=> 重定向: 你请求的是 a 服务器地址, 但是 a 服务器把你的请求转嫁到了 b 服务器, 真实给你返回数据的是 b 服务器
=> 301: 永久重定向
=> 302: 临时重定向
=> 304: 缓存
=> ...
4. 400 ~ 499
=> 表示各种客户端错误
=> 404: 地址不对
=> 403: 权限不够
=> ...
5. 500 ~ 599
=> 表示各种服务端错误
=> 500: 表示标准服务器错误
=> 501: 服务器过载或维护
=> ...

ajax 对象的兼容问题
=> 标准浏览器: new XMLHttpRequest()
=> IE 低版本: new ActiveXObject('Microsoft.XMLHTTP')

28.localStorage/sessionStorage

+ localStorage     永久存储
+ sessionStorage   会话存储(关闭浏览器就消失了)
+ 所有页面都可以访问, 因为是属于浏览器的一部分内容+ localStorage     永久存储
+ sessionStorage   会话存储(关闭浏览器就消失了)
+ 所有页面都可以访问, 因为是属于浏览器的一部分内容
window.localStorage.setItem(key, value)   // 写
window.localStorage.getItem(key)          //读
window.localStorage.removeItem(key)       // 删除
window.sessionStorage.setItem(key, value)
window.sessionStorage.getItem(key)
window.sessionStorage.removeItem(key)

29.回调函数 callback

把 函数A 当作实参传递到 函数B 内,在 函数B 内使用形参调用 函数A

我们管这个行为叫做 回调函数,函数A 是 函数B 的回调函数

30.async / await

ES7 以后的语法,把异步代码写的看起来像同步代码, 本质还是异步

async 关键字
+ 使用: 书写在函数的前面
=> async function () {}
=> async () => {}
+ 作用:
1. 该函数内可以使用 await 关键字了
2. 把该函数变成 异步函数, 只是叫做 异步函数
=> 影响的是函数内部的代码

await 关键字
1. await 后面的内容必须是一个 promise 对象
2. await 必须写在一个有 async 关键字的函数内部
可以把 promise 中本该在 then 内的代码直接定义变量接受
后续的代码需要等到 promise 执行完毕才会执行

31.cookie

cookie: 客户端的一个存储空间
cookie的特点
1. 按照域名存储的,哪一个域名存储起来, 哪一个域名使用
2. 必须依赖服务器,本地打开的页面是无法存取 cookie
3. cookie 的时效性,默认是会话级别, 关闭浏览器就没有了,可以手动设置时效,手动设置的时候, 和你是否关闭电脑, 是否关闭浏览器没有关系
4. cookie 存储格式
+ 一条cookie 的存储格式是 key=value
+ 多条cookie 的存储格式是 key=value; key2=value2; key3=value
5. cookie 空间的存储大小
+ 4KB 左右
+ 50 条左右
6. 请求的自动携带
+ 当你的 cookie 空间中有数据的时候
+ 只要你在当前域名发起任何请求, 都会在请求头中自动把 cookie 空间内的所有数据带携带
7. 前后端操作
+ 前端可以通过 JS 操作 存取
+ 任何一个后端语言都可以操作 存取

本地存储之间的区别(重点)
1. 出现时间
=> cookie 是一直有
=> localStorgae/sessionStorage 是 H5 标准下才有的
2. 存储大小
=> cookie 大概是 4KB 左右
=> localStorage/sessionStorage 大概是 20MB 左右
3. 时效性
=> cookie 默认是会话级别, 可以手动设置
=> localStorage/sessionStorage 有浏览器 API 固定好不能手动设置
-> lcoalStorage 就是永久存储
-> sessionStorage 就是会话存储
4. 请求携带
=> cookie 内存储的数据会自动携带在请求头
=> localStorage/sessionStorage 内存储的内容不会自动携带, 需要手动设置
5. 操作
=> cookie 是可以前后端操作的
=> localStorage/sessionStorage 只能前端操作, 后端语言不能操作
扩展: 在任何服务端语言内有一个 服务器存储空间, 叫做 session
读:document.cookie
写:document.cookie = 'key=value'(一次只能设置一条 cookie)
设置带有时效性的 cookie
document.cookie = 'key=value;expires=' + 时间对象
注意: 不管你给他的时间对象是什么时间, 是哪一个时区的时间, cookie 都会当做世界标准时间来使用
var time = new Date('2021-7-23 9:27:00') //世界标准时间的 9:30 其实使我们 北京时间 17:30
document.cookie = 'a=100;expires=' + time
设置一个当前时间 30s 以后过期的 cookie
const time = new Date() // 1. 获取当前时间节点
let t = time.getTime() - 1000 * 60 * 60 * 8
t += 1000 * 30
time.setTime(t) // 把时间戳使用 setTime() 在设置回 time 时间对象身上
document.cookie = 'a=100;expires=' + time

cookie 是不能手动删除的,如果你想删除 cookie, 只能是把 cookie 的过期时间设置为当前时间以前

32.同源策略

当发送请求时,如果打开页面的完整地址和接受服务器的完整地址只要 域名 传输协议 端口号有任意一个不一样,就是触发了同源策略,浏览器不允许你获取该服务器的数据
跨域请求
我们需要请求非同源服务器的数据,这种请求叫做 跨域请求
常见的跨域请求解决方案
1. jsonp
2. cors(跨域资源共享)
3. proxy(代理)

33.jsonp

 <script src="http://localhost:8080/07_jsonp/jsonp.php?callback=fn"></script>

认识一下 script 标签 和 src 属性
=> 因为 src 属性只是标注引入一个外部资源的路径,script 标签默认会把你引入的所有内容当做 js 代码来执行, src 属性是 W3C 标准给出专门用来引入外部资源的属性
浏览器不会去管 src 引入的内容是否是跨域的, 浏览器的同源策略不管 src 属性

jsonp 的实现方式
利用 script 标签的 src 属性, 去请求一个 非同源的 服务器地址
要求服务器给出的内容必须是一段合法的可以执行的 js 代码
要求服务器给出的 js 代码需要是一个 '函数名(数据)' 的格式

34.cors

cors(跨域资源共享):和前端没有任何关系的一种跨域请求方案,前端该如何发 ajax 请求, 就如何发
<?php

  // 在这里告诉浏览器, 你别管, 我愿意给他数据

  // 告诉浏览器, 哪些域名可以请求我
  header("Access-Control-Allow-Origin: *");
  // 告诉浏览器, 哪些请求方式我能接受
  header("Access-Control-Request-Methods:GET, POST, PUT, DELETE, OPTIONS");
  // 告诉浏览器, 我能接受哪些额外的请求头信息
  header('Access-Control-Allow-Headers:x-requested-with,content-type,test-token,test-sessid,authorization');

  echo 'hello world';

?>

35.proxy

proxy(代理),任何服务器都可以实现代理请求转发的功能
+ apache 服务器
-> 代理 http 请求免费
-> 代理 https 请求要证书
+ nginx 服务器
-> 代理 http 和 https 都是免费的
+ 打开小皮面板
-> apahce 停止
-> nginx 开启

配置代理
+ 打开小皮面板
+ 点击左侧边栏 设置
+ 点击顶部选项 配置文件
+ 点击 vhosts.conf 文件
+ 选择下面的 0localhost_端口号.conf
+ 找到 server 的闭合括号的上一行, 书写代理配置
location /xx {
  proxy_pass 你跨域的地址;
}
/xx: 代理标识符
+ 关键: 重启服务器

36.函数

函数的特点:保护私有变量,每一个函数会生成一个独立的私有作用域

在函数内定义的变量, 我们叫做 私有变量, 该变量只能在该函数作用域及下级作用域内使用,外部不能使用

函数定义时不解析变量

=> 函数定义的时候, 函数体内的代码完全不执行,任何变量不做解析

=> 直到执行的时候才会解析变量

函数的两个阶段

函数定义阶段

1. 在 堆内存 中开辟一段存储空间

2. 把 函数体内的代码, 一模一样的复制一份, 以字符串的形式放在这个空间内, 此时不解析变量

3. 把 堆内存 中的空间地址赋值给变量

函数调用阶段

1. 按照 变量名(函数名) 内存储的地址找到 堆内存 中对应的空间

2. 在 调用栈 内开辟一段新的函数执行空间

3. 在 新的 执行空间内 进行形参赋值

4. 在 新的 执行空间内 进行预解析

5. 在 新的 执行空间内 把函数体内的代码当做 js 代码执行一遍

6. 把 开辟在调用栈 内的 执行空间 销毁(等到所有代码执行完毕)

一个不会销毁的函数执行空间
当函数返回一个 复杂数据类型, 并且在函数外部有变量接受的情况

function fn() {
const obj = { name: 'Jack', age: 18, gender: '男' }
return obj
}
const res = fn()

37.继承

+ 继承是出现在两个构造函数之间的关系

=> 当 构造函数A 的实例, 使用了 构造函数B 内书写的属性和方法

=> 此时我们就说 构造函数B 继承自 构造函数A

+ 常见的继承方案

1. 原型继承

2. call继承

3. 组合继承

4. ES6 的继承语法

原型继承(原型链继承)
子类的原型指向父类的实例: 子类.prototype = new 父类
优点:
+ 父类的 构造函数体内 和 原型 上的内容都能继承下来
缺点:
+ 继承下来的属性不在自己身上, 子类的实例的所有属性分开了两部分书写
+ 同样都是给 子类实例 使用的属性, 在两个位置传递参数
call 继承(借用继承 / 借用构造函数继承)
+ 核心: 利用 call 方法调用父类构造函数
优点:
+ 可以把继承来的属性直接出现在 子类的实例 身上
+ 一个实例使用的属性可以再一个位置传递参数了
缺点:
+ 只能继承 构造函数体内 书写的内容, 构造函数的 原型上 不能继承
function Student(gender, name, age) {
this.gender = gender
// 这里的 this 是 Student 的每个实例对象
// 利用 call 调用 Person 构造函数, 把 Person 内的 this 修改为 Student 内的 this
// 把 Person 内的 this 修改为 Student 的每一个实例对象
// Person 构造函数体内书写成员就都添加到了 Student 的实例身上
Person.call(this, name, age)
}
组合继承: 把原型继承和call继承 合并在一起就做组合继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
function Student(gender, name, age) {
this.gender = gender
// 实现 call 继承
// 目的: 为了把父类构造函数体内的内容放在子类实例自己身上
Person.call(this, name, age)
}
// 实现原型继承
// 目的: 为了把 Person 的 prototype 内的内容继承下来
Student.prototype = new Person()
Student.prototype.play = function () { console.log('你好 世界') }
// 创建子类的实例
const s = new Student('男', '张三', 20)
ES6 的继承方案,ES6官方提出了关键字来实现继承
语法:class 子类 extends 父类 { ... }
class Student extends Person {
// 创建一个 继承自 Person 的 Student 类,extends 关键字相当于原型继承
constructor (gender, name, age) {
  // 相当于在调用父类构造函数体, 把 name 和 age 传递过去
  // 相当于 call 继承
  super(name, age)
    //super 必须写在所有 this 的最前面
    this.gender = gender
  }
  play () { console.log('你好 世界') }
}

38.单利模式

为了解决某一类问题给出的简洁而优化的解决方案

1. 单例模式
+ 一个构造函数一生只有一个 实例对象
+ 例子: 弹出层
=> 一个网站的某一个页面, 连续弹出多次弹出层
=> 最好: 每次弹出的都是这一个 div, 只是文字和显示的效果更换了
+ 核心代码:
let instance = null
function singleton() {
    if (!instance) instance = new 类
    return instance
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值