JavaScript基础知识

176 阅读18分钟

JavaScript基础部分

  • JavaScript 基本数据类型
    • String 字符串

    • Number 数字

    • Boolean 布尔值

    • Null 空值

    • Undefined 未定义

    • Object 对象属于一种复合数据类型,可以保存多个不同的数据类型的数据

对象分类

  • 1.内建对象
    • 有ES标准中定义的对象,在任何的ES的实现中都可以使用
    • 比如:Math String Number Boolean Function Object
  • 2.宿主对象
    • 由JS的运行环境提供的对象,比如浏览器提供的对象
    • 比如 BOM与DOM
  • 3.自定义对象
    • 由开发人员自己创建的对象

in 运算符 - 通过该运算符可以检查一个对象中是否含有指定的属性 - 属性 in Object

JS变量

  • JS中的变量都是保存到栈内存中
  • 基本数据类型的值直接在栈内存中储存
  • 值与值之间是独立存在的,修改一个值不会印象其他值

JS对象

  • 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的内存空间而变量保存的是对象的内存地址(对象的引用), 如果两个变量保存的是同一个对象引用当一个通过一个变量修改属性时,另一个也会受影响

对象比较

  • 当比较两个基本数据类型的值时,就是比较值
  • 然而比较两个引用数据类型时,它比较的是对象的内存地址,如果两个对象一模一样,但是地址不同,所以返回 false

创建对象

  • 创建一个对象
    • var Obj = new Object()
  • 使用对象字面量创建一个对象
    • var obj = {}
  • 使用对象字面量,可以在创建对象时,直接指定对象中的属性
    • 语法:{属性名:属性值,属性名:属性值}
    • 属性名和属性值是一组一组的名值结构,名和值之间使用 ':' 连接,多个名值对之间使用 ',' 隔开
    • var obj = {name:'张三'}

函数

  • 函数也是一个对象
  • 函数中可以封装一个功能(代码),在需要时可以执行这些功能(代码)
  • 函数中可以保存一些代码在需要的时候调用
  • 使用typof检查一个函数对象时,会返回function

创建函数(只做了解,实际开发中不推荐使用)

  • 创建一个函数对象
    • 可以将要封装的代码以字符串的形式传递给构造函数
    • 封装到函数中的代码不会立即执行
    • 函数中的代码会在调用的时候执行
    • 调用函数 语法:函数名()
    • var fun = new Function()

使用函数声明来创建一个函数

function 函数名([形参一],[形参二],。。。。,[形参三]){
    语句。。。
}

使用函数表达式来创建一个函数

var 函数名 = function ([形参一],[形参二],。。。。,[形参三]){
    语句。。。
}

立即执行函数

  • 函数对象()
    • 立即执行函数
    • 函数执行完立即被调用,这种函数就叫做立即执行函数
    • 立即执行函数往往只执行一次
(function(){
    alert('我是一个匿名函数~~~')
})();

方法

  • 对象的属性值可以是任何 数据类型 也可以是个 函数
  • 函数也可以是对象的属性
    • 如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法
    • 调用函数就说调用对象方法(method),但是它只是名称上的区别没有其他区别

枚举对象中的属性

var obj = {
    name:'张三',
    age:18,
    gender:'男'
}
  • 枚举对象中的属性使用:for...in...
for(var n in obj){
    console.log("属性名"+n) // 取属性名
    console.log("属性值" + obj[n] ) // 取属性值
}

作用域

  • 作用域指一个变量的作用范围

    • 全局作用域
      • 直接编写在script标签中的代码,都在全局作用域中
      • 全局作用域在页面打开时创建,在页面关闭是销毁
      • 在全局作用域中有一个全局作用域 Window ,它代表是一个浏览器窗口,它由浏览器创建我们可以直接使用
      • 在全局作用域中创建的变量都会作为window对象的属性保存,创建的函数都会作为window的方法保存
    • 变量的声明提前
      • 使用var关键字声明的变量,会在所有的代码执行前被声明(但是不会被赋值),但是如果声明变量时不适用var关键字,则变量不会被声明提前
    • 函数的声明提前
      • 使用函数声明式创建的函数:function 函数名(){},他会在所有代码执行前就被创建,所以我们可以在函数声明前调用
      • 使用函数表达式创建的函数:var fun = function (){},他不会被声明提前,他只是声明的变量fun,并没有赋值,所以没有被声明提前
    • 函数作用域
      • 调用函数,创建函数作用域,函数执行完毕以后,函数作用域销毁
      • 没调用一次函数就会创建一个函数作用域,他们之间是相互独立的
      • 函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问函数作用域中的变量
      • 当在函数作用域中操作一个变量时,他会先在自身作用域查找,如果有就直接用,没有则向上一级作用域寻找,直到找到全局作用域,如果全局作用域都没有怎报错 ReferenceError
      • 在函数中要访问全局变量,可以使用window对象查找
      • 在函数中也有声明提前的特性,使用 var 关键字声明变量,会在函数中所有的代码执行前被声明函数声明也会在函数中所有的代码被执行前声明,
      • 在函数中,不使用 var 声明的变量会变成全局变量
      • 定义形参就相当于在函数作用域中声明了变量
      var a = 10;
      function fun(a){
          console.log(a)
      } 
      fun(); // 输出 undefined
      

this

  • 解析器在调用函数每次都会向内部传递一个隐含的参数,这个隐含的参数就是this
    • this 指向的是一个对象,这个对象我们称为函数的上下文对象
    • 根据函数的调用方式不同,this会指向不同的对象
      • 1、以函数形式调用时 fun() ; this 永远指向 windo
      • 2、以方法形式调用时 obj.sayName() ; this指向的就是调用方法的那个对象(谁调用指向谁)
      • 3、当以构造函数调用时,this指向的就是新创建的那个对象
    function fun (a,b){
        console.log("a = "+a+",b = " + b )
        console.log(this) // 此时输出 [object window]
    }
    fun()
     
     // 创建一个对象
    var obj = {
        name:'孙悟空',
        sayName:fun
    }
    console.log(obj.sayName == fun) /// true
    
    obj.sayName() // [object object] // 此时fun 函数中的this  指向 obj
    
    

工厂方法创建对象

  • 通过该方法可以大批量创建对象

      ```
      function createPerson(name , age , gender){
          var obj = new Object();
          obj.name = name;
          obj.age = age;
          obj.gender = gender;
          obj.sayName = function(){
              alert(this.name)
          }
          return obj;
      }
    
      var obj1 = createPerson('张三',18,'男')
    
    • 构造函数

      • 构造函数和普通函数的区别就是调用的方式不同
      • 普通函数是直接调用,构造函数需要使用 new 关键字来调用
      • 构造函数调用流程:new 之后发生了什么:
        • 1、立刻创建一个新对象
        • 2、将新建的对象设置为函数中的 this,在构造函数中可以使用 this 来引用新建的对象
        • 3、逐行执行函数中的代码
        • 4、将新建的对象作为返回值返回
      function person(){
          this.name = name;
          this.age = age
      }
      
      var per = new person()
      
      console.log(per) // [object object] //此时的 `this` 指向的是对象per
      
    • 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类

      • 我们将通过一个构建函数创建的对象,称为该构造函数的实例
      • 使用 instanceof 可以检查一个对象是否是一个类(构造函数)的实例
        • 语法:对象 instanceof 构造函数
        • 所有对象都是 Object 的后代,任何对象在和 Objectinstanceof检查是返回的都是true
    • 原型对象 :prototype

      • 我们所创建的每一个函数,解析器都会为函数添加一个prototype,这个属性对应着一个对象,这个对象就是我们的原型对象
      • 如果我们的函数只是作为普通函数调用 prototype 没有任何作用
      • 当函数以构造函数方式调用时 new ,他所创建的对象中都会有一个隐式的属性 __proto__,指向该函数的原型对象
      function MyClass(){
      
      }                        // 解析器给 MyClass 函数添加了一个 原型属性 prototype 
      
      var mc = new MyClass() ; // 构造方式调用,因为new的时候会创建对象,这个对象中有一个隐含属性 __proto__,而这个隐含属性指向的就是MyClass函数中的prototype对象
                               //  所以 MyClass.prototype == mc.__proto__   
      
      • 原型对象就相当于一个公共区域,所有同一个函数(类)的实例都可以访问到这个原型对象 ,我们可以将对象中共有的内容,统一设置到原型对象中
      • 当我们访问对象的一个属性或者方法时,他会先在对象自身中查找有没有,如果有则直接使用,如果没有则会原型对象中查找
      • 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使没个对象都具有这个属性跟方法
      function Class(){
      
      }
      Class.prototype.name = "我是原型中的name"
      
      var cl = new Class()
      
      console.log("name" in cl)  // 使用in 检查的是对象中有没有该属性,如果没有也会向上查找
      
      cl.hasOwnProperty('name') // 该方法是检查自身有没有该属性,如果没有则返回 false
      
      
      • 原型对象也是对象,所以他也有原型 __proto__
      • 当我们使用一个对象的属性方法时,会在自身中查找,如果有则使用,如果没有,则在原型中查找
      • 在原型中查找如果有,则使用,如果没有,则在原型的原型(Object)中查找,直到找到Object原型,Object对象的原型没有原型,所以返回NUll,如果在Object中属性还没找到,则返回undefined
    • toSting() 方法修改

      function Person(name,age,gender){
          this.name = name;
          this.age = age;
          this.gender = gender;
      }
      
      var person = new Person('张三',12,'男')
      
      console.log(person) // 此时调试输出的是 [object object] 
      // 如需修改怎么办?
      
      Person.prototype.toString = function(){
          return "[name="+this.name+"agesss="+this.age+"gender="+this.gender+"]"
      }
      
      var person2= new Person('李四',18,'男')
      
      console.log(person2.toString()) // [name="李四",age=18,gender='男']
      

数组(Array)

  • 数组也是一个对象,它和普通对象功能类似、也是用来存储一些值、不同的是普通对象是使用字符串

数组方法

  • push()
    • 该方法可以向数组的末尾添加一个或多个元素,并返回数组长度
    • 可以将要添加的元素作为方法的参数传递,这些元素可以自动添加到数组的末尾
    • 该方法会将新数组的长度作为返回值返回
    var arr = [];
    arr.push('张三','李四')
    console.log(arr) //  ['张三','李四']
    
  • pop()
    • 该方法可以删除数组中最后一个元素
    var arr = ['1','2','3']
    arr.pop()
    console.log(arr) // ['1','2']
    
  • unshift()
    • 该方法是向数组的开头添加一个或多个元素,并返回新的数组长度
    • 向前插入元素以后,其他的元素索引会依次调整
    var arr = [4,5,6]
    arr.unshift(1,2,3)
    console.log(arr) //[1,2,3,4,5,6]
    
  • shift()
    • 该方法可以删除数组的第一个元素,并将删除的元素作为返回值返回
    var arr = [1,2,3,4,5,6]
    var result = arr.shift()
    console.log(result) // 返回  1
    console.log(arr) // [2,3,4,5,6]
    

数组遍历

  • for循环遍历
    var arr = [1,2,3,4,5,6]
    for(var i = 0; i<arr.length;i++){
        console.log(arr[i])
    }
    
  • forEach 遍历 (ie9 以下不支持)
    • forEach() 方法需要一个函数作为参数
    • 像这种函数,由我们创建但是不由我们调用,我们称之为回调函数
    • 数组中有几个元素、函数就会执行几次,每次执行时,浏览器会将遍历的元素以实参的形式传递进来
    • 第一个实参为数组元素,第一个实参为数组的下标,第三个实参为数组对象
    • 索引值还可以传入一个负值,则从后往前计算
    var arr = [1,2,3,4,5,6]
    
    arr.forEach(function(element,length,arr){
    
    })
    
  • slice 从某个已有的数组中返回选定的元素
    • 参数:截取开始的索引;截取结束的索引(可选)
    • 该方法不会影响原数组,而是将截取的封装到新的数组
    • 返回的新数组 包含开始索引,不包含结束索引
    var arr = [1,2,3,4,5,6]
    var newArr = arr.slice(1,2)
    console.log(arr) // 返回的还是原数组
    console.log(newArr) // 截取后的数组 [2]
    
    
  • splice 可以用于删除数组中指定位置的元素
    • 使用splice()会影响原数组,会将指定位置元素从原数组中删除,并将删除的元素作为返回值返回
    • 参数:1、表示开始位置的索引 2、表示删除的数量 第三个及以后 可以传递新元素,并将这些元素插入到开始索引的前面
    var arr = [1,2,3,4,5]
    arr.splice(0,2) 
    console.log(arr) // 返回 [3,4,5]
    
    arr.splice(0,1,1,2,3)
    console.log(arr) // 返回[1,2,3,4,5]
    
    
    // 数组去重
    var arr = [1, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 7]
    
    function arrSplice(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1)
                j--;
            }
        }
    }
    return arr;
    }
    var result = arrSplice(arr)
    console.log(result)
    
  • concat()
    • 可以连接两个或多个数组,并将新的数组返回
    • 该方法不会对原数组产生影响
    var arr1 = [1,2,3]
    var arr2 = [4,5,6]
    
    var result = arr1.concat(arr2)
    console.log(result) // 返回 [1,2,3,4,5,6]
    
    
  • join()
    • 该方法可以将数组转换成字符串
    • 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
    • 在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符,如果不指定,则默认使用 “,” 逗号连接
    var arr =[1,2,3]
    var result = arr.join()
    console.log(result) //  “1,2,3”
    
    
  • reverse()
    • 该方法用来反转数组(前后颠倒)
    • 该方法回修改原来的数组
    var arr = [1,2,3,4,5]
    var result = arr.reverse()
    console.log(result) // [5,4,3,2,1]
    console.log(arr) // [5,4,3,2,1]
    
  • sort()
    • 可以用来对数组进行排序
    • 该方法会修改原数组
    • 默认按照Unicode编码进行排序,所以对数字进行排序时可能会出错
    • 可以在sort()中添加回调函数来指定排序规则,
      • 回调函数中需要定义另个形参,
      • 浏览器将会分别使用数组中的元素作为实参去调用回调函数
      • 使用哪个元素调用不确定,但肯定的是数组中a一定在b前面,
      • 浏览器会根据回调函数的返回值来决定元素的顺序
      • 如果返回一个大于0的值,则两元素交换位置
      • 如果返回一个小于0的值,则两元素位置不变
      • 如果返回一个 0 ,则认为两个元素相等,也不交换
    • 如果需要升序,则 return a-b;
    • 如果需要降序,则 return b-a;
    var arr = [5,4,3,7,8,9,0,1,2,6]
    arr.sort()
    console.log(arr) // [0,1,2,3,4,5,6,7,8,9]
    // 传参
    
    arr.sort(function(a,b){
        return a- b;
    })
    console.log(arr) // [0,1,2,3,4,5,6,7,8,9]
    

函数的方法

  • call()与apply()

    • 这两个方法都是函数对象的方法,需要通过函数对象来调用
    • 当对函数调用call()和apply()都会调用函数执行
    • 在调用call() 和 apply() 可以将一个对象指定为第一个参数 ,此时这个对象是谁函数中的this 就指向的是谁
    function fun (){
        console.log(this.name)
    }
    var obj ={name:"obj"}
    var obj2 = {name:'obj2'}
    fun.call(obj) // 此时输出 obj
    fun.call(obj2) // 此时输出 obj2
    fun() // 此时输出 undefined
    
    • call() 方法可以将实参在对象之后依次传递
    • apply() 方法需要将要传递的实参封装到一个数组中传递
    function fun(a,b){
        console.log(this.name,a,b)
    }
    var obj ={name:"obj"}
    fun.call(obj,1,2) // 输出: “obj”,1,2
    
    fun.apply(obj,1,2) // 输出:“Arguments list has wrong type”
    
    fun.apply(obj,[1,2]) // 输出:“obj,1,2”
    
    

this 再总结

  • 1、以函数形式调用时,this永远指向window
  • 2、以方法的形式调用时,this是调用方法的对象(谁调用指向谁)
  • 3、以构造函数的形式调用时,this是新创建的对象(new的是谁,this指向的是谁)
  • 4、使用call和apply调用时,第一个参数是谁,this指向的就是谁

arguments

  • 在调用函数时,浏览器每次都会传递进两个隐含的参数;
    • 1、函数的上下文对象 this
    • 2、封装实参的对象 arguments
      • arguments 是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度,在调用时,我们所传递的实参都会封装到anguments
    • 它里面有一个属性叫做 callee
      • 这个属性对应一个函数对象,就是当前正在执行的函数的对象
    function fun(a, b) {
    console.log(arguments instanceof Array); // false
    console.log(Array.isArray(arguments)); // false
    console.log(arguments[1]); // true
    console.log(arguments.length);// 2
    console.log(arguments.callee); // [Function:fun]
    }   
    fun('hello', true)
    

Date 对象 日期

  • 在JS中使用Date对象来表示一个时间
    • 创建一个Date()
    • 直接使用构造函数调用创建一个Date对象,则会封装为当前代码执行时间
    var d = new Date()
    console.log(d) // 返回当前时间
    
    • 创建一个指定时间
    var d2 = new Date("12/03/2020 11:30:23")
    console.log(d2) // Thu Dec 03 2020 00:00:00 GMT+0800 (中国标准时间)
    
    • Date.getTime() 获取当前日期对象的时间戳,时间戳:从格林威治1970年1月1日,0时0分0秒起到当前的时间毫秒值(1秒=1000毫秒)
    var d = new Date()
    var time = d.getTime()
    console.log(time)
    
    • Date() 对象还有很多方法,查阅相关手册

Math

  • Math和其他函数不同,它不是一个构造函数,它属于一个工具类不用创建对象,它里面封装了数学运算的相关方法
Math.abs(1) // 返回绝对值
Math.PI //圆周率
Math.ceil // 向上取整 1.1 得 2
Math.floor // 向下取整 1.9 得 1
Math.round // 四舍五入取整
Math.random 
// 生成随机数0-1之间
Math.random()
// 生成0-x 之间
Manth.round(Math.random()*x) 
// 生成 x-y 之间
Manth.round(Math.random() * (y-x) ) + x
  • 相关方法可以查阅相关手册

包装类

  • 基本数据类型
    • String Number Boolean Null Undefined
  • 引用数据类型
    • Object
  • 在JS中为我们提供了三个包装类,通过这三个包装类可以将基本的数据类型转换为对象
    • String()
      • 可以将基本数据类型字符串转换为String对象
    • Number()
      • 可以将基本数据类型数字转换为Number对象
    • Boolean()
      • 可以将基本数据类型布尔值转换为Boolean对象
    • 但是注意 在我们实际开发中不会使用基本数据类型对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预料的结果
    var num = new Number(2)
    var str = new String("hello")
    var bool = new Boolean(true)
    
    console.log(typeof num) // object
    console.log(typeof str) // object
    console.log(typeof bool) // object
    
    
    • 当我们对一些基本数据类型的值调用属性和方法时,浏览器临时使用包装类将其转换为对象,然后再调用方法
    var s = 123 ;
    s.toString();
    console.log(s) ;// 输出 “123”
    console.log(typeof s) // 输出string
    
    

string 方法

  • 在底层字符串是以字符数组的形式保存的“hello” ,是以['h','e','l','l','o']
  • length 可以用来获取字符串长度
  • charAt()
    • 可以返回字符串指定位置字符
    • 根据索引获取指定的字符,从0开始
    str = "hello string"
    var result = str.charAt(0)
    console.log(result) // 输出:h
    
  • charCodeAt()
    • 返回 Unicode编码
  • fromCharCode()
    • 可以根据字符编码获取字符
    // 必须使用string调用
    result = String.fromCharCode(72); // 输出 “H”
    
  • concat()
    • 可以连接两个或多个字符串
    • 作用与 “+” 号一样
  • indexof()
    • 该方法可以检索一个字符串是否包含指定内容
    • 如果该字符串中含有该内容,则会返回其第一次出现的索引
  • 其余方法查找手册

正则表达式

  • 用于定义一些字符串的规则,计算机可以根据正则表达式,来检查一个字符串是否符合规则,获取将字符串中符合规则的内容提取出来
    // 创建正则表达式
        /**
         * 语法:var 变量 = new RegExp("正则表达式","匹配模式")
         * 在构造函数中可以传递一个匹配模式作为第二个参数:i 表示忽略大小写;g 表示全局匹配
         */
        var reg = new RegExp(); // 正则表达式也是一个对象
    
  • 使用字面量来创建正则表达式
    • 使用字面量创建更加方便;使用构造函数创建更加灵活
    • “ | ” 表示或者的意思
    • " [] " 表示的也是或的意思
    • " [a-z] " 表示a----z
    • " [^ ] " 表示除了什么 匹配
    • “ [ 0-9 ] ” 匹配数字
    • “ \ ” 表示转义字符
    // 语法 : var 变量 = /正则表达式/匹配模式
    // 创建一个正则表达式,检查一个字符出中有a或b
    
        var reg = /a|b/;
        reg.test('bacd')    
    
    // 创建一个表达式检查一个字符串中是否有字母
        var reg = /[a-z]/i
    // 检查一个字符中是否含有 abc 或 adc 或 zec
        var reg = /a[bde]c/
    // [^ ]除了什么匹配