综合知识复习

变量

  1. 变量创建

    需要使用var 关键字,不使用var的时候创建的是全局变量,在js当中当你创建一个变量的时候,这个变量只是一个名字而已。而且因为预处理机制的存在变量的创建会发生一个声明提前的问题。

    变量创建的过程可以分成3个步骤:

    1. 创建名字
    2. 确定作用范围
    3. 将创建的函数提升到所在函数的最顶端
  2. 变量的赋值

    对于基础数据而言这个值是直接保存到变量当中。

    对于对象而言值是保存在内存当中然后把内存的地址保存到变量当中。

    对于变量而言它里面保存的永远是一个基础类型的值。你可以把变量想象成为一个牌子,当你声明变量的时候,就会声明出来这么一个牌子。而这牌子上写的是undefined,而当你对这个变量赋值的事实如果它是一个基础数据类型,这个基础数据类型是可以直接写出来的。比如:123,abc,true,false。对于这些可以直接写出来的基础数据类型js是直接把它写在这个牌子上的。对于不能直接写出来的数据类型比如一个人、一个狗、一支笔这些对象而言它是没法直接写出来的。对于这种东西它会直接把这个对象直接保存到内存当中。对于这个内存来讲它会有一个内存地址,然后把这个地址写到牌子上。也就是把这个地址保存到变量当中。

  3. 对变量的操作

    • 对变量的属性进行操作

      对于基础数据类型不会报错也没有任何效果。

      对于引用类型而言,它是可以正常的去操作的。

    • 对变量进行修改

      所有对变量的修改都相当于重新的赋值。

      基础数据类型,相当于把牌子的值抹掉,然后写上一个新的值。

      引用数据类型,牌子上写的是一个地址,把这个地址抹掉,写上一个新的。

    • 对变量进行复制

      基础数据,复制出来的东西和原来的东西是相互独立的没有任何关系。相当于把一个牌子复制一份,这个复出来的牌子跟原来的牌子一摸一样但没有任何关系。

      引用数据,也是把一个牌子复制出来,但是上面写的是同一个内存地址。而这个时候如果你对其中一个变量进行操作,另外一个变量最后得到的值也会受影响。

  4. 变量当作函数参数使用

    1. 基础数据,相当于复制一份作为函数的局部变量。复制出来的这个和原先的那个他们两个是相互独立的互不影响的。跟变量的复制是完全一样的。

    2. 引用数据,相当于这个参数传递的只是个内存地址。 这时会发生两种情况:第一种情况,对参数上的属性进行修改,那么原先的对象也会受影响。第二种情况,你直接对这个参数进行赋值,当你进行这样的操作时,相当于你在函数内部重新创建一个新的变量,并且断开和原先变量的关系,原先的变量是不会受到影响的。

      所以书中说,参数的传递是值的传递而不是引用的传递。

作用域

作用域就是js当中的一套管理规则。 这套规则是基于函数来创建的。在js中每当我们去运行一个函数的时候都会创建一个新的作用域。而当我们去声明一个函数的时候,这个函数都会在它当前的作用域下声明提前。跟变量的声明提前是一样的。在js中你声明一个变量又声明了一个函数,这两个东西同时会被提前。当他们名字相同时,函数的声明的优先级会大于变量。也就是在js当中会用函数的声明去覆盖变量的声明。

在js的解释器当中,当我们要访问一个值的时候,都会在当前的作用域下查找。如果当前作用域下没有找到这个值的话,那么会顺着作用域链到它外层的作用域下接着查找。这种链式的关系就是靠着一个叫做作用域链的东西来实现的。

数组

  1. 数组创建

    • new操作符

      new Array(3) 可以传入一个数组表示数组的长度。这样创建出来的数组每一项都是一个undefined项数就是你传入的数字。但这样创建的数组是无法使用for each map这种循环的。

      Array.apply(null, {length:4})  //这样创建可以使用 mao for each循环
      
    • 字符字面量

      var colors = ["red", "blue", "green"]

  2. 如何检查数据

    Object.prototype.toString.call(value) == "[object Array]" 
    
  3. 操作方法

    • ES3

      • 对数组有影响的

        push() pop() 往前插,往后插

        shift() unshift() 把前面的推出去, 把后面的推出去

        reverse() sort() 数组反转, 数组排序

      • 对原数组没有影响

      concat()

      slice()

      splice()

      indexOf()

      lastIndexOf()

    • ES5

      • every() filter() map() some()

    sort() 方法默认排序是安装ask码进行排序的。它是可以接受一个排序的函数的。这个排序的函数有两个参数,你要对这两个参数进行比较。这个方法的返回值必须是一个数字,如果不是数字的sort方法会把它转换为数字。然后它会根据这个数字是否大于0来决定他的一个排序顺序。

    splice() 一个参数用于截取,两个参数用于删除,三个参数相当于对这个数组进行修改。返回的是一个新数组,对原数组没有影响。

  4. 伪数组

    看着像是数组,但不能调用数组的方法。一般两个地方:

    • 对html进行操作时抓去的dom节点,他是一个伪数组。
    • 函数当中有个argements对象表示函数的参数它也是个伪数组。

    将伪数组转化为数组:

    Array.prototype.slice.call(伪数组)
    Array.prototype.slice.call(fakeArray)
    
  5. 数组的去重

时间对象

  1. 时间对象的起点

    1970年1月1日0点

  2. 创建时间对象

    new Date //本地时间
    new Date(123) //参数是数字表示的是毫秒数 返回的是从1970年1月1日加上这个毫秒数的时间
    new Date("08/31/2018 10:10:9")//参数是字符串,返回字符串表示的时间。标准格式: '月/日/年 时:分:秒'
    new Date("qqq") // 参数不能被解释为时间的时候返回 “Invalid Date” 
    
  3. 时间对象方法

    设置 set

    获取 get

    UTC时间

    年月日 周 时分秒

    获取年用:getFullYear() getYear()弃用

    getDate() 是日 getDay() 是周 没有set方法

  4. 时间对象的转化毫秒数

    var date = new Date

    1. valueOf()方法 date.valueOf()
    2. getTime()方法 date.getTime()
    3. number()方法 Number(date)
    4. 一元操作符+ +date
    5. Date.parse(a) 效率最慢

    效率比较 valueOf()和 getTime() 》number() 和 一元+ 差别不大

函数对象

  1. 函数的创建

    • 函数声明语句

      声明有名字的函数。

      1. 会发生声明提前,整个函数体都会提到代码最顶端
      2. 函数上有个name属性,就是函数的名字
    • 匿名函数表达式

      声明没有名字的函数,把他赋值给一个变量。

      1. 也会发生声明提前,但提前的只上变量的名字
      2. 这个函数是没有name属性的

      需要在语句块中创建不同的函数,要用匿名函数。如if语句 循环语句等

    • 命名函数表达式

      集合前两种创建方式。var a = function b (){} 他的name属性在函数外不能访问到。递归时可能会用到。

    • ES6箭头函数

      1. 只能创建匿名函数
      2. 没有this 也没有agreement
    • ES6函数生成器

    • 函数构造器

  2. 自执行函数 IIFE

    原理是让函数的声明语句变成函数表达式。

    思路:让函数自执行就不需要定义函数名,只需声明一个匿名函数。函数的执行是在它后面加上() 让它执行。但声明的匿名函数不能直接执行,要把前面的声明函数转化为表达式语句。

    声明语句和表达式语句的区分就看是否是function开头,所以想办法在function前面加上一个其他东西就行。一般是用()括起来,后面再加上() 就成了自执行函数。

    作用:

    1. 避免了全局作用域的污染
    2. 对性能提升,它减少了作用域的查找
    3. 便于代码压缩。
    4. 解决命名冲突问题,通过传参重新命名
    5. 保存闭包的状态
    6. 改变代码的运行顺序 AMD CMD

闭包

js中所有的函数运行完之后都有返回值,如果明显的返回值那返回undefined。一个特殊情:一个函数他的返回值还是一个函数这时就产生一个特殊的现象叫做闭包。

理解闭包需要理解函数的执行的过程。

函数执行起来分成几步:

  1. 创建活动对象也可以理解为创建作用域
  2. 进行预处理,把函数体内所有声明的变量和函数添加到活动对象上
  3. 执行代码
  4. 垃圾回收,删除刚才创建的活动对象。

如果函数执行后返回值还是一个函数,这时外部的活动对象和内部的活动对象就产生了一定关系。在垃圾回收机制去回收活动对象的时候没办法处理这种关系,者就导致活动对象被保存下来了。而在函数体内创建的变量是保存在活动对象上的,所以它也被保存下来了。

闭包的问题:

活动对象没有被回收,占有内存。

闭包的清理:将返回的函数对应的变量设成null

包装对象

基础数据类型在调用方法或者属性的时候产生的临时对象。

只有对象才能调用属性或者方法,基础数据类型能调用属性和方法就是因为包装对象的存在。

null 和 undefined 是没有包装对象的。

  • 数字类型

    常用 toFixed() 接受一个数字参数表示保留几位小数

  • 字符串类型

    slice() substring() substr()

    参数为负数的时候 slice方法会倒着截取。substring() substr() 为作为0处理

    substring() substr() 比较:substr第二个参数表示的是截取的个数。

内置对象

不需要使用new创建的对象。

  • Global

    • 处理数字方法

      isNaN() 是否是NaN

      isFinite() 是否位于最小和最大的数值之间

      parseInt() 转换为数字

      parseFloat() 转换浮点数

    • 处理URL的方法

      编码:

      ​ encodeURI()

      ​ encodeURIComponent()

      解码:

      ​ decodeURI() ​ decodeURIComponent()

      主要区别:是否对一些可以正常在URL中使用,但是它本身是特殊字符的字符进行转码。

      encodeURI() 用于整个URL进行编码,

      encodeURIComponent() 用于URL一部分进行编码。

    • eval()方法

      eval方式是js的解释器,它可以接收一个字符串当作参数,然后把这字符串当作语句来执行。

      作用分类:

      1. 低版本浏览下将字符串形式的json结构转换为对象。

      2. 动态声明大量局部变量。

        在for循环中批量的声明一批函数。这时就需要使用eval()动态的声明一个局部变量,然后把一个匿名函数赋值给它。

      3. 代码压缩

        在控制器中使用把eval()改成 console.log()就打印出源码

  • Math

    Math.random() 返回 0 到 1 的一个随机数

    Math.min()和 Math.max() 获取一组数值中最大和最小的值。

  • JSON

    字符串和JSON之间的互转