JavaScript-2


数组

数组,数据的聚集,在一段连续的空间里存储多个数据,javascript中的数组不同其它语言,数组的长度以及数组中存储的数据类型是可以改变的。

创建数组

创建数组使用 new Array()构造器或者使用 []

 // 构造一个长度为10的数组
 var arr = new Array(10)
 // 构造并初始化数组
 var arr1 = new Array(1, 2, 3, 4, '小明')
 // 创建数组的简便写法
 var arr2 = []
 // 创建并初始化数组
 var arr3 = [1,2,3,4,'99'] ```

> 数组名称代表的是数组本身,如果使用 console.log(arr) 在控制台打印数组名称,则输出整个数组。

### 访问数组元素及赋值

- 数组是一段连续的存储空间,要想访问数组中的数据需要使用**数组名称**加上数组的**下标**。
- 下标从 **0** 开始计数到数组的长度减 1。
- 数组中存储的数据叫作元素。元素可以看作是一个变量,可以存储任意类型的数据。

  ```js
  var arr = [1,2,3,4,'99']
  // 访问数组中第一个元素
  console.log( arr[0] )

数组中所存储的不同的数据类型,但是为以后期数据的管理建议存储相同类型的数据

  • 元素赋值

    var arr = new Array(10)
    arr[0] = 1
    arr[1] = 5
    arr[2] = 9

数组长度

  • 使用 array.length 属性可以获取当前数组的长度

    var arr = [1,2,3,4,'99']
    console.log( arr.length ) //5
  • 在 javascript 中数组的长度是可以变化的。

    var arr = new Array(10)
    console.log( arr.length ) //10
    arr[11] = 123
    console.log( arr.length ) //12
  • array.length 可以直接赋值。

    var arr = new Array(10)
    console.log( arr.length ) //10
    //重新定义数组的长度
    arr.length = 5 
    console.log( arr.length ) //5

    注意:修改 length 的值可能会造成数组中数据的丢失。谨慎使用!

    遍历数组

  • 使用普通for循环遍历

    var array = [2,3,4,5,6,7,8]
    for (var i = 0; i < array.length; i++) {
      console.log(array[i])
    }
  • for/in 遍历

    for (const key in array) {
      console.log(array[key])
    }

    key中迭代出数组的下标

  • for/of 遍历

    for (const value of array) {
      console.log(value)
    }

    value 迭代出数组中元素值

    多维数组

  • 数组中元素如果存储的是具体的数据这类数组称为一维数组。如果数组中元素存储的不是具体数据值而是一个 一维数组 那么我们把这个数组称为 二维数组。同理多维数组就是在一个数组的元素中存储另外一个数组。

  • 创建二维数组:

    // 方式一:
    var array = [[9, 3, 4], [1,3,4]]
    // 方式二:
    var array1 = new Array()
    array1[0] = new Array()
    array1[1] = new Array()
  • 访问二维数组:

    var array = [[9, 3, 4], [1, 3, 4]]
    //  输入二维数组中数据 
    console.log(array[0][0]) // 9
    console.log(array[1][0]) // 1

    二维数组在访问数据使用 array[][],左侧第一个 [] 中填入的是下标为第一维度下标, array[0] 时表示的是第二维度中第一个数组的名称。要想访问第二维度中具体元素值就需要在 第二个 [] 填入第二维度的下标。

  • for 循环遍历二维数组

    var array = [[9, 3, 4], [1, 3, 4]]
    // i 控制第一维度下标
    for(var i=0; i

函数

函数可以将代码进行封装,以达到复用的效果。函数可以接收调用者输入的数据,并且也可以返回数据给调用者。使用 function 关键字定义函数。

  • 定义函数

    // 定义函数
    function fun(){
      console.log('这是一个函数')
    }
    //调用函数
    fun()
    fun()

    带参数的函数

    // ()中定义调用者要传入的参数, 形参。
    function fun(arg1, arg2, arg3) {
    console.log(arg1, arg2, arg3)
    }
    // ()传入参数, 实参。
    fun(1, 2, 3) //控制台打印 1 2 3
    fun(98, 89, 66) //控制台打印 98 89 66
  • 形参:在定义函数时写在()中,形参可以有多个。

  • 实参:调用函数时需要根据形参列表传入对应的参数。

    注意:形参与实参需要一一对应。

函数的返回值

使用 return 关键字可以返回数据给调用者,调用带返回值函数时需要接收返回的数据。

function fun(arg1, arg2) {
    // 返回数据给调用者
    return arg1 + arg2
}
// 接收函数返回值
var result = fun(1,2)

arguments

arguments 是一个对应于传递给函数的参数的类数组对象。

function fun() {
    // arguments对象接收调用函数时传入的参数列表。
    console.log(arguments)
}
fun(12,3,3,5,6,7)

递归函数

  1. 程序直接或间接调用自身的编程技巧称为递归,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

  2. 递归有三个阶段 :边界条件、递归前进段和递归返回段。

  3. 当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

    递归函数中代码尽可能的短小简练。如果函数过大,那么最好分解该函数再写递归函数。

    var res = jieCheng(5)
    // 求阶乘
    function jieCheng(num) {
    if(1==num){
       return 1
    }
    return num * jieCheng(num -1)
    }

    闭包

    闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

    function  out(params) {
    let num = params
    function inner(){
       num++
       return num
    }
    return inner
    }
    let inn =  out(19)
    console.log( inn() ) //20
    console.log( inn() ) //21

    自执行函数

  • 自执行函数也叫作立即调用函数

  • 为了避免解析上的歧义,JS引擎规定,如果function出现在行首,一律解析成语句。立即执行函数需要将函数体放在一个圆括号里

```js
(function(){
//code
}())

(function (){
//code
})()

为了避免错误请在 请在自执行函数结尾加 分号 ;

回调函数

定时器

通过设置定时器可以让代码延迟或循环执行。

  1. setTimeout() 只执行一次的定时器

  2. setInterval() 循环执行的定时器。

    以上两种定时器都会返回一个正整数的定时器ID,这个ID表示定时器的编号。通过这个ID可以删除正在运行中的定时器。

  3. clearTimeout() 删除 setTimeout()对应的定时器,参数为定时器ID

  4. clearInterval() 删除 setInterval()对应的定时器,参数为定时器ID

    需要注意的是setTimeout()和setInterval()共用一个编号池,技术上,clearTimeout()和 clearInterval() 可以互换。但是,为了避免混淆,不要混用取消定时函数。

    对象

    对象是一个复合数据类型,可以根据需要在对象中任意添加成员属性及方法。

    创建/访问对象

  • new Object() 创建对象

    // 创建空对象
    var boy = new Object()
    // 添加对象成员到对象
    boy.name = "小明"
    boy.age = 19
    boy.work = function(){
      console.log('学生')
    }
  • 访问对象中属性和方法,

    • 访问对象中属性的方法需要使用到点运算符 .
    boy.name
    boy.age
    boy.work()
  • JSON 格式创建

    var man = {
      name:'小明',
      age:19,
      job:function(){
          console.log('的工作是学生')
      }
    }

面向对象

  • 工厂方式

    function createPerson(name, sex) {
      //实例化对象
      var person = new Object();
      person.name = name;
      person.age = sex;
      person.doSome = function () {
          console.log(">> "    this.name);
      }
      //返回对象给调用者
      return person;
    }
  • 构造函数方式

    function Person(name, sex) {
      //属性
      this.name = name;
      this.sex = sex;
      //方法
      this.doSome = function () {
          console.log("》》 " + this.name);
      }
    }
    var p1 = new Person('小白', 18);
    • prototype 属性允许您向类中添加属性和方法
      添加原型属性时通过 类名 方式添加 ClassName.prototype.attrName = value
      对象中有属性和 prototype 中属性名称重名,会优先使用对象中的属性。

    [] 数组方式访问对象成员

    var p1 = new Person('小白', 18);
    console.log(p1['name'])

    delete

  • delete 删除对象成员属性

    // 删除对象中成员属性
    delete p1.name

instanceof

  • instanceof 判断对象是否是某个类的实例

    var p1 = new Person('小白', 18);
    
    console.log(p1 instanceof Person) // true
    console.log(p1 instanceof String) //false

    in

  • in 检查对象中是否有该属性或方法

    如果该属性是通过继承得来的也会输出为true

    console.log('toString' in p1)

    .hasOwnProperty()

  • hasOwnProperty()方法判断的是对象是否自身拥有的,该方法会忽略掉那些从原型链上继承到的属性。

    console.log(p1.hasOwnProperty('name'))
    console.log(p1.hasOwnProperty('sex'))

    遍历对象

  • for/in

    • for/in 迭代出对象中属性名
    var p1 = new Person('小白', 18);
    
    for (const key in p1) {
      if (p1.hasOwnProperty(key)) {
          const element = p1[key];
          // 输出属性名
          console.log(key) 
          // 输出属性值
          console.log(element)
    
      }
    }

this

  • 在函数中,this 表示,this 表示全局对象。

  • 在方法中,this 该方法所属的对象。

  • 如果单独使用表示全局对象。

  • 在事件中,this 表示接收事件的元素。

  • setTimeout时this 指向全局对象

  • 使用箭头函数时this可以指向程序的上下文,(就是定义时所在的对象,而不是使用时所在的对象)

    改变this指向

  • func.call(thisArg, arg1, arg2, ...)

  • func.apply(thisArg, [argsArray])

  • func.bind(thisArg[, arg1[, arg2[, ...]]])

    继承

    继承是面向对象三大特征之一:继承的特点就是让子类拥有父类对象的属性和方法,类似人类社会中的儿子具有父亲的特征是一样的。js中要实现两个对象间的父子关系比较麻烦,ES6之前没有继承语法。

  • js实现继承的示例:

    //定义父类
    function Human(name,age){
      this.name = name;
      this.age = age;
      this.run = function(){
          alert('run...');
      }
    }
    Human.prototype.say = function(){
      alert("我的名字叫:"+this.name);
    }
    //定义子类
    function Man(name,age,job){
      // 让父类拥有子类的属性和方法(构造函数伪装)。
      Human.call(this,name,age);
      this.job = job;
    }
    //子类继承父类原型中方法和属性(原型链)。
    Man.prototype = Human.prototype;
    //给子类添加方法
    Man.prototype.work = function(){
      alert(this.job);
    }
    
    /**
    * 实例化
    */
    var man = new Man('小强',22,'工人');
    man.say(); //父类中定义方法
    man.run(); //父类中定义方法
    man.work();//子类中定义方法
    • 在子类的构造函数中调用了 Human.call(this,name,sex), 函数内部时会Human对象设置this.name、this.age属性和this.run()方法。但是在这里使用了call()方法,并且第一个参数传入了this,我们知道call()方法的作用就是更改调用者内部的this指向的。Human.call(this,name,sex)参数中的this所代表是的子类Man对象,所以调用调用Human.call(this,name,sex)就等同于直接在子类中写入与父类中的相同的属性和方法,这个过程就叫作构造函数的伪装。
    • 调用Human.call()可以直接将父类中的属性和方法继承到子类中使用但js原型中的方法并继承过来所以直接Man.prototype = Human.prototype;将原型中的属性和方法也赋值到子类中。
    • 在经过构造函数的伪装和原型链操作后就实现js版的继承了。

常用内置对象

标准的内置对象例如 Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String 以及其他对象.

全局属性

  • Infinity 代表正的无穷大的数值。

  • NaN 指示某个值是不是数字值。

  • undefined 指示未定义的值。

    全局方法

  • eval() 计算 JavaScript 字符串,并把它作为脚本代码来执行。

  • isNaN() 检查某个值是否是数字。

  • Number() 把对象的值转换为数字。

  • parseFloat() 解析一个字符串并返回一个浮点数。

  • parseInt() 解析一个字符串并返回一个整数。

  • String() 把对象的值转换为字符串。

  • escape() 对字符串进行编码。

  • unescape() 对由 escape() 编码的字符串进行解码。

  • encodeURI() 把字符串编码为 URI。

  • decodeURI() 解码某个编码的 URI。

Array 常用属性及方法

  • array.length 设置或返回数组元素的个数。
  • Array.prototype 允许你向数组对象添加属性或方法。
  • array.indexOf() 搜索数组中的元素,并返回它首次出现的位置。
  • array.lastIndexOf()搜索数组中的元素,并返回它最后出现的位置。
  • array.concat() 连接两个或更多的数组,并返回结果。
  • array.copyWithin() 从数组的指定位置拷贝元素到数组的另一个指定位置中。
  • array.reverse() 反转数组的元素顺序。
  • array.every() 检测数值元素的每个元素是否都符合条件。
  • array.fill() 使用一个固定值来填充数组。
  • array.forEach() 数组每个元素都执行一次回调函数。
  • array.push() 向数组的末尾添加一个或更多元素,并返回新的长度。
  • array.pop() 删除数组的最后一个元素并返回删除的元素。
  • array.shift() 删除并返回数组的第一个元素。
  • array.unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
  • array.slice() 选取数组的的一部分,并返回一个新数组。
  • array.sort() 对数组的元素进行排序。
  • array.splice() 从数组中添加或删除元素。
  • array.toString() 把数组转换为字符串,并返回结果。

String 常用属性及方法

  • str.length 返回字符串的长度
  • String.prototype 允许您向对象添加属性和方法
  • str.charAt() 返回在指定位置的字符。
  • str.concat() 连接两个或更多字符串,并返回新的字符串。
  • str.indexOf() 返回某个指定的字符串值在字符串中首次出现的位置。
  • str.lastIndexOf() 返回某个指定的字符串值在字符串中最后出现的位置。
  • str.match() 查找找到一个或多个正则表达式的匹配。
  • str.replace() 在字符串中查找匹配的子串, 并替换与正则表达式匹配的子串。
  • str.search() 查找与正则表达式相匹配的值。
  • str.slice() 提取字符串的片断,并在新的字符串中返回被提取的部分。
  • str.split() 把字符串分割为字符串数组。
  • str.toLowerCase() 把字符串转换为小写。
  • str.toUpperCase() 把字符串转换为大写。
  • str.trim() 去除字符串两边的空白

Boolean

  • boo.prototype 使您有能力向对象添加属性和方法。
  • boo.toString() 把布尔值转换为字符串,并返回结果。

Number

  • Number.MAX_VALUE 可表示的最大的数。
  • Number.MIN_VALUE 可表示的最小的数。
  • Number.NaN 非数字值。
  • num.prototype 允许您可以向对象添加属性和方法。
  • num.toString() 把数字转换为字符串

Math

  • Math.PI 返回圆周率(约等于3.14159)。
  • Math.abs(x) 返回 x 的绝对值。
  • Math.ceil(x) 对数进行上舍入。
  • Math.floor(x) 对 x 进行下舍入。
  • Math.max(x,y,z,...,n) 返回 x,y,z,...,n 中的最高值。
  • Math.min(x,y,z,...,n) 返回 x,y,z,...,n中的最低值。
  • Math.round(x) 四舍五入。
  • Math.random() 返回 0 ~ 1 之间的随机数。。

Date

  • date.getTime() 返回 1970 年 1 月 1 日至今的毫秒数。
  • date.getFullYear() 以四位数字返回年份。
  • date.getMonth()返回月份 (0 ~ 11)。
  • date.getDate() 返回一个月中的某一天 (1 ~ 31)。
  • date.getDay() 返回一周中的某一天 (0 ~ 6)。
  • date.getHours() 返回小时 (0 ~ 23)。
  • date.getMinutes() 返回分钟 (0 ~ 59)。
  • date.getSeconds() 返回秒数 (0 ~ 59)。
  • date.getMilliseconds() 返回毫秒(0 ~ 999)。
  • date.setFullYear() 设置的年份(四位数字)。
  • date.setMonth() 设置月份 (0 ~ 11)。
  • date.setDate() 设置月的某一天 (1 ~ 31)。
  • date.setHours() 设置小时 (0 ~ 23)。
  • date.setMinutes() 设置分钟 (0 ~ 59)。
  • date.setSeconds() 设置秒钟 (0 ~ 59)。
  • date.setMilliseconds() 设置毫秒 (0 ~ 999)。
  • date.setTime() 以毫秒设置 Date 对象。

JSON

  • JSON.stringify() 将一个对象或者数组转换为一个 JSON 字符串。
  • JSON.parse() 将一个JSON 字符串转换为对象或数组。

深拷贝与浅拷贝

  • 深拷贝:数据 B 复制了数据 A 当修改数据 B 时不影响数据 A,叫作深拷贝。
  • 浅拷贝:数据 B 复制了数据 A 当修改数据 B 时数据A也随着一起变化叫作浅拷贝。
    在数组与对象的使用中会经常出现深浅拷贝的问题。