目录

javascript

目录

JS基础

简单数据类型

Undefined类型

  • 只声明但未初始化
  • 只有一个值:undefined
  • 用typeof检测返回undefined,typeof返回的值是一个字符串

NUll类型

  • 表示空对象指针,用于未来会保存对象的变量初始化
  • 只有一个值:null
  • 用typeof检测返回object,typeof返回的值是一个字符串
  • ==注意==:undefined派生自null(null==undefined为true,但是null == =undefined为false)

Boolean类型

  • 只有两个值:true和false
  • 转型函数Boolean()
    1. 数字:除了0和NaN,其余都是true
    2. 字符串:除了空串都为true
    3. null,undefined为false
    4. 对象为true
  • 对任意数据类型取反两次!!可以转为布尔值

Number类型

  • js中所有的数字都是Number类型
  • 二进制0b
  • 八进制最高位加0
  • 十六进制最高位加0x
  • 浮点数在小数点后没有数或小数点后都为0时会被转为整型
  • ==注意==:
    1. 在输出和进行算术运算时都会转换成十进制
    2. ECMAScript中浮点计算(0.2+0.1)会有误差,因此不要去判断浮点数

数值范围

  • 超过Number.MAX_VALUE和-Number.MAX_VALUE的数值会被转成 Infinity和-Infinity
  • Number.MIN_VALUE表示的是>0的最小值

NaN

  • 任何涉及NaN的操作都会返回NaN(没有字符串连接)
  • NaN与任何值都不想等,包括NaN本身
  • isNaN()用于测试传入的数值是否能转为数值,如果能则返回false
  • ==注意==:
    1. typeof NaN为number

    2. true能转化为1

  • isNaN()也适用于对象,对象调用isNaN()函数时首先调用对象自己的valueOf()方法,以确定该方法的返回值是否可以转为数值。如果不能,再基于这个返回值调用tostring()方法,再次测试

数值转换

Number()
  • 可以用于任何数据类型
  • Boolean值,true返回1,false返回0
  • null值,返回0
  • undefined值,返回NaN(Number类型)
  • 字符串,除空的转为0,有额外字符的转为NaN,其他都转为十进制数
  • ==注意==:不能转八进制,因为前导0会忽视
parseInt(,进制)
  • 用于将一个字符串中的有效==整数==内容取出来

  • 如果第一个字符不是数值或负号,则返回NaN。(空返回NaN)

  • 直到解析到非数字字符(包括小数点)停止

  • 能够解析八进制和十六进制,加上第二个参数,表示基数是多少进制

==注意==:

  1. 对于非字符串值会先转为String然后再操作
parseFloat()
  • 可以解析第一个小数点
  • 只能解析十进制数
  • 如果传入的字符是整数,则也会返回整数

String类型

  • 转义字符
  • 拼接字符串会很慢,字符串的不可变性
  • 注意比较运算符的==两边都是==字符串时不会将其转化成数字进行比较,而会分别比较字符串中字符的Unicode编码,一位一位进行比较,如果两位一样则比较下一位,所以==在比较两个字符串型的数字之前一定要转成Number==

转为字符串

toString()
  • 除了null,undefined都有该方法
  • 参数表示返回数值的进制
  • 该方法有返回值,不会影响原变量
String()
  • 对于Number和Boolean,实际还是调用toString()方法
  • 如果值为null,返回 “null”
  • 如果值为undefined,返回“undefined”
+ ""
  • 加一个空字符串,隐式类型转换

JS对象

创建对象

  • 字面量

    1
    2
    3
    4
    5
    6
    
    var obj = {
                uname: 'xqz', //里面的属性方法采取键值对的形式
                sayHi: function () { //方法冒号后面跟的是一个匿名函数
                    console.log('hi');
                }
            }
    
  • 利用Object()

    1
    2
    3
    4
    5
    
    var obj = new Object(); //一个空对象
            obj.uname = 'xqz';
            obj.sayHi = function () {
                console.log('Hi');
            };
    
  • 构造函数

    function Person(){

    }

    Person() //不加new是普通函数

    new Person() //加new是构造函数

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
     function Star(uname, age, sex) { //构造函数首字母大写
                this.name = uname;
                this.age = age;
                this.sex = sex;
                this.sing = function (songs) {
                    console.log(songs);
                }
            }
            var ldh = new Star('刘德华', 19, '男'); //构造函数不需要return
            ldh.sing('冰雨');
    

==注意==:

  1. 构造函数每执行一次就会创建一个新的方法,也就是说所有的实例的sing方法都是唯一的,这样占用了大量的内存空间,完全可以让所有的对象共享一个方法:对象的prototype属性中写

  2. 对于不再使用的对象,必须设置为null,这样GC才会回收

    1
    2
    
    var person = new Person();//此时仍有变量在引用
    var person = null; //此时栈中对堆中的引用断开,对象成为垃圾
    

使用对象

  • 使用属性

    obj.uname

    obj.[‘uname’]

  • 使用方法

    obj.sayHi();

hasOwnproperty() 方法验证属性是存在于对象中,还是存在于实例中。在实例中则返回true,在构造函数的prototype中则返回false。 name in Object 只要能通过原型链找到则返回false. hasPrototypeProperty()方法 实例中重写属性后,属性就存在于实例中,原型中的属性就用不到了。

枚举(不明白) 得到所有可枚举的实例属性 Object.keys()方法

Object.assign(default,new) //属性覆盖

遍历对象

1
2
3
4
for (const key in ldh) {
  console.log(key);//输出属性名
  console.log(ldh[key]);//输出属性值
}

==注意==:

  1. “属性名” in 对象:可以检查obj中是否有该属性
  2. obj2=obj1;此时修改obj1中的值会影响obj2因为他们指向的是同一个堆地址,如果让obj1=null,并不会改变obj2的值,只是将obj1的指向断开,堆内存中的值仍然存在

判断对象类型

  1. instance of检测是否为该对象类型,Array和Function都是特殊的Object类型

  2. typeof

    能区别:数值/字符串/布尔值/undefined/function

    不能区别:null与Object,Object和Array

  3. ===只对undefined和null有效,因为只有这两种类型有固定值

  4. typeof a(返回值是字符串类型) === ‘undefined’也可以进行判断,注意undefined == =’undefined‘是false,一个是undefined类型,一个是字符串类型

内置对象

Math对象

  • 最大值

    Math.max()

  • 绝对值

    Math.abs()

  • 取整

    • 向下

      Math.floor()

    • 向上

      Math.ceil()

    • 四舍五入

      Math.round()

      ==注意==:负数中.5特殊,往大了取

  • 随机数

    • 返回[0,1)之间的小数

      Math.random()

    • 返回两个数之间的随机整数

      1
      2
      3
      4
      
      //返回两个数之间的随机整数,并且包含这两个数
              function getRandom(min, max) {
                  return Math.floor(Math.random() * (max - min + 1)) + min;
              }
      

日期对象

  • 返回系统当前时间 new Date()

  • 返回自定义的时间

    • 参数为数字型

      new Date(2020,6,30)

      ==注意==:返回的月份比实际大1月

    • 参数为字符串型

      new Date(‘2020–6–30 8:23:45’);

  • date.getFullYear()

  • date.getMouth() + 1(0~11)

  • date.getDate()

  • 周几

    date.getDay() (0-6)

  • date.getHours()

  • date,getMinutes()

  • date.getSeconds()

  • 时间戳(毫秒)

    ==注意==:是距离1970年1月1日过了多少毫秒

    • date.valueof()

    • date.getTime()

    • +new Date()

    • Date.now()

数组对象

创建数组

  • 字面量

    1
    
     var arr = [1, 3, 3, 3]
    
  • 利用new Array()

    1
    2
    
    var arr1 = new Array(2); //长度为2的空数组
    var arr1 = new Array(2, 3); //等价于[2,3]表示里面有两个数组元素是2和3
    

==注意==:

  1. 读取不存在的索引不会报错,返回undefined
  2. 对于连续的数组,用length会得到数组的长度,对于非连续的数组,length获得数组的最大索引加1

检测是否为数组

  • arr instance of Array
  • Array.isArray(arr)

  • 在末尾加, 返回新数组长度

    arr.push()

  • 在开头加,返回新数组长度

    arr.unshift()

  • 在指定位置加

    splice(开始索引,0,添加的元素) //返回删除的数组,在开始的索引之后增加

  • 删末尾一个,返回删除的元素

    arr.pop()

  • 删开头一个,返回删除的元素

    arr.shift()

  • 删除并在删除位置添加,会改变原数组

    splice(开始索引,删除个数,添加的元素)//返回删除的数组

​ splice(开始索引,删除个数,添加的元素)//返回删除的数组

根据元素找索引

1
2
console.log(arr.indexOf('A')); //从前往后找 它只返回第一个满足条件的索引号 找不到则会返回-1
console.log(arr.lastIndexOf('A')); //从后往前找

findIndex(),返回一个索引

1
2
3
4
//根据id从数组中查找元素的索引
this.books.findIndex(function (item) {
  return item.id == id;
})

翻转

arr.reverse(),修改原数组

排序

  1. 修改原数组,默认按照unicode编码进行排序
  2. sort里放一个函数如果返回大于0的数则a,b交换位置,如果返回小于0的数则a,b不交换位置
1
2
3
4
5
6
7
8
9
arr.sort(function(a,b){
  if(a>b){
    return 1;//换位置
  }else if(a<b){
    return -1;//不换
  }else{
    return 0;//a和b相等
  }
})
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//对数字进行排序结果会出错,所以需要在sort里面放一个函数实现排序
arr.sort(function (a, b) {
  <<<<<<< HEAD
          return a - b;//升序,如果a-b>0,a>b返回一个>0的数,交换位置
});
return b-a;//降序
=======
return a - b;//降序,如果a-b>0,a>b返回一个>0的数,交换位置
});
return b-a;//升序
>>>>>>> 1ceb7a2e23037ad4c54e9f577ca2057109b71222
console.log(arr);

合并

arr1.concat(arr2)

不会改变原数组,返回新数组

数组转字符串

  • arr.join(连接符) //默认逗号,不会改变原数组,将转换后的字符串作为结果返回
  • arr.toString() //逗号分隔

数组截取

arr.slice(开始索引,结束索引(不包含))

==注意==:

  1. 如果传递一个负值,则从后往前进行计算
  2. 不会改变原数组

数组遍历

  • array.filter(function(currentValue,index,arr), thisValue)//当前元素的值,当前元素的索引,当前元素属于的数组对象
    • 不会改变原始数组
    • 返回一个新数组
1
2
3
4
 //根据id查询出要编辑的数据
this.books = this.books.filter(function(item){
  return item.id==id;
});
  • some(function(){})
    • 用于检测数组中的元素是否满足指定条件
    • some()方法会以此执行数组的每个元素:
      • ==如果有一个元素满足条件,则表达式返回true==,剩余的元素不再遍历
      • 如果没有满足体条件的元素,返回false

==注意==:不能对空数组进行检测

1
2
3
4
5
6
7
8
 //根据当前的id去更新数组中对应的数据
this.books.some((item) => { //箭头函数中的this指向定义这个函数的父级作用域中的this,也就是handle的this,指向vue实例
  if (item.id == this.id) {
    item.name = this.name;
    //完成更新操作后需要中止some遍历
    return true;
  }
});

字符串对象

  • string是简单数据类型,为什么有length属性?

    步骤:

    1. 创建基本类型的一个实例;
    2. 在实例上调用指定的方法;
    3. 销毁这个实例;
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    var str = "我是string基本类型的值";
    var new_str = new String("我是string基本类型的值");  // 包装处理
    var my_str = new_str.substring(5,8);
    new_str = null;   // 方法调用之后销毁实例
    
    var str2 = "xqz";
    str2.age = 21;
    console.log(str.age);   //undefined
    //可见,并非string调用了自身的方法,而是后台创建了一个基本包装类型String,从而进行下一步操作。
    //基本类型的“销毁性”致使我们不能为基本类型添加属性和方法。
    
  • ==注意==:String,Number,Boolean都是基本包装类型

    1
    2
    3
    
    var a = 123;
    a.hello = "hello"; //这里不报错是因为转为了基本包装类型Number(),给改对象添加了hello属性,而后让new_num=null从而销毁实例
    console.log(a.hello);//这里调用a的hello属性不报错,结果为undefined,因为重新又创建了一个Number()实例,此时这个实例中并没有hello属性
    
  • 字符串的不可变性

    指的是里面的值不变,其实只是地址变了,内存中开辟了一个内存空间

    1
    2
    3
    4
    5
    6
    7
    8
    
    var str2 = 'andy';
    str2 = 'red'; //str从andy指向red,但是andy仍然存在
    //因为我们字符串的不可变所以不要大量拼接字符串
    var str2 = '';
    for (var i = 0; i < 100; i++) { //如果i过大会很卡
    	str += i;
    }
    console.log(str);
    
  • ==注意==:字符串的所有方法都不改变自身,都返回一个新的字符串

根据值找索引

1
2
3
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春'));
console.log(str.indexOf('春', 3)); //从索引号3的位置(包括3)往后找 lastindexof()同理

根据索引找值

  • 返回字符

    str.charAt()

    str[]

  • 返回ASCII值,unicode编码

    str.charCodeAt()

  • str[]

    因为在底层字符串是以字符数组的形式保存的

合并

​ str1.concat(str2)

截取

  • str.substr(开始的索引,截取长度) //如果只有一个参数且为负数,则是从后往前
  • str.substring(开始索引,结束索引) //结束索引不能为负数,负数会被转为0,如果第二个参数小于第一个参数会自动交换位置
  • str.slice(开始索引,结束索引(不包含)) //可以接受负数,会将字符串长度与负数相加作为第二个参数
  • 都是返回截取下来的字符串

替换

​ str.replace(要替换,替换为) //只会换一个

返回一个新的字符串

可以接收正则表达式

1
str.replace(/[a-z]/g,"@");//全部替换

大小写

​ toUpperCase()

​ toLowerCase()

去除空格

​ str.trim()

是否包含

​ str.includes() //返回bool类型(es6)

搜索指定内容

​ str.search()

​ 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到则返回-1,它可以接收正则表达式作为参数来进行搜索

​ str.search(/a[bef]c/),不能全局匹配,只会查找第一个

提取

1
2
3
str = '123afd445fda5';
result = str.match(/[A-z]/);//默认情况下match智慧找到第一个符合要求的内容,找到以后就会停止检索,可以设置正则表达式为全局匹配模式
result = str.match(/[A-z]/gi);//全局匹配并且忽略大小写,返回一个新的数组

字符串转数组

​ str.split(以什么分隔符分割该字符串) //返回一个数组

==注意==:

  1. 根据任意字母来将字符串拆分str.split(/[A-z]/),这个方法不设置全局匹配也会全部拆分;

根据字符编码获取字符

​ var result = String.fromCharCode()

FormData对象

https://www.jianshu.com/p/e984c3619019

arguments的使用

  • arguments是函数的一个内置对象,只有function()才有,当不确定有几个参数传递时使用

  • arguments是一个伪数组:可以通过索引访问,有length属性,但是没有数组的方法

JS预解析

变量提升

只提升变量名(使用var定义),不提升赋值操作

函数提升

只提升函数声名,不调用函数

==注意==:先执行变量提升,再执行函数提升

  • 例题

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    	    f1();
            console.log(c);
            console.log(b);
            console.log(h);
    
            function f1() {
                var h = b = c = 9;
                //相当于 Var a=9;b=9;c=9;b和c直接赋值 没有var 当全局变量看
                //集体声明应该写成 var a=9,b=9,c=9;
                console.log(h);
                console.log(b);
                console.log(c);
            }
    
            //相当于
            function f1() {
                var h;
                h = 9;
                b = 9;
                c = 9;
                console.log(h);
                console.log(b);
                console.log(c);
            }
            f1();
            console.log(c);
            console.log(b);
            console.log(h);//此处报错,h没有声名,因为h的作用域只在f1函数中
    

JSON

  1. JS中的对象只有JS自己认识,其他的语言都不认识
  2. JSON就是一个特殊格式的字符串,可以被任意语言所识别,且可以转成任意语言的对象,JSON在开发中主要用来数据的交互
  3. JavaScript Object Notation JS对象表示法

==注意==:

  1. JSON字符串的属性名必须加双引号

分类

  1. 对象{}
  2. 数组[]

JSON中允许的值

  1. 字符串
  2. 数值
  3. 布尔值
  4. null
  5. 对象
  6. 数组

JSON转对象

JSON.parse()

  1. 需要一个JSON字符串作为参数,会将该字符串转为JSON对象

对象转JSON

JSON.stringify()

  1. 需要一个js对象作为参数,会返回一个JSON字符串

WebAPI

DOM

节点操作

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E8%8A%82%E7%82%B9%E5%B1%9E%E6%80%A7.png

  • nodeType

    1. 元素节点
    2. 属性节点
    3. 文本节点
  • nodeName

  • nodeValue

==注意==:节点操作主要操作元素节点

元素节点和元素对象的区别

1.所谓元素,即html文档里面,所有的标签都可以称之为元素,比如说

、等,也就是说元素是个统称,一个文档里面有很多的元素。

2.所谓节点,是js为了对html文档进行操作,而开发的,即DOM,文档对象模型。即每个元素都可以称之为一个节点,节点是唯一的。比方来说,《p》标签,肯定是一个p标签元素,那如果通过js对它进行样式控制的时候,就必须获取(找到)到这个元素,称之为节点,如果有好多元素,可以获得第1个、第2个或者第n个。总之,元素是统称,节点是具有唯一性的。

获取节点
API 说明
document.getElementById(’’) 根据id返回元素对象
document.getElementByClassName(’') 根据类名返回元素对象
document.getElementByTagName(’') 根据标签名返回元素对象集合(伪数组),可以先获取父元素在获取子元素
document.querySelector(’') 根据css选择器返回第一个符合条件的元素对象
document.querySelectorAll(’') 根据css选择器返回所有元素对象
document.body() 获取body标签
document.documentElement 获取html标签

==注意==:得到的多个都是伪数组

获取父节点
API 说明
node.parentNode 得到的是离元素最近的父级节点
获取子节点
API 说明
node.children 得到所有子节点(元素节点)
node.children[0] 得到子节点的第一个元素
node.children[node.children.length-1] 得到子节点的最后一个元素
node.childNodes 包括空白的所有子节点
node.firstChild 包括空白的第一个子节点
node.firstElementchild 不包括空白的第一个子节点
获取兄弟节点
API 说明
node.nextElementSibling 下一个兄弟节点(元素节点)
node.previousElementSibling 上一个兄弟节点(元素节点)
创建节点
API 说明
var child = document.createElement(‘标签名’) 创建一个节点
document.createTextNode() 创建文本节点,child.appendChild(textnode)
element.innerHTML='' 创建并且添加
添加节点
API 说明
node.appendChild(child) 添加到父节点(node)的子节点列表末尾
node.insertBefore(child,指定元素(node.children[])) 添加到父节点(node)的指定的子节点之前
删除节点
API 说明
node.removeChlid(child) node是一个父节点
node.remove() 删除自身节点及其子节点
复制节点
API 说明
node.cloneNode() 只复制标签
node.cloneNode(true) 深拷贝,全复制
替换节点
API 说明
node.replaceChild(new ,old) 替换节点

元素操作

操作元素内容

innerHTML和innerText的区别

  • innerText不识别html标签,且会自动去除空格和换行

  • innerHTML识别html标签,且保留空格和换行

  • 这两个属性可读写,可以获取元素里面的内容

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
            //innerText和inner HTML的区别
            //1.innerText 不识别HTML标签 去除空格和换行
            var div =document.querySelector('div');
            div.innerText='<strong>1</strong>';
            //2.innerHTML 识别HTML标签 (常用) 保留空格和换行
            div.innerHTML='<strong>1</strong>';
    
            //这两个属性可读写 可获取元素里的内容
            var p = document.querySelector('p');
            console.log(p.innerText);
            console.log(p.innerHTML);
    

操作元素属性

获取属性
获取元素自带属性
API 说明
element.属性名 常见元素自带的属性:src,href,title,alt等,表单元素自带的属性:type,value,disable等,获取class属性时用className获取
  • offset系列属性

    offset系列属性 作用
    element.offsetParent 返回最近一级的带有定位的父元素,没有则返回body==区别==element.parentNode返回最近一级父亲,不管有没有定位
    element.offsetTop 返回元素相对带有定位父元素上方的偏移,没有则以body为准
    element.oddsetLeft 返回元素相对带有定位父元素左边框的偏移
    element.offsetWidth 返回自身包括==边框,padding,内容区==的宽度,返回数值不带单位
    element.offsetHeight 返回自身包括边框,padding,内容区的宽度,返回数值不带单位

    ==offset与style的区别==

    offset style
    可以得到任意样式表中的样式值 只能得到行内样式表中的样式值
    返回的数值没有单位 返回带有单位的字符串
    offsetWidth包括padding+border+width style.width不包括padding和border
    offsetWidth等属性是只读属性,不能赋值 可读可写
    用于获取元素大小 用于更改元素样式值
  • client系列属性

    client系列属性 作用
    element.clientTop 返回元素上边框的大小
    element.clientLeft 返回元素左边框的大小
    element.clientWidth 返回自身包括==padding,内容区==的宽度,返回数值不带单位
    element.clientHeight 返回自身包括padding,内容区的宽度,返回数值不带单位
  • scroll系列属性

    scroll系列属性 作用
    element.scrollTop 返回被卷去的上侧距离(overflow:auto;滚动条),返回数值不带单位,有padding从内容离开padding算起,否则边框下沿开始计算
    element.scrollLeft 返回被卷去的左侧距离,返回数值不带单位
    element.scrollWidth 返回自身不含边框的==实际宽度==(超出的也算进去),返回数值不带单位
    element.scrollHeight 返回自身不含边框的==实际高度==(超出的也算进去),返回数值不带单位

==注意==:

  1. 元素被卷去的头部距离:element.scrollTop获取
  2. 页面被卷去的头部距离,window.pageYoffset获取
  3. 说明垂直滚动条滚动到底:scrollHeight-scrollTop == clientHright //用于判断用户是否阅读完协议
获取元素自定义属性

element.getAttribute(‘属性名’)

设置属性
设置元素自带属性
API 说明
element.属性名 = ‘’;
设置元素自定义属性
API 说明
element.setAttribute(‘属性名’,‘值’)

==注意==:修改class属性时

  1. 用element.==className== ‘’;
  2. 用element.setAttribute(’==class==’,’’);

==注意==:H5规定自定义属性data开头作为属性名并且赋值:

移除属性
移除元素自定义属性
API 说明
element.removeAttribute(’’)
判断是否有该属性
API 说明
element.hasAttribute() 判断元素属性,而不是css样式表中的样式属性

操作元素样式

获取样式属性
API 说明
getComputedStyle(element).属性 可以获取css样式表的样式,需要两个参数1.需要获取样式的元素2.可传递一个伪元素,一般都传null,该方法会返回一个对象,对象中封装了当前元素对应的样式。
element.style.样式名 只能获取行内样式(这里的style就是元素的一个属性,将将样式名修改为驼峰命名)
设置样式属性
API 说明
element.className='' 会覆盖原来的class,用 += 可以防止覆盖,注意要加空格className += ‘ b2’
element.style.样式名=‘值’ 添加的是内联样式,所以如果在样式中写了important,js就无法修改了(这里的style就是元素的一个属性)

动画函数的封装

动画函数原理

定义一个setInterval的定时器,函数里对元素的样式进行操作

1
2
3
4
5
6
7
8
        var div = document.querySelector('div');
        var time = setInterval(function () {
            if (div.offsetLeft >= 400) {
                clearInterval(time);
            } else {
                div.style.left = div.offsetLeft + 1 + 'px';
            }
        }, 1)

动画函数简单封装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<body>
    <div></div>
    <span></span>
    <button>点击开炮</button>
    <script>
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn=document.querySelector('button');
        animate(div, 300);
        
        //obj目标元素,target目标位置
        function animate(obj, target) {
            //防止速度加快先清除以前的定时器
            clearInterval(obj.time);
            //给不同的元素指定不同的定时器
            obj.time = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    clearInterval(obj.time);
                } else {
                    obj.style.left = obj.offsetLeft + 1 + 'px';
                }
            }, 1)
        };
        btn.addEventListener('click',function(){
            //bug:当不断点击按钮元素速度会越来越快
            //解决方案:元素只有一个定时器执行
            animate(span, 200);
        })
        console.dir(div);
    </script>
</body>

缓动动画函数封装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function animate(obj, target, callback) {
    //先清除以前的定时器
    clearInterval(obj.time);
    //给不同的元素指定不同的定时器
    obj.time = setInterval(function () {
        //把步长值,上下取整看正负值
        var x = (target - obj.offsetLeft) / 10;
        if (x >= 0) {
            x = Math.ceil(x);
        } else {
            x = Math.floor(x);
        }
        if (obj.offsetLeft == target) {
            clearInterval(obj.time);
            //回调函数
            // if (callback) {
            //     callback();
            // }
            callback && callback();//&&具有短路的功能
        } else {
            obj.style.left = obj.offsetLeft + x + 'px';
        }
    }, 15)
}

三种动态创建元素的区别

  1. document.write()会导致文档流重绘

  2. element.innerHTML = ''

  • 拼接字符串,很慢

    解决方法:存入数组中,一次性渲染,很快

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    var inner = document.querySelector('.inner');
            inner.innerHTML = '<a href="#">百度</a>';
            // 创建多个字符串拼接的时候特别慢效率低
            // 但是用数组的形式拼接是最快的
            var arr = [];
            var date1 = Date.now();
            for (var i = 0; i < 1000; i++) {
                arr.push('<a href="#">9</a>');
            }
            inner.innerHTML = arr.join('');//数组转字符串
            var date2 = Date.now();
            console.log(date2 - date1);
    
  1. var child = document.createElement();

    node.appendChild(child);

    比2慢,比1快

事件

鼠标事件

事件 说明
onclick 点击
onmouseover/onmouseenter 移入
onmouseout/onmouseleave 移出
onmousedown 按下
onmouseup 松开
onmousemove 移动
onwheel 鼠标滚轮,e.datail(火狐)或者e.wheelDelta

==注意==:mouseover和mouseenter的区别:mouseenter不会冒泡,简单的说,它不会被它本身的子元素的状态影响到.但是mouseover就会被它的子元素影响到,在触发子元素的时候,mouseover会冒泡触发它的父元素.(想要阻止mouseover的冒泡事件就用mouseenter)

键盘事件

事件 说明
onkeyup 松开,不区分大小写
onkeydown 会在文字还没进入文本框前就添加事件,不区分大小写,一直按着某个按键不松手,事件会连续触发,第一次和第二次之间会间隔稍微长一点,其他会特别快
onkeypress 不识别功能按键,如ctrl。区分大小写,触发比onkeydown慢

表单事件

事件 说明
onfocus 获得焦点,无冒泡
onblur 失去焦点,无冒泡
onchange 在元素值改变时触发,适用于input,textarea,select元素
onselect 在文本框内容被选中时触发,适用于单选框,多选框

编辑事件

事件 说明
oncopy 在拷贝时触发
onselect 在文本框内容选中时触发,return false让用户无法选中
oncontentmenu 鼠标右击触发,用e.preventDefault()来禁止鼠标右键

页面事件

事件 说明
onload 等待文档流加载完成后触发
onbeforeunload 即将离开页面(刷新或关闭)时触发

滚动事件

事件 说明
onscroll 滚动条滚动触发该事件,给添加了overflow:auto的元素绑定

传统事件

注册

element.事件类型 = function(){}

删除

element.事件类型 = null

事件监听器

区别传统

相比传统的onclick=function(){},addEventListener可以让同一元素同一事件可以注册多个监听器,按注册顺序依此执行,而传统的只能写一个,如果写了多个以最后一个为准

注册
API 说明
element.addEventListener(’’",function(e){},[true/false]) 第一个参数事件类型,不用加on,第三个参数默认false,冒泡阶段,true,捕获阶段
删除
API事件 说明
element.removeEventListener(’’",函数名,[true/false]) 第一个参数事件类型,不用加on,第三个参数默认false,冒泡阶段,true,捕获阶段

事件对象

事件对象属性
属性 说明
e.type 事件类型
e.target 真正触发事件的那个元素(事件委托:ul和li利用冒泡只需给ul添加点击事件,用e.target获取点击的li)
事件对象方法
方法 说明
e.preventDefault() 阻止默认行为
e.stopPropagation() 阻止事件冒泡
鼠标事件对象
属性 说明
e.pageX/Y 相对于文档页面(图片跟随鼠标移动,图片要绝对定位)
e.clientX/Y 相对于浏览器的可视窗口
e.screenX/Y 相对于电脑屏幕
e.offsetX/Y 相对于带有定位的父盒子的xy坐标
键盘事件对象
属性 说明
e.altKey
e.ctrlKey
e.shiftKey 是否按下shift
e.keyCode 键盘输入的ascll码
DOM事件流

传统和监听器一般都是得到冒泡阶段,把addEventListener第三个参数改为true则能得到捕获阶段

捕获阶段

document=>html=>body=>father=>son(如果father有监听事件,先执行father的,再执行son的)

冒泡阶段

于捕获相反,取消冒泡:e.cancelBubble=true,点击了子元素,点击事件冒泡到父元素

==注意==:onblur,onfocus,onmouseenter,onmousemove没有冒泡

事件委托

原理:将事件监听器设置在父节点上,利用冒泡原理影响每个子节点,用e.target获取按下的那个元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<body>
    <ul>
        <li>2342</li>
        <li>2342</li>
        <li>2342</li>
        <li>2342</li>
        <li>2342</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function (e) {
            //排他
            for (var i = 0; i < ul.children.length; i++) {
                ul.children[i].style.backgroundColor = '';
            }
            //得到你点击的小li
            e.target.style.backgroundColor = 'pink'
        })
    </script>
</body>

BOM

Window对象是浏览器的顶级对象

  1. 它是JS访问浏览器窗口的一个接口
  2. 它是一个全局对象。定义在作用域中的变量,函数会变成window对象的属性和方法

==注意==:window下的一个特殊属性:window.name

window对象

==浏览器内核常见模块:==

js引擎模块、html,css文档解析模块、DOM\CSS模块、布局和渲染模块、定时器模块、事件响应模块、网络请求模块。

location属性

location是一个对象,用于获取或设置窗体的URL,并且可以用于解析,如果直接打印location,返回的是地址栏的信息

  • 属性

    属性 说明
    window.location.href 返回当前页面的URL
    location.host 返回主机域名
    location.port 返回端口号
    location.pathname 返回路径
    location.hash 返回片段 #后面的内容 常见于链接 锚点
    window.lacation.search 返回参数:?键=值(var arr=substr(1).split(“=”))
  • 方法

    方法 说明
    assign() 与改变href属性一样可以跳转页面,可以后退,和直接修改location一样
    replace() 替换当前页,不记录历史,无法后退
    reload() 重新加载页面,若参数为true会强制刷新,相当于浏览器上的刷新按钮
1
2
3
4
5
6
7
8
    <script>
        var btn=document.querySelector('button');
        btn.addEventListener('click',function(){
            location.assign('案例/login.html');
            location.replace('案例/login.html');
            location.reload();
        })
    </script>

包含有关浏览器的信息,常用window.navigator.userAgent,返回由客户机发送服务器的user-agent头部的值,用正则进行匹配

==注意==:

  1. ie11已经不能用useragent判断浏览器了,但是ie中有ActiveXObject对象属性,通过判断页面一这个属性来知道是不是ie浏览器

histroy属性

方法 说明
back() 后退,相当于浏览器上的按钮
forward() 前进
go(1/-1) 1前进一个页面,-1后退一个页面,-2后退两个页面
length 当此访问的链接的数量

其他常见属性

属性 说明
window.page(Y/X)offset 获取页面卷去的头部/左侧
window.scroll(x,y) x,y不加单位,滚定至文档中的特定位置
window.innerWidth 返回窗口宽度,无单位

window事件

事件 说明
window.onload=funtion(){}/window.addEventListenter(’load’,function(){}) 在文档内容(css,js,html)全部加载完成后触发
window.onDOMContentLoaded 在DOM加载完成后就触发
window.onresize 调整窗口大小时触发

定时器

setTimeout

  • 创建

    会返回一个定时器ID给变量

    var time = window.setTimeout(回调函数,[延迟的毫秒数])//在定时器到期后执行回调函数,==只调用一次==

  • 清除

    clearTimeout(定时器ID)

setInterval

  • 创建

    var time = window.setInterval(回调函数,[延迟的毫秒数])//每隔延迟的时间就调用一次,==会重复调用==

  • 清除

    clearInterval(定时器ID),可以接收任何参数,如果参数是undefined或者null则什么也不做

1
2
3
4
5
6
7
8
        setInterval(fn1,500)
        setInterval(fn1(),500)//如果没有返回的函数则只执行一次  1 22222.。。
        function fn1() {
            console.log(1)
            return function () {
                console.log(2)
            }
        }

this指向问题

  1. 在全局作用域,定时器,普通函数中this指向window,==注意==:箭头函数中的this指向上下文对象
  2. 方法中的this指向调用者
  3. 构造函数中的this指向实例

JS执行对列

同步任务在主线程执行,形成一个执行栈。当有异步任务时,如ajax,DOM待触发事件,定时器。放入异步进程处理,触发后放入任务队列(异步队列),等待主线程执行完毕后,通过事件循环机制来任务队列中取出任务执行

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/JS%E6%89%A7%E8%A1%8C%E9%98%9F%E5%88%97.png

JS高级

类和对象

  • 关键字:class

    注意:类中所有函数不需要加function关键字,多个方法间不加逗号分隔.

  • 方法中的this指向:方法的调用者

构造器

  • 关键字:constructor()

  • 作用:用于传递参数,返回实例对象,new生成对象实例时自动调用。

    注意:如果未定义会自动创建一个constructor()

  • this指向:实例对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 <script>
        class Star {
            constructor(uname, age) {
                this.uname = uname;
                this.age = age;
            }
            sing(song) {
                console.log(this.uname + song);
            }
        }
        var ldh = new Star('刘德华', 18);
        var zxy = new Star('张学友')
        console.log(ldh.uname + ldh.age);
        ldh.sing('冰雨')
    </script>

注意:

this的指向问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body>
    <button>
        唱歌
    </button>
    <script>
        var that;
        class Father {
            //构造器里面的this指向实例对象
            constructor(uname, age) {
                that = this;
                this.uname = uname;
                this.age = age;
                // this.sing();
                this.btn = document.querySelector('button');
                this.btn.onclick = this.sing;//因为这个按钮调用了这个函数
            }
            //这个方法里的this 指向的是btn 这个按钮
            sing() {
                // console.log(this.uname);
                console.log(that.uname); //that 里面存储的是constructor里面的this
            }
        }
        var father = new Father('刘德华');
    </script>
</body>

类的继承

关键字

  • entends

  • 注意:ES6中类没有变量提升,必须先定义类,才能实例化

继承属性

调用父类构造函数:

  • 关键字:super(x,y)

注意:在constructor中调用,且必须在子元素的this之前调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <script>
        class Father {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
            sum() {
                console.log(this.x + this.y);
            }
            money() {
                console.log(100);
            }
        }
        class Son extends Father {
            constructor(x, y) {
                super(x, y);
            }
        }
        var son = new Son(1, 2);
        son.money();
        son.sum();
    </script>

继承方法

  • 子类实例会自动继承父类的方法

  • 在子类中调用父类方法:

    • 关键字:super.父类方法名()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    <script>
        class Father {
            say() {
                return '我是爸爸'
            }
        }
        class Son extends Father{
            say() {
                console.log(super.say()+'的儿子'); 
            }
        }
        var son = new Son();
        son.say();
  • 扩展子类的方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    <script>
        class Father {
            constructor(x, y) {
                this.x = x;
                this.y = y;
            }
            sum() {
                console.log(this.x + this.y);

            }
        }
        class Son extends Father {
            constructor(x, y) {
                super(x, y);
                this.x = x;
                this.y = y;
            }
            sub() {
                console.log(this.x - this.y);
            }
        }
        var son = new Son(3, 1);
        son.sum();
        son.sub();
    </script>

构造函数和对象

  1. 利用构造函数创建对象,首字母要大写(之前还有利用new Object(), 字面量的方法创建对象)

  2. 通过this添加实例成员和实例方法

  3. 构造函数名.属性名 || 方法名,添加静态成员和静态方法

    ==注意==:静态成员和方法只能通过构造函数来访问

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
            function Star(uname, age) {
                this.uname = uname;//实例成员
                this.age = age;
                this.sing = function () {
                    console.log('我会唱歌');
                }
            }
            var ldh = new Star('刘德华', 13);
            Star.sex = '男';//静态成员
            Star.dance = function () {
                console.log('dance');
            }//静态方法
            console.log(Star.sex);
    

构造函数原型:prototype(原型对象)

  • 构造函数通过原型分配的函数是所有对象所共享的

  • 每一个构造函数都有一个prototype属性,这个属性就是一个对象,它所拥有的所有属性和方法,都会被构造函数所拥有,包函constructor指回构造函数,和proto属性指向父级的prototype

  • 每一个实例对象也都有一个_proto_属性,也就是对象原型,指向构造函数的prototype

    注意:一般公共的属性定义到构造函数里面,公共的方法放入原型对象中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //Star.prototype被对象赋值覆盖了,所以没有了constructor属性
        Star.prototype = {
            constructor: Star,//重新将构造器指回构造函数
            sing: function () {
                console.log('我会唱歌');
            },
            movie: function () {
                console.log('我演电影');
            }
        }

对象原型:proto

  • 每个实例对象都会有一个属性proto向构造函数的prototype,但最终又通过prototype里的constructor指回构造函数
  • 每一个构造函数的prototype(原型对象)中也有一个proto属性,指向父级构造函数的prototype

方法查找规则

  1. 先看实例对象身上有没有a方法
  2. 如果没有,通过proto指向去构造函数的prototype里找有没有
  3. 如果没有,通过prototype执向父级构造函数的prototype里找有没有,直到找到object为止

注意:

  1. 通过proto到prototype中找到的属性用person.hasOwnProperty()去查找属性返回false,通过in查找返回true
  2. 在打印对象时会自动掉用Object中的toString()方法,如果不想用Object中的方法,可以给对象添加toString()方法

constructor

  • proto中有一个constructor,最终通过prototype指回构造函数

  • prototype中有一个constructor,指回构造函数

    注意:如果prototype被覆盖了,需要重新将constructor:构造函数名(重新指回构造函数)

原型链

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E5%8E%9F%E5%9E%8B%E9%93%BE.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //Star.prototype被对象赋值覆盖了,所以没有了constructor属性
        Star.prototype = {
            constructor: Star,
            sing: function () {
                console.log('我会唱歌');
            },
            movie: function () {
                console.log('我演电影');
            }
        }
        var ldh = new Star('刘德华', 12);
        console.log(Star.prototype);
        console.log(Star.prototype.__proto__ === Object.prototype);
        console.log(Object.prototype.__proto__);

==注意==:

  1. Object是对象也是函数,Object.proto===Function.prototype,Object是Function的实例

  2. function也是==Function(构造函数)==的实例 new Function(),Star.proto->Function.prototype

  3. Function也是Function的实例,Function.proto = Function.prototype

  4. Star.prototype.proto->Object.prototype

  5. ldh.proto->Star.prototype,Star.prototype.proto->Object.prototype

成员查找机制

  1. 当访问一个对象的属性(包括方法时),首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是proto指向的prototype原型对象)
  3. 如果还没有就查找原型对象的原型
  4. 以此类推直到Object为止(null)
  5. proto对象原型的意义就在于为对象成员查找机制提供一个方向路线

instance of

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E5%8E%9F%E5%9E%8B%E9%93%BE2.png

通俗一点来讲,instanceof的判断规则是:instanceof会检查整个原型链,将沿着A的__proto__这条线来一直找,同时沿着B的prototype这条线来一直找,直到能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。即上图中的 f1–>__proto__Foo–>prototype 指向同一个对象,console.log(f1 instanceof Foo)true

this指向

  1. 在构造函数中,里面的this指向的是实例对象
  2. prototype中的this也指向实例对象,因为实例对象调用原型对象里面的方法
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
        var that;

        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        //Star.prototype被对象赋值覆盖了,所以没有了constructor属性
        Star.prototype = {
            constructor: Star,
            sing: function () {
                that = this;
                console.log('我会唱歌');
            },
            movie: function () {
                console.log('我演电影');
            }
        }
        var ldh = new Star('刘德华','12');
        ldh.sing();
        console.log(that === ldh);//true
        console.log(Star);

改变this指向

this指向的4种形式

  1. 一般函数,this指向全局对象window
  2. 在严格模式下,为undefined
  3. 对象的方法里调用,this指向调用该方法的对象
  4. 构造函数里的this,指向创建出来的实例
  5. 箭头函数中this指向上下文

call

  • 第一个参数:改变this指向
  • 第二个参数:实参
  • 使用时候会自动执行函数
1
2
3
4
//A.call( B,x,y ):就是把A的函数放到B中运行,x 和 y 是A方法的参数。
var obj={}
function fun(){}
fun.call(obj)  

apply

  • 第一个参数:改变this指向,在函数运行时才会改变this指向
  • 第二个参数:数组(里面为实参)
  • 使用时候会自动执行函数
  • 主要应用:Math.max.apply(Math,arr)//这里this的指向还是Math不过可以比较数组中的最大值

==注意==:

  1. call和apply这两个方法都是函数对象的方法,需要通过函数对象来调用
  2. 调用call和apply会将一个对象指定为第一个参数,此时这个对象会称为函数执行时的this
  3. call(obj,2,3)方法可以将实参在对象之后依次传递,apply需要将实参封装到数组中统一传递

bind

  • 第一个参数:改变this指向
  • 第二个参数之后:实参
  • 返回值为一个新的函数
  • 使用的时候需要手动调用下返回 的新函数(==不会自动执行==)

原型继承

继承属性

通过构造函数+原型对象模拟实现继承,称为组合继承

原理:同call()把父类型的this改为子类型的this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
        //通过借用父构造函数来继承属性
        //1。父构造函数
        function Father(uname, age) {
            //this指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        //2.子构造函数
        function Son(uname, age) {
            //this指向子构造函数的对象实例,在Father执行时指定this值,这个this是子构造函数中的
            Father.call(this, uname, age);
        }
        var ldh = new Son('刘德华', 12);
        console.log(ldh);

继承方法

直接给构造函数添加的是静态方法,给构造函数的prototype添加的是实例方法

原理:创建一个父类的实例,让子类的原型对象执向这个实例所在的内存空间,但是子类的prototype里的constructor被覆盖了,需要重新指向子类构造函数,这样就能通过父类实例的中的proto找到父类中的方法,且在子类中添加自己的私有方法也不会影响父类。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
        //通过借用父构造函数来继承属性
        //1。父构造函数
        function Father(uname, age) {
            //this指向父构造函数的对象实例
            console.log(this);
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function () {
            console.log(100000);
        }
        //2.子构造函数
        function Son(uname, age) {
            //this指向子构造函数的对象实例
            Father.call(this, uname, age);
        }
        //Son.prototype = Father.prototype;
        Son.prototype = new Father();
		Son.prototype.constructor=Son
        Son.prototype.exam = function () {
            console.log('孩子要考试');
        }
        // var zxy = new Father('张学友', 12)
        var ldh = new Son('刘德华', 12);
        console.log(ldh);
        // console.log(zxy);

扩展内置对象

1
2
3
4
5
6
7
8
9
        Array.prototype.sum = function () {
            var sum = 0;
            for (var i = 0; i < this.length; i++) {
                sum += this[i];
            }
            return sum;
        }
        var arr1 = new Array(11, 22, 33);
        console.log(arr1.sum());

Web Workers

  1. 主线程才能操作dom,web workers可以将大计算量的代码另外开一个线程去计算,从而防止冻结用户界面
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="text" id="number">
<button id="btn">计算</button>
</body>
<script>
    window.onload=function(){
        document.querySelector('#btn').addEventListener('click',function () {
            let number = document.querySelector('#number').value
            console.log(number)
            //创建一个Worker对象
            let worker = new Worker('worker.js')
            //接收worker传过来的数据函数
            worker.onmessage=function (event) {
                console.log(event.data)
            }
            //向worker发送消息
            worker.postMessage(number)
        })
    }
</script>
</html>
1
2
3
4
5
6
7
onmessage = function (event) {
    postMessage(f(event.data))
}

function f(n) {
    return n <= 2 ? 1 : f(n - 1) + f(n - 2)
}

缺点

  1. 不能跨域加载js
  2. worker内代码不能访问DOM
  3. 浏览器兼容问题

函数

  1. 函数也是一个对象
  2. 函数不会检查实参类型和数量,少了则为undefined,多了则忽略
  3. return后的语句不会执行,return;后面不跟值相当于返回undefined,不写return也返回undefined。使用return结束整个函数
  4. 函数对象也可以return
  5. 实参会存到arguments(伪数组)中,函数中不定义形参也能使用,arguments有一个属性callee,是当前正在执行得函数对象

定义

  1. 命名函数

    function fn(){ }

  2. 匿名函数

    var fun = function() {}

  3. new Function(‘参数1’,‘参数2’,‘函数体’)

    var f = new Function(“xxxx ”);

==注意==:所有函数都是Function的实例

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/function.png

执行上下文栈

  1. 在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
  2. 在全局执行上下文(window)确定后,将其添加到栈中
  3. 在函数执行上下文创建后,将其添加到栈中(压栈)
  4. 在当前函数执行完后,将栈顶的对象移除(出栈)
  5. 当所有的代码执行完后,栈中只剩下window
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//进入全局执行上下文
var a = 10
var bar = function(x){
	var b = 5
	foo(x+b)
}
//进入foo执行行下文
var foo = function(y){
	var c = 5
	console.log(a+c+y)
}
//进入bar函数执行上下文
bar(10)

调用方式和this指向

  • 解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象
  1. 普通函数

    fn();//实际上是windows.fn()

    this指向windows

  2. 对象的方法

    obj.xxx();

    this指向对象

  3. 构造函数里的方法

    function xxx(){}

    new xxx();

    this指向实例,包括构造函数的prototype原型对象里的this也指向实例

  4. 事件函数

    btn.onclick=function(){}

    this执向调用者btn

  5. 定时器函数

    setInterval(function(){},1000)//实际上是windows.setInterval

    this指向window,只能用bind(this)改变this指向,因为call和apply是立即执行。

  6. 立即执行函数

    (function(){})()或者(function (){} ())

    this 指向windows

高阶函数

它接收函数作为参数,将函数的返回值作为输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/** 
 * 数值转换
 * @param {Number} val 要被处理的数值
 * @param {Function} fn 处理输入的val
 * @return {Number || String}
 */
const toConvert = function(val, fn) {
    return fn(val);
};

const addUnitW = function(val) {
    return val + 'W';
};

toConvert(123.1, Math.ceil); // 124
toConvert(123.1, addUnitW); // "123.1W"

另外,JS的回调函数同样是以实参形式传入其他函数中,这也是高阶函数(在函数式编程中回调函数被称为 lambda表达式):

1
2
3
4
5
[1, 2, 3, 4, 5].map(d => d ** 2); // [1, 4, 9, 16, 25]

// 以上,等同于:
const square = d => d ** 2;
[1, 2, 3, 4, 5].map(square); // [1, 4, 9, 16, 25]

闭包

变量作用域

  • 局部变量(函数作用域)
    1. 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
    2. 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
    3. 在函数作用域中可以访问全局变量,反之不行
    4. 当在函数作用域中操作一个变量时,有则直接使用。没有,则去上一级作用域中去寻找
    5. 定义形参就相当于var 定义变量
  • 全局变量(全局作用域)
    1. 在打开页面时创建,关闭页面时销毁
    2. 直接编写在script标签中的js代码,都在全局作用域
    3. 在函数中不用var定义的变量也在全局作用域中
    4. 全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
    5. 创建的变量都变成window对象的属性,创建的函数都变成window对象的方法
  • 当函数执行完毕,本作用域内的局部变量就会自动销毁

闭包的产生

  1. 当一个嵌套的内部函数引用了嵌套的外部函数的变量(函数),就产生了闭包
  2. 通过chrome的debug调试查看closure就是闭包

闭包的定义

指有权访问另一个函数作用域中变量的函数

闭包的作用

在函数a执行完毕并返回后,闭包使得Js的垃圾回收机不会回收a所占用的资源,因为a的内部函数b需要依赖a中的变量,从而延伸了变量的作用范围(生命周期)。

闭包的生命周期

产生:在嵌套内部函数定义执行完成时就产生了(不是在调用时)

死亡:在嵌套的内部函数成为垃圾对象时

demo
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1.function fn() {
            var num = 10;
            return function fun() {
                console.log(num);
            };
        }
        //fn外面的作用域访问fn()内部的局部变量
        fn()();//10


 2.      window.onload = function () {
        function fn() {
            let a = 2
            function add() {
                a++
                console.log(a)
            }

            function minus() {
                a--
                console.log(a)
            }

            return {add, minus}
        }
//没有触发闭包
        fn().add()//3
        fn().minus()//1
//区别
        let fn1 = fn() //触发闭包
        fn1.add()//3
        fn1.minus()//2
    }
     
     //如果fn()写成var f = fn()
     //那么再执行完后就不会释放闭包中的a,因为f变量指向fn(),return的函数中有对a的引用
     //当f=null时,闭包死亡,因为包函闭包的函数对象成为垃圾对象

闭包的例子

获取ul中li的索引号
  • 最初的方法
1
2
3
4
5
6
7
var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {//注意:这里lis是一个伪数组,循环中lis.length会计算多次,所以写成for(var i = 0 ,length=lis.length; i < length ;i++)这样能加快运行效率
            lis[i].setAttribute('index', i);
            lis[i].addEventListener('click', function () {
                console.log(this.getAttribute('index'));
            })
        }//在循环的同时给每个li添加自定义属性index,需要时再读取属性值
  • 利用闭包
1
2
3
4
5
6
7
8
for (var i = 0; i < lis.length; i++) {
            //创建了4个立即执行函数
            (function (num) {
                lis[num].onclick = function () {
                    console.log(num);
                }func
            })(i)
        }

这里面的闭包指的是匿名函数,通过(i)把值保存到了num中。每个点击事件都有一个局部变量num,num保存的是相应的i值。

  • 错误写法
1
2
3
4
5
for (var i = 0; i < lis.length; i++) {
            lis[i].addEventListener('click', function () {
                console.log(i);
            })
        }//无论点击哪个li都输出4

每个li标签的onclick事件执行时,本身onclick绑定的function的作用域中没有变量i,i为undefined,则解析引擎会寻找父级作用域,发现父级作用域中有i,且for循环绑定事件结束后,i已经赋值为4,所以每个li标签的onclick事件执行时,log的都是父作用域中的i,也就是4。

经典例子
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
function fn() {
            var num = 3;
            return function () {
                var n = 0;
                console.log(++n);
                console.log(++num);
            }
        }
        fn()();// 1 4
        fn()();//1 4
        
        var f1 = fn();
        f1();//1 4
        f1();//1 5

        

直接调用fn函数,此时fn执行完后,就连同它的变量num一同销毁,但是如果将fn的返回值赋给f1,这时候相当于f1=function(){var n = 0};并且匿名函数内部引用这fn里面的变量num,所以变量num无法被销毁,而变量n在调用完后会销毁,在每次调用时新建,于是最后只剩下num,所以再次调用时num是在4的基础上+1。

定时器中的闭包函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
		//3秒后同时打印所有li元素的内容
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (a) {
                setTimeout(function () {
                    console.log(lis[a].innerHTML);
                }, 3000)
            })(i);
        }
        
        //每隔3秒打印一个li元素的内容
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (a) {
                setTimeout(function () {
                    console.log(lis[a].innerHTML);
                }, a*3000)
            })(i);
        }

闭包的应用:定义js模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script src="myModule.js"></script>
<script>
   let fn = myModule() //使用第一种必须要先执行函数
    fn.doSomething()
    myModule2.doSomething()
</script>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function myModule() {
    let msg = 'my msg'

    function doSomething() {
        console.log(msg.toLowerCase())
    }

    function doSomething2() {
        console.log(mag.toUpperCase())
    }

    return {
        doSomething,
        doSomething2
    }
}

//如果是匿名函数的自调用,则暴露在window对象中
(function myModule2() {
    let msg = 'my msg'

    function doSomething() {
        console.log(msg.toLowerCase())
    }

    function doSomething2() {
        console.log(mag.toUpperCase())
    }

    window.myModule2 = {
        doSomething,
        doSomething2
    }
})()

闭包的缺点

因为闭包会使得Js的垃圾回收机不会回收占用的资源,滥用闭包会造成内存泄露,所以在必要时,我们要及时释放这个闭包函数

内存溢出与内存泄漏

内存溢出:栈溢出,堆溢出

内存泄露:内存泄漏积累多了就容易导致内存溢出

常见的内存泄漏:

  1. 意外的全局变量
  2. 没有及时清理的计时器或回调函数
  3. 闭包

Let的出现

将上面的错误写法中的var改为let,let会产生块级作用域

1
2
3
4
5
for (let i = 0; i < lis.length; i++) {
            lis[i].addEventListener('click', function () {
                console.log(i);
            })
        }//点击li输出相应的索引

递归

函数内部自己调用自己,作用和循环一样

注意:防止发生栈溢出,所以要加退出条件return

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<script>
        var data = [{
            id: 1,
            gname: '家电',
            goods: [{
                id: 11,
                gname: '冰箱',
                niubi: [{
                    id: 111,
                    gname: 'haha'
                }]
            }, {
                id: 12,
                ganme: '洗衣机'
            }]
        }, {
            id: 2,
            gname: '服饰'
        }]
        //输入id号返回数据对象
        // 1.利用foreach遍历
        function getid(json, id) {
            var o = {};
            json.forEach(function (value, index, json) {
                // console.log(value);
                if (value.id == id) {
                    // console.log(value);
                    o = value;
                    // 2.想要得到里层的数据 11 12
                    //里面应该有goods数组,且长度不为0
                } else if (value.goods && value.goods.length > 0) {
                    o = getid(value.goods, id);
                } else if (value.niubi && value.niubi.length > 0) {
                    o = getid(value.niubi, id);
                }
            });
            return o;
        };

        console.log(getid(data, 1));
        console.log(getid(data, 2));
        console.log(getid(data, 12));
        console.log(getid(data, 111));
    </script>

浅拷贝和深拷贝

  • 浅拷贝只是拷贝一层,更深层次的对象级别的只拷贝引用(修改数据会修改原来的)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    var obj1 = {
           name: 'zs',
           age: 18,
           sex: '男',
           dog: {
             name: '金毛',
             age: 2,
             yellow: '黄色'
           }
         }
    
         var obj2 = {};
    
    function copy(o1, o2) {
          for (var key in o1) {
            o2[key] = o1[key];
          }
        }
        copy(obj1, obj2);
    
        // 修改obj1中的成员
        obj1.name = 'xxxx';
        obj1.dog.name = '大黄';
    
        console.dir(obj2);
    // name 属性深拷贝,不改变;dog对象浅拷贝, dog.name 随之发生改变
    

    ES6语法糖:Object.assign(new,old)

  • 深拷贝拷贝多层,每一级的数据都会拷贝

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    // 定义一个深拷贝函数  接收目标target参数
    function deepClone(target) {
        // 定义一个变量
        let result;
        // 如果当前需要深拷贝的是一个对象的话
        if (typeof target === 'object') {
        // 如果是一个数组的话
            if (Array.isArray(target)) {
                result = []; // 将result赋值为一个数组,并且执行遍历
                for (let i in target) {
                    // 递归克隆数组中的每一项
                    result.push(deepClone(target[i]))
                }
             // 判断如果当前的值是null的话;直接赋值为null
            } else if(target===null) {
                result = null;
             // 判断如果当前的值是一个RegExp对象的话,直接赋值    
            } else if(target.constructor===RegExp){
                result = target;
            }else {
             // 否则是普通对象,直接for in循环,递归赋值对象的所有值
                result = {};
                for (let i in target) {
                    result[i] = deepClone(target[i]);
                }
            }
         // 如果不是对象的话,就是基本数据类型,那么直接赋值
      } else {
            result = target;
      }
         // 返回最终结果
        return result;
    }
    

    ==注意==:先判断数组再判断对象,因为数组也属于对象,如果对象中没有function和RegExp且为json对象可以先用

    JSON.stringify转为字符串再用JSON.parse转为新的对象

正则

创建

1
2
3
4
var regexp = new RegExp("正则表达式""匹配模式");
//正则表达式为字符串,匹配模式包括i(忽略大小写),g(全局匹配模式)
var regexp = / /i;
//字面量创建

检测

1
2
regexp.test(str);
//返回布尔值

特殊字符

边界符

  • ^:行首文本以谁开始

  • &:行尾文本以谁结束

  • \bxxx\b:表示单词边界

    /^abc$/

字符类

  • :中括号里的内容是或的关系

    1
    2
    3
    4
    5
    6
    
    /[abc]/
    表示包含有a或b或c的一个或多个
    /^[abc]$/
    表示有且仅有其中一个
    /[^abc]/
    除了中括号里的
    

量词符

用于设定每个模式出现的次数

量词 说明
* 重复0次或更多次,相当于{0,}
+ 重复一次或更多次,相当于{1,}
重复0次或一次,相当于{0,1}
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n次到m次(中间无空格)
1
2
3
4
5
/^a*$/
/^a{3,8}$/
/^abc{3}$/
/^[abc]{3}$/     //[]内的单个内容可以重复三次
/^(abc){3}$/     //()内的重复三次

正则中的预定义类

预定义类 说明
\d 匹配0-9之间的任一数字
\D 匹配0-9以外的字符,相当于/[^0-9]/
\w 匹配任意的字母,数字和下划线,相当于/[A-Za-z0-9_]/
\W 除了所有字母,数字和下划线以外的字符,相当于/[^A-Za-z0-9_]/
\s 匹配空格(包括换行符,制表符,空格符等),相当于[\t\r\n\v\f],去除开头和结尾空格/^\s*|\s*$/ g
\S 匹配非空格的字符,相当于/[^\t\r\n\v\f]/

正则中的替换

  • replace(//,’’)只替换第一个,加上/g全局替换

    1
    2
    3
    
            btn.onclick = function () {
                div.innerHTML = text.value.replace(/激情|gay/g, '**');
            }
    

修饰符

  • /g:全局匹配
  • /i:忽略大小写
  • /gi:全局匹配且忽略大小写
[ ] 中括号里的内容是或的关系
[ab] a|b
[a-z] 任意小写字母
[A-Z] 任意大写字母
[A-z] 任意字母
/a[bde]c/ 检测一个字符串中是否含有abc或adc或aec
/[^]/ 除了中括号里的都行

ES5

严格模式

为脚本开启‘use strict’写在script标签第一行

为函数开启写在函数体第一行

特点

  1. 变量必须先声名

    ==区别:==标准模式中

    ​ a=2||this.a=2是给window对象的一个属性,可以用delete删除

    ​ var a=2也是给window对象一个属性,但是不能用delete删除

  2. 全局作用域中this是undefined,而不是windows对象

  3. 构造函数不加new调用(不创建实例)的话会报错,因为严格模式中this为undefined,要new之后this才有指向的实例对象,标准模式中构造函数没有实例对象,它的this也是指向window对象的

    ==注意:==定时器的this还是指向window

  4. 参数不能同名

JSON对象

写法:

  • 只能用双引号
  • 所有名字都必须用双引号包起来

JSON对象转JSON字符串

JSON.stringify(json)

JSON字符串转JSON对象

JSON.parse(json)

JSON的简写

名字和值一样时保留一样即可

1
2
3
4
5
6
let a = 12;
let b = 15;
let c = 30;
let json = {a,b,c}
//相当于
let json = {a:a,b:b,c:c}

json中方法的简写

ES6中可以和面向对象中的方法一样把function删除

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let json = {
 "name":"xqz",
 show(){
     alert(this.a)
 }
}
//相当于
let json = {
	"name":"xqz",
	show: function(){
        alert(this.a)
    }
}

Object扩展

常用的三个静态方法

Object.create(prototype,[descriptors])

作用:

  1. 以指定对象为原型创建新的对象(通过__proto__可以找到)

  2. 为新的对象指定新的属性,并对属性进行描述

    value:指定值

    writable:标识当前属性值是否可以修改,默认为false

    configurable:标识当前属性是否可以被删除,默认为false

    enumberable:标识当前属性是否能用for in 枚举 默认为 false

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/ES5Object%E6%89%A9%E5%B1%951.png

Object.defineProperty()

  • 定义对象中新属性或修改原有的属性
  • obj:目标对象
  • prop:要增加或修改的属性名字
  • descriptor:增加或修改的属性所持有的特性
    1. value:设置属性的值,默认为undefined
    2. writable:值是否可以重写,默认为false,遍历时就无法遍历出来
    3. enumerable:目标属性是否可以被枚举,默认为false也遍历不出来
    4. configurable:目标属性是否可以别删除或者再次修改特性,默认false
1
2
3
4
5
6
7
8
        Object.defineProperty(obj, 'num', {
            value: 20000,
            writable: false,
            enumerable: false,
            configurable: false
        })
        delete obj.num;
        console.log(obj);

Object.defineProperties(object,descriptors)

作用:

  1. 为指定对象定义扩展多个属性
  2. get:用来获取当前属性值的回调函数
  3. set:用来修改当前属性值的触发回调函数,并且实参即为修改后的值
  4. 存取器属性:setter,getter一个用来存,一个用来取
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
        let obj = {firstName:'x',lastName:'qz'}
        Object.defineProperties(obj,{
            fullName:{
                get:function () {
                    return this.firstName+this.lastName//获取属性时自动调用get方法
                },
                set:function (data) {//设置属性时自动调用set方法
                    let arr = data.split(',')
                    this.firstName=arr[0]
                    this.lastName=arr[1]
                }
            }
        })
        console.log(obj.fullName)
        obj.fullName='w,xx'
        console.log(obj.fullName)

对象本身的两个方法

get propertyName(){}

set propertyName(){}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
        let obj2={
            firstName:'x',
            lastName:'qz',
            get fullName(){
                return this.firstName+''+this.lastName
            },
            set fullName(data){
                let arr = data.split(' ')
                this.firstName = arr[0]
                this.lastName = arr[1]
            }
        }
        console.log(obj2)
        obj2.fullName='w xx'

Array扩展

indexOf

Array.prototype.indexOf(value) 得到值在数组中的第一个下标

lastIndexOf

Array.prototype.lastIndexOf(value) 得到值在数组中的最后一个下标

forEach

Array.prototype.forEach(function(item,index){}) 遍历数组

  1. array.forEach(function(currentValue,index,arr)) 遍历每个元素,将每个元素的返回值给回调函数
  2. 数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以来定义形参来读取这些内容
  3. 浏览器会在回调函数中传递三个参数
  • currentValue:数组当前项的值
  • index:数组当前项的索引
  • arr:数组对象本身

==注意==:如果return false会阻止函数继续向下执行,但不会结束遍历,会继续遍历下一个元素,无返回值

1
2
3
4
5
6
7
8
        var arr = ['red', 'green', 'blue', 'pink'];
        arr.forEach(function (value) {
            if (value == 'green') {
                console.log('找到');
                return false;
            }
            console.log(11);           
        })

Array.prototype.map(function(item,index){}) 遍历数组返回一个新数组,返回加工后的值

map

映射,给多少处理完后还多少

map() 方法==返回一个新数组==,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

1
2
3
var array1 = [1,4,9,16];
const map1 = array1.map(x => x *2);
console.log(map1);

filter

Array.prototype.filter(function(item,index){}) 遍历过滤出一个新的子数组,返回条件为true的值

  1. array.filter(function(currentValue,index,arr))会==返回一个新的数组==,新数组中是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
  2. 通过return true或false来决定保留不保留

注意:直接返回新数组

1
2
3
4
5
        var arr = [23, 13, 545, 52];
        var newArr = arr.filter(function (value, index, array) {
            return value >= 20;
        })
        console.log(newArr);//[23,545,52]

some

array.some(function(currentValue,index,arr))用于查找数组中是否有满足条件的元素

==注意==:

  • 返回的是布尔值,找到返回true且找到后不会再继续执行,找不到返回false。
1
2
3
4
5
        var arr = [3, 2, 3, 5, 5, 4, 23, 55, 45, 435, 3, 4524, 5, 245, 2, 52];
        var arr1 = arr.some(function (value, index, array) {
            return value >= 20;
        });
        console.log(arr1);//true

区别:foreach和filter不会终止迭代,some检测到符合要求的元素后会停止,且返回值三者不同

reduce(参数一,参数二)

参数一是回调函数

参数二是tmp的默认值,0

进去一堆,出来一个

  1. tmp为中间结果,是函数返回的结果,当遍历到数组最后一个元素是=0时,函数的返回值则为最终结果
  2. item为数组中的每一项
  3. index为数组索引
1
2
3
4
5
6
7
8
var arr = [12,34,3,4,2];
var result = arr.reduce(fucntion(tmp,item,index){
     if(index != arr.length-1){
   	 	return tmp*item;//求和
	}else{
        return tmp*item/arr.length;//最后一次求平均数
    }	
})

Function扩展

Function.prototype.bind()

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/bind.png

ES6

let

  1. 产生块级作用域

  2. for循环中防止i变成全局变量

  3. let无变量提升(js预解析会把var和function(){}提到最前面)

  4. 暂时性死区

  5. 不能重复声明相同的变量名

    1
    2
    3
    4
    5
    6
    
            var tmp = 123;
            if (true) {
                    tmp = 'avd';
                    // let tmp;如果在if中需要用一样的变量名,用let声名
                }
                console.log(tmp);
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
        <script>
            let arr = [];
            for (let i = 0; i < 2; i++) {
                arr[i] = function () {
                    console.log(i);
                }
            }
            arr[0]();
            arr[1]();
            //每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时输出的是自己的上一级(循环产生的块级作用域)作用域下的i值
        </script>
    

const

  1. 用来声名常量,值无法更改

  2. 也具有块级作用域,不存在变量提升

    1
    2
    3
    4
    5
    6
    7
    8
    
            if (true) {
                const a = 10;
                if(true){
                    const a=20;
                    console.log(a);
                }
                console.log(a);
            }
    
  3. 必须赋初始值

  4. 赋值后的内存地址不能修改,但是复杂数据类型内的值可以改

    1
    2
    3
    
    const arr=[100,100];
    arr[0]='a';//这里没有修改内存地址,所以是可以修改的
    arr=['a',100];//这里修改了内存地址,所以是无法修改的
    

解构赋值

如果解构后无值则为undefined

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
        //数组解构
        let [a, b, c] = [1, 2, 3];
        console.log(a);
        let person = {
            name: 'xuqianzhou',
            age: 13
        };

        let {
            name,
            age
        } = person;
        console.log(name);

箭头函数

  • 不能使用argunments来获取参数

  • 函数体只有一句可以省略大括号

  • 只有一个参数可以省略括号

  • 箭头函数不绑定this关键字,箭头函数中的this指向的是函数定义位置上下文的this(所处的对象)

    1. 如果箭头函数外层有函数,箭头函数的this和外层函数的this一摸一样
    2. 如果外层没有函数,指向window
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
        <script>
            const add = (a, b) => {
                console.log(a + b);
            }
            add(1, 3);
    
            const obj = {
                name: 'zhangsan'
            }
    
            function fn() {
                console.log(this);
                return () => {
                    console.log(this);//这里两个this相同
    
                }
            }
            const fun = fn.call(obj);
            fun();
        </script>
    

    注意:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
            var age = 100;
            var obj = {
                age: 20,
                say: () => {
                    console.log(this);//这里的this指向window
                    alert(this.age);
                }
            }
            obj.say();
    

形参默认值

1
2
3
function show(a,b=5,c=10){
//当不传b的值,默认为5
}

三点运算符

  • 将不定数量的参数表示为一个数组,只能放在最后

    1
    2
    3
    4
    5
    6
    7
    8
    
          const sum = (num, ...arr) => {
                console.log(num);
                console.log(arr);
                let total = 0;
                arr.forEach(item => total += item);
                return total;//50
            };
           console.log( sum(10, 20, 30));
    
  • 可以配合解构使用

    1
    2
    
    var obj={xxx,xxx,xxx};
    let {s1,...s2}=obj;//s1是obj对象中的第一个数据,剩下的在s2数组中
    

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E4%B8%89%E7%82%B9%E8%BF%90%E7%AE%97%E7%AC%A6.png

JSON

写法:

  • 只能用双引号
  • 所有名字都必须用双引号包起来

JSON对象转JSON字符串

JSON.stringify(json)

JSON字符串转JSON对象

JSON.parse(json)

JSON的简写

名字和值一样时保留一样即可

1
2
3
4
5
6
let a = 12;
let b = 15;
let c = 30;
let json = {a,b,c}
//相当于
let json = {a:a,b:b,c:c}

json中方法的简写

ES6中可以和面向对象中的方法一样把function删除

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let json = {
 "name":"xqz",
 show(){
     alert(this.a)
 }
}
//相当于
let json = {
	"name":"xqz",
	show: function(){
        alert(this.a)
    }
}

Array的扩展方法

扩展运算符

将数组或对象转为用逗号分隔的参数序列,其实就是和剩余参数一个相反的过程,这里用逗号拆开,剩余参数是合并为一个数组

1
2
let arr=[1,2,3];
log(...arr)//1 2 3(逗号被log当作参数分隔符)
  • 可以用于合并数组

    1
    2
    3
    4
    5
    
    arr1=[1,2,3];
    arr2=[4,5,6];
    arr3=[...arr1,...arr2];
    //或者
    arr1.push(...arr2);
    
  • 可以将伪数组转为真正的数组

    1
    2
    3
    4
    
    //方法一:
    arr2=[...arr1];//arr1是伪数组;
    //方法二:
    let arr2=Array.form(arr1,item=>item+1);//将arr1伪数组转为真正的数组,并且每个数组元素加1
    

Array.form()

将伪数组转为数组且对元素进行加工

Array.find()

用于找出第一个符合条件的数组成员,返回对象,如果没有找到则返回==undefined==

1
2
3
4
5
6
7
8
let arr[{
id:1,
name:'张三'
},{
id:2,
name:'李四'
}]
let target = arr.find((item,index)=>item.id==2);//函数用于返回查找的条件

Array.findindex()

用于找出第一个符合条件的数组成员的==位置==,如果没有返回==-1==

1
2
3
let arr=[1,5,9,15];
let index=arr.findindex((value,index)=>value>9);//函数用于返回查找的条件
log(index);//2

String的扩展方法

模板字符串

  • 可以解析变量

    1
    
    `hello,my name is${变量名}`
    
  • 可以换行

  • 可以调用函数

    1
    2
    3
    4
    
    const sayhello = function(){
    return....;
    }
    let agree = `hello,my name is ${sayhello()}`
    

includes()

判断是否包含指定的字符串

startsWith()

startsWith()

是否以某字符开头,返回布尔值

startsWith(‘Hello’)

endsWith()

是否以某字符结尾,返回布尔值

endsWith(’!’)

repeat()

将原字符重复n次,返回一个新的字符串

str.repeat(3);

trim()

删除字符串两边的空格,不影响原字符串,==返回一个新的字符串==(防止用户输入空格)

Number的扩展方法

二进制与八进制数值表示法:二进制0b,八进制0o

isFinite()

判断是否是有限大的数

isNaN()

判断是否是NaN

isInteger()

判断是否是整数

parseInt()

判断是否是整数

trunc()

将字符串转换为对应的数值

Object的扩展方法

  1. Object.is(v1,v2)

判断2个数据是否相等

  1. Object.assign(target,source1,source2..)

    将源对象的属性赋值到目标对象上,如果没有则使用原来的默认值

  2. 直接操作_proto_属性

    let obj2 = {}

    obj2.proto = obj1

  3. Object.keys()

  • 用于获取对象自身所有的属性

  • 返回由属性名组成的数组

1
2
3
4
5
6
7
8
        var obj = {
            id: 1,
            pname: '小米',
            price: 1999,
            num: 2000
        }
        var arr = Object.keys(obj);
        console.log(arr);

Promise

作用:将异步操作写成同步代码,避免了回调地狱

promise对象的3个状态

  1. pending:初始化状态
  2. fullfilled:成功状态
  3. rejected:失败状态

过程:

  1. 首先new promise对象
  2. 在异步代码执行成功时,调用resolve()方法,改变对象状态,传的参数在promise实例的then方法中的第一个函数中获取
  3. 异步代码执行失败时,调用reject()方法,改变对象状态,传的参数在promise实例的then方法中的第二个函数中获取
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
let promise = new Promise((resolve,reject)=>{
    //初始化promise状态:pending:初始化
    console.log('111')
    //执行异步操作,通常是发送ajax请求,开启定时器
    setTimeout(()=>{
        console.log(333)
        //根据异步任务的返回结果去修改promise的状态
        //异步任务执行成功
        resolve(data) //修改promise的状态为 fullfilled:成功的状态

        //异步任务执行失败
        // reject(err)   //修改promise的状态为 rejected:失败的状态
    },2000)
})

promise.then((data)=>{
    //成功的回调
    console.log('成功')
},(err)=>{
    //失败的回调
    console.log('失败')
})

symbol

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/symbol.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/symbol2.png

==注意==:

  1. for in 和for of 不能遍历symbol属性

对象的Symbol.iterator属性:指向对象的默认遍历器方法(fenerator)

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/%E5%AF%B9%E8%B1%A1%E7%9A%84iterator%E6%8E%A5%E5%8F%A3.png

==注意==:

  1. 三点运算符和解构赋值实际上就是实现了iterator接口

iterator遍历器

概念:是一种接口机制,为各种不同的数据结构提供统一的访问机制

作用:

  1. 为各种数据结构,提供一个统一的,简便的访问接口
  2. 使得数据结构的成员能够按照某种次序排列
  3. ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费

工作原理:

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/iterator%E6%8E%A5%E5%8F%A3.png

底层实现:

实际上这里的nextIndex使用了闭包 https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/iterator%E6%9C%BA%E5%88%B6.png

实现了iterator接口的数据结构

assets/%E5%AE%9E%E7%8E%B0%E4%BA%86interator%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.png

==注意==:

  1. 对象没有iterator接口,无法用for of去遍历循环

generator

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/generator.png

普通函数:一路到底

generator函数:函数加*,中间能停,next一次走一步,yield处停止

  1. yield的值是next中传入的参数,==注意==:执行函数的第一个next不能传参,因为传了也不能赋值给变量,第二个next传的参数是第一个yield的返回值
  2. 调用next方法的返回值是函数return的值,或者yield后面的值
  3. ==生成遍历器对象==,给对象的Symbol.iterator属性添加一个遍历器对象后,就能用for of遍历

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/generator2.png

yield

可以传参,返回

看成把一个函数分成多个子函数,show_1,show_2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    //可以传参
function* show() {
  alert('a')
  let a = yield
  alert('b')
  console.log(a)
}

let genObj = show()//yield之前函数传参
genObj.next(12)//没法给yield传参,执行函数开始到第一个yield,此时yield有值,但是并没有给变量a
genObj.next(5)//执行yield往后的代码,let a是在yield之后

//可以返回
function* show2() {
  alert('a')
  yield 12
  alert('b')
  return 55
}
let genObj2 = show2()
let res1 = genObj2.next()
console.log(res1)
let res2 = genObj2.next()//这里的结果是通过函数中的return得到的
console.log(res2)

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/generatorAjax.png

==注意==:

  1. 在getNews里面调用next方法并且传参,这样能在generator中得到url的值

class类和继承

类和对象

  • 关键字:class

    注意:类中所有函数不需要加function关键字,多个方法间不加逗号分隔.

  • 方法中的this指向:方法的调用者

构造器

  • 关键字:constructor()

  • 作用:用于传递参数,返回实例对象,new生成对象实例时自动调用。

    注意:如果未定义会自动创建一个constructor()

  • this指向:实例对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 <script>
  class Star {
    constructor(uname, age) {
      this.uname = uname;
      this.age = age;
    }
    sing(song) {
      console.log(this.uname + song);
    }
  }
  var ldh = new Star('刘德华', 18);
  var zxy = new Star('张学友')
  console.log(ldh.uname + ldh.age);
  ldh.sing('冰雨')
</script>

==注意==:

this的指向问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body>
<button>
  唱歌
</button>
<script>
  var that;
  class Father {
    //构造器里面的this指向实例对象
    constructor(uname, age) {
      that = this;
      this.uname = uname;
      this.age = age;
      // this.sing();
      this.btn = document.querySelector('button');
      this.btn.onclick = this.sing;//因为这个按钮调用了这个函数
    }
    //这个方法里的this 指向的是btn 这个按钮
    sing() {
      // console.log(this.uname);
      console.log(that.uname); //that 里面存储的是constructor里面的this
    }
  }
  var father = new Father('刘德华');
</script>
</body>

类的继承

关键字
  • entends

  • 注意:ES6中类没有变量提升,必须先定义类,才能实例化

继承属性

调用父类构造函数:

  • 关键字:super(x,y)

注意:在constructor中调用,且必须在子元素的this之前调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <script>
  class Father {
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
    sum() {
      console.log(this.x + this.y);
    }
    money() {
      console.log(100);
    }
  }
  class Son extends Father {
    constructor(x, y) {
      super(x, y);
    }
  }
  var son = new Son(1, 2);
  son.money();
  son.sum();
</script>
继承方法
  • 子类实例会自动继承父类的方法

  • 在子类中调用父类方法:

    • 关键字:super.父类方法名()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    <script>
  class Father {
    say() {
      return '我是爸爸'
    }
  }
  class Son extends Father{
    say() {
      console.log(super.say()+'的儿子');
    }
  }
  var son = new Son();
  son.say();
  • 扩展子类的方法
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    <script>
  class Father {
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
    sum() {
      console.log(this.x + this.y);

    }
  }
  class Son extends Father {
    constructor(x, y) {
      super(x, y);
      this.x = x;
      this.y = y;
    }
    sub() {
      console.log(this.x - this.y);
    }
  }
  var son = new Son(3, 1);
  son.sum();
  son.sub();
</script>

深度克隆

  1. arr.concat():数组浅拷贝
  2. arr.slice():数组浅拷贝
  3. JSON.parse(JSON.stringify(arr/obj)):数组或对象深拷贝,拷贝的数据里不能有函数,这里实际上拷贝的是json字符串,是基本数据类型
  4. Object.assign();浅拷贝
  5. 浅拷贝拷贝引用,拷贝以后的数据会影响原数据
  6. 深拷贝拷贝值,拷贝以后的数据不会影响原数据

封装深拷贝函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
let arr = [1, 2, {userName: 'xqz'}, 3, 2]

function clone(a) {
  if (a instanceof Array) {
    let arr1 = []
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] instanceof Object) {
        arr1[i] = clone(arr[i])
      } else {
        arr1[i] = arr[i]
      }
    }
    return arr1
  } else if (a instanceof Object) {
    let obj = {}
    for (const key in a) {
      obj[key] = a[key]
    }
    return obj
  }
}

let newArr = clone(arr)
console.log(newArr)
newArr[2].userName = 'hhh'
console.log(arr)
console.log(newArr)

set容器

  1. 无序的,不可重复的多个value的集合体
  • 类似于数组,但是成员不能重复,会自动去重

    1
    2
    
    const s = new Set();
    const s = new Set([1,2,3,4,4])//可以接收数组初始化,会自动去重4
    
  • 数据数量

    s.size();

  • 可以用于数组去重

    1
    2
    3
    
    var arr = [1,2,3,4,4];
    const s = new Set(str);
    var arr = [...s];//这里用扩展运损符将s用逗号分隔开
    

实例方法

  • add(value):添加某个值,返回Set结构本身
  • delete(value):删除某个值,返回布尔值,表示是否和删除成功
  • has(value):返回布尔值,表示该值是否为set的成员
  • clear():清除所有成员,没有返回值

Set遍历

和数组一样有foreach方法,无返回值

s.forEach(value=>log(value))

map容器

  1. 无序的key,不重复的多个key-value的集合体

Map()

Map(array)

set(key,value)//添加

get(key)

delete(key)

has(key)

clear()

size

1
2
3
4
5
6
        let map = new Map([['username',25],[36,'age']])
console.log(map)
map.set(78,'haha')
console.log(map)
map.delete(78)
console.log(map)

for of

  1. 遍历数组
  2. 遍历set
  3. 遍历map
  4. 遍历字符串
  5. 遍历伪数组

ES7

async/await

  • ES7的新语法,可以更加方便得进行异步操作
  • async用于函数上(async函数得返回值时promise对象)
  • await用于saync函数中(await可以得到当前异步的结果)

==注意==:因为async返回的也是个promise对象,在调用时也可以用then获得函数的返回值

1
2
3
4
5
6
7
8
        async function queryData() {
  var ret = await axios.get('adata');
  console.log(ret.data);
  return ret.data;
}
queryData().then(data => {
  console.log(data);
});

==注意==:await后面必须跟promise实例对象,才能获取异步的结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
        async function num() {
  var ret = await new Promise(function (resolve, reject) {//resolve成功,reject失败
    setTimeout(function () {
      resolve('nihao')
    }, 1000)
  });
  console.log(ret);
  return ret;
};
num().then(data => {
  console.log(data);
})
  • 处理多个异步任务

    桉顺序写即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
            axios.defaults.baseURL = 'http://localhost:3000';
            async function queryData() {
                var info = await axios.get('async1');
                var ret = await axios.get('async2?info=' + info.data);//用info作为参数
                return ret.data;
            }
            queryData().then(ret=>{
                console.log(ret);
            })
    

Array.includes()

表示某个数组是否包含给定的值,返回布尔值

1
2
arr=[1,2,3];
arr.includes(2);//true

指数运算符

**

模块化规范

namespace模式

1
2
3
4
5
6
let obj ={
  msg:'module',
  foo(){
    console.log('foo()',this.msg)
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

</body>
<script src="module.js"></script>
<script>
  obj.foo()
  obj.msg='修改了'//对象中的值仍然可以被修改
  obj.foo()
</script>
</html>

IIFE模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//有独立的作用域
(function (window) {
  let msg = 'module'

  function foo() {
    console.log('foo()', msg)
  }
  //给全局的window对象添加属性
  window.module={foo}
})(window)//闭包
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

</body>
<script src="module.js"></script>
<script>
  module.foo()
</script>
</html>

IIFE模式增强

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//有独立的作用域
(function (window, $) {
  let msg = 'module'

  function foo() {
    console.log('foo()', msg)
  }

  window.module = foo
  $('body').css('background', 'red')

})(window, jQuery)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

</body>
<script src="jquery.min.js"></script>
<script src="module.js"></script>
<script>
  module()
</script>
</html>

CommonJS

规范

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/Commmonjs.png

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/commonjs.png

基于服务器端

文件结构

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/CommonJS-node.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//1
module.exports={
  msg:'module1',
  foo(){
    console.log(this.msg)
  }
}
//2
module.exports = function () {
  console.log('module2')
}
//3
exports.foo=function () {
  console.log('foo() module3')
}
exports.bar=function () {
  console.log('bar() module3')
}
exports.arr=[1,2,3,5,4,3,3,5]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//app.js
//引入第三方库
let uniq =require('uniq')
//将其他的模块汇集到主模块
let module1 = require('./modules/module1')
let module2 = require('./modules/module2')
let module3 = require('./modules/module3')

module1.foo()
module2()
module3.foo()
module3.bar()
let result = uniq(module3.arr)
console.log(result)

==注意==:

  1. npm install xxx –save-dev 标识开发依赖包

基于浏览器端

文件结构

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/Commonjs-browserify.png

  1. 首先和服务端一样,用module.epxorts进行暴露,require进行引入

  2. 其次

    全局下载browserify包:npm install browerify

    再局部下载开发依赖:npm install browerify –save-dev

  3. 其次命令行打包处理:

    错误内容: 'browserify' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    已解决: 命令行前面加上browserify的路径即可, node_modules\.bin\browserify js/src/app.js -o js/dist/build.js

    ==注意==:

  4. 前面的是原文件

  5. -o表示output

  6. 后面的是输出文件的目录以及文件名字

  7. 然后在index.html中引入输出的新文件,即可在浏览器端使用require

AMD

规范

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/AMD.png

文件结构

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/RequireJS.png

下载requireJS

定义没有依赖的模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//没有依赖的模块
define(function () {
  let name = 'dataService'

  function getName() {
    return name
  }

  //暴露模块
  return {getName}
})

定义有依赖的模块

1
2
3
4
5
6
7
8
9
//定义有依赖的模块
define(['dataService'],function (dataService) {
  let msg = 'alerter.js'
  function showMsg() {
    console.log(msg,dataService.getName())
  }
  //暴露模块
  return {showMsg}
})

main.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(function () {

  requirejs.config({
    baseUrl: 'js/',//基本的路径,出发点在根目录下
    paths: {//配置路径
      dataService: './modules/dataService',//属性名和之前定义的模块名一样
      alerter: './modules/alerter'
    }
  })
  requirejs(['alerter'], function (alerter) {
    alerter.showMsg()
  })
})()

==注意==:

  1. 引入jquery时要小写

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

</body>
<script data-main="./js/main.js" src="./js/libs/require.js"></script>//先通过src找到require第三方库,然后通过data-main找到main.js,再从main中的path找到相应的模块路径
</html>

CMD

ES6

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/ES6.png

步骤:

  1. 定义package.json文件

  2. 安装babel-cli,babel-preset-es2015和browserify

  • npm install babel-cli browserify -g
  • npm install babel-preset-es2015 –save-dev
  • preset 预设(将es6转为es5的所有插件打包)
  1. 定义.babelrc文件,

    1
    2
    3
    
    {
      "presets": ["es2015"]
    }
    
  2. 编码

    文件结构

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/ES6babel.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//暴露模块 分别暴露
export function foo() {
  console.log('foo() module1')
}

export function bar() {
  console.log('bar() module1')
}

export let arr = [1,3,4,5]

统一暴露

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//统一暴露
function fun() {
  console.log('fun() module2')
}

function fun2() {
  console.log('fun2() module2')
}

export {fun,fun2}

默认暴露

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//默认暴露 可以暴露任意数据类型 暴露什么数据接收到的就是什么数据
//只能一次
// export default ()=>{
//     console.log("默认")
// }
export default {
  msg:'默认暴露',
  foo(){
    console.log(this.msg)
  }
}

main

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//引入其他的模块

//语法:import xxx from ‘路径’
import {foo,bar} from './module1'
import {fun,fun2} from './module2'
import module3 from './module3'

console.log(module3.foo())
console.log(foo(),bar(),module2)

console.log(module1,module2)

​ ==注意==:

  1. 要使用解构赋值的方式来引入模块

5.编译

  • 使用babel将ES6编译为ES5代码:==babel js/src -d js/lib==

    ​ 源文件目录 编译后的文件目录

    改成require那种es5的,但是require仍然需要转换

  • 使用Browserify编译js:==browserify js/lib/main.js -o js/lib/bundle.js==

6.引入:index.html中使用bundle文件

​ ==注意==:

  1. 一旦修改了js文件就需要重新编译打包

打包完成后文件结构

https://raw.githubusercontent.com/yzuxqz/pic-bed/master/notes-img/ES6%E6%89%93%E5%8C%85%E5%90%8E.png