博客

  • 对象键值对简化写法

    对象属性名, 属性值同名, 可以简写, 只写一个

    方法可以将 :function 省略不写

    let x = 10;
    let y = 20;
    let obj = {
      x,
      y,
      getPosition() {
        return obj.x
      }
    }
    
  • 解构赋值

    概念: ES6 允许 按照一个模式, 从目标结构 (数组/对象) 中提取值, 赋予给变量, 解构的目的方便取值.
    目的: 优化取值的过程

    数组的解构

    • 完全解构
    • 不完全解构
    let arr = ["春天", "夏天", "秋天", "冬天"]
    
    let [spr, sum, aut, win] = arr // 完全解构
    
    let [spr, , aut] = arr // 不完全解构
    

    对象的解构

    • 基本解构
    • 解构重命名

    解构赋值只要两边解构相同就行,所以对象也是可以解构赋值的。但是需要注意的是对象和数组的解构有一个很大的区别:对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let obj = {
      name: 'liao',
      age: 18,
      desc: '不错'
    }
    
    // 1. 基本解构
    let { name, age, desc } = obj
    
    // 2. 解构重命名 {变量名: 新的变量名}
    let { name: myname, age: myage, desc: mydesc } = obj
    
    // 3. 解构默认值
    let { name, age, desc, girl = '小花' } = obj
    
    // 4. 重命名 + 默认值
    let { name, age, desc, girl: myGirl = '小花' } = obj
    
    使用解构赋值的时候,要注意声明变量的作用域问题
    // 错误的写法
    let x;
    {x} = {x: 1};
     
    // 正确的写法
    let x;
    ({x} = {x: 1});
    

    上面的例子中错误的原因是{x}被认为是一个块级作用域,导致解构失败,我们在使用解构要尽量避免这种大括号直接在行首的情况。

    https://blog.csdn.net/bjhan_csdn/article/details/97389320

  • Map()与Set()

    Map()

    Map是一个带键的数据项的集合,就像object一样。但是它们最大的差别是Map允许任何类型的键。

    方法和属性

    • new Map() —- 创建map
    • map.set(key,value) —- 根据键存储值
    • map.get(key) —- 根据键来返回值,如果map中不存在对应的key,则返回undefined
    • map.has(key) —- 如果key存在则返回true,负责返回false
    • map.delete(key) —- 删除指定键的值
    • map.clear() —- 清空map
    • map.size —- 返回当前元素个数
    let map=new Map() 
    
    map.set('1','se') //根据键储存值 返回 Map(1) {"1" => "se"}
    
    map.get('1') //根据键返回值,如果不存在返回undefind 返回se
    
    map.has('1') //如果key存在返回true
    
    map.delete('1') //删除指定键的值 返回true
    
    map.clear() //清空 返回undefind
    
    map.size //返回当前元素个数 返回0
    

    https://blog.csdn.net/qq_52959651/article/details/110275146

    Set()

    • 是一组key的集合,但不存储value。(或者说key、value相同)
    • 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。Set中,key不能重复。如果出现重复的key,Set会自动过滤。Set没有索引,它的键和值是一个。
    • Set()是一个类似数组解构,但它不是数组。它本身就是一个构造函数。
    • 它最主要的作用是去重。
    • 可以使用Array.from()把它变成一个数组。
    • 通过展开运算符(…)可以把Set集合转换成一个数组。
    let set = new Set([1, 2, 3, 3, 3, 4, 5]),
    array = [...set] 
    console.log(array)  // [1,2,3,4,5]
    

    方法和属性

    • set.add("a")添加一个元素
    • set.delete("a")删除一个元素
    • set.size获取元素的数量
    • set.clear()清除对象中的所有元素。
    • set.has("a")判断s对象中是否有某个元素,返回true或false
    //实例化一个Set对象
    var set =new Set() 
    
    //Set对象通过add方法添加元素
    set.add('3')
    set.add('3') //注意3和'3'是不同的元素
    set.add('apple') 
    console.log(s) //打印结果:Set(3) {3, "3", "apple"}
    
    //使用delete可以删除元素
    set.delete('apple') 
    console.log(s)  //打印结果:Set(2) {3, "3"}
    
    //清除set对象中的所有元素。
    set.clear() 
    

    例:可以用多个add加入元素

    set.add(1).add('哈').add('apple') 
    console.log(s)  //Set(3) {1, "哈", "apple"}
    //Set括号中数字代表set中有几个元素
    

    https://blog.csdn.net/qq_42238554/article/details/86609429

  • 数组方法(二)

    arr.includes()

    用来判断一个数组是否包含一个指定的值

    语法

    arr.includes(item)

    arr.concat()

    用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

    语法

    arr.concat(arr1,arr2)

    Array.from(arr)

    可将伪数组转换为数组

    语法

    Array.from(arr[, mapFn[, thisArg]])

    arr 想要转换成数组的伪数组对象或可迭代对象。

    mapFn如果指定了该参数,新数组中的每个元素会执行该回调函数。

    let arr = [1, 2, 3, 4, 5]
    //把数组里的值都*100
    let newArr = Array.from(arr, (i) => i * 100)
    
    //去重 利用Set构造函数
    let arr1 = [1,1,2,2,3,4,5,6,6,7,7]
    let newArr1 = Array.from(new Set(arr1))
    // [1, 2, 3, 4, 5, 6, 7]
    

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from

    arr.reduce()

    语法

    arr.reduce(callback,[initialValue])

    callback 回调函数(包含四个参数)

    1. previousValue (上一次调用回调返回的值,或者是提供的初始值initialValue
    2. currentValue (数组中当前被处理的元素)
    3. index (当前元素在数组中的索引)
    4. array (调用 reduce 的数组)

    initialValue

    可选

    如果没有提供,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供,则从索引0开始。

    let arr = [1, 2, 3, 4, 5]
    //计算所有元素和
    arr.reduce( (prev, now) => previous + now ) // === 15
    //自己指定初始值initialValue 
    arr.reduce( (prev, now) => previous + now , 100) // === 115
    

    https://blog.csdn.net/qq_43340606/article/details/120765502

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

  • 数组方法

    ES5新增

    对象调用的方法作用返回值
    array.forEach(function(value, index, array){})遍历
    array.map(function(value, index, array){})遍历&返回新数组
    array.filter(function(value, index, array){ return 条件 })过滤&返回新数组
    array.every(function(value, index, array){ return 条件})遍历&判断布尔值
    array.some(function(value, index, array){return 条件})遍历&判断布尔值

    forEach() 遍历

    item是形参,如果是简单类型的形参的修改, 不会影响到原来值

    let arr = [5, 6, 7, 8];
    arr.forEach(function(item){
       item = item + 1;
    })
    //arr没有变化
    
    let arr2 = [
        { name: 'zs', age: 18 },
        { name: 'zs', age: 20 },
    ]
    arr2.forEach(function(item) {
        item.age = item.age + 1
    })
    //{ name: 'zs', age: 19 },
    //{ name: 'zs', age: 21 },
    
    这是以下几个方法共享的数据
    let arr = [
      { name: 'zs', score: 100 },
      { name: 'ls', score: 99 },
      { name: 'li', score: 59 }
    ]
    

    map() 遍历 + 返回

    例:只保留名字,利用map()方法返回新数组来做

    let onlyNameArr = arr.map( item => item.name )
    //onlyNameArr === ['zs','ls','li']
    //如果想原数组只保留name,直接赋值即可arr = arr.map(...)
    //箭头函数只有一个参数,并需要被return时,不需要加return和花括号(自动加了)
    

    filter() 遍历 + 返回

    例:只保留60分以上的同学(包含的信息全都要),利用filter()过滤并返回新数组

    let MoreThan60 = arr.filter( item => item.score >= 60 )
    //需要加return条件,会把符合条件的item加到新数组
    //(并不是只加item.score,这只是用于判断)
    

    every() 遍历 + 判断

    例:比如需要判断所有学生分数是否都高于90

    let isMoreThan90 = arr.every( item => item.score >=90 )
    //isMoreThan90 === false
    

    some() 遍历 + 判断

    只要数组中有一个判断正确,则返回true

    ES6新增

    对象调用的方法作用返回值
    array.find(function(item, index) { return 条件 })遍历 / 查找找到的项 / undefined
    array.findIndex(function(item, index) { return 条件 })遍历 / 查找下标 / -1
    注意

    find() 找第一个符合条件的项, 没找到会返回 undefined,找所有符合条件的还是使用filter()方法

    findIndex() 找第一个符合条件项的下标, 没找到会返回 -1

    复习数组基本的方法

    增加

    push() 增加到最后一个

    shift() 增加到第一个

    splice() 传三个参数( 从哪开始删 , 删几个 , 要添加到数组的元素 )

    第一个参数如果是负数,则为倒数第几个(从-1开始算,不是0,等价于arr.length – n)

    要添加到数组的元素可以有多个item1, item2, 

    删除

    pop() 删除最后一个

    unshift() 删除第一个

    splice() 根据索引指定删除某一个

  • 继承

    什么是继承?

    继承一些需要重复使用的属性和方法

    原型链继承

    语法

    子构造函数.prototype = new 父构造函数()

    注:原型链继承代码必须在创建实例对象之前

    (实例对象在创建的那一刻起,其原型链就定下来了)

    //定义Person构造函数
    function Person() {}
    Person.prototype.sayHi = function () {
        console.log('hi~')
    }
    
    //定义Student构造函数
    function Student() {}
    
    //原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
    Student.prototype = new Person()
    //构造函数指向改回Student 否则会指向Person
    Student.prototype.constructor = Student
    let one = new Student()
    one.sayHi() //继承了Person的sayHi方法

    组合继承( 原型链 + 构造函数 )

    又称伪经典继承

    原型链主要用于实例对象继承方法构造函数用于实现实例对象属性的继承

    不足

    二次调用父类构造函数

    //定义Person构造函数
    function Person(name) {
        this.name = name
    }
    Person.prototype.sayHi = function () {
        console.log('hi~')
    }
    
    //定义Student构造函数
    function Student(name,id) {
      //第二次调用父类构造函数
      Person.call(this,name) // 实现属性的继承
         this.id = id
    }
    
    //原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
    //第一次调用父类构造函数
    Student.prototype = new Person()
    
    let one = new Student('Liao',1)
    one.sayHi() //继承了Person的sayHi方法

    寄生组合继承

    通过借用构造函数来继承属性,通过原型链形式来继承方法,会解决2次调用父类函

    数以及复用率的问题。

    上例中,Student实例上有name了,原型__proto__上不需要再有这些属性,利用Object.create()改造

    Object.create(参数对象), Object.create 会创建一个新对象, 并且这个新对象的__proto__ 会指向传入参数对象

    简单理解

    Object.create()通过括号内的参数对象,创建一个新的对象出来,新对象的__proto__指向参数对象

    Student.prototype = Object.create(Person.prototype)
    //效果等价于(本质还是有区别)
    Student.prototype.__proto__ = Person.prototype
    //定义Person构造函数
    ···
    //定义Student构造函数
    ···
    //利用fn.call()方法,Student已经继承了Person构造函数中的属性
    
    //原型继承
    Student.prototype = Object.create(Person.prototype)

    总结

    Object.create() 以参数的对象, 作为新建对象的__proto__属性的值, 返回新建的对象

    寄生组合式继承 – 简书

    JS 常见的 6 种继承方式_jatej的博客-CSDN博客

  • this显式绑定

    call()、apply()、bind()

    显式绑定:使用call()、apply()、bind()方法将this进行强制绑定(硬绑定)。

    call()的语法和作用与 apply()方法只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

    call()

    使用call()方法会直接调用函数

    function.call(this指向, 参数1, 参数2, ...)

    this指向:可选,用于修改函数this指向,非严格模式下,指定null、undefined会自动指向全局window

    参数1, 参数2, ...

    传递给函数的实参

    apply()

    使用apply()方法会直接调用函数

    function.apply(this指向, [参数1, 参数2, ...])

    this指向:第一个参数用于修改函数this指向

    [参数1, 参数2, ...]:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给function函数。

    Function.prototype.call() – JavaScript | MDN

    Function.prototype.apply() – JavaScript | MDN

    bind()

    使用bind()方法不会不会不会直接调用函数

    返回值

    一个新函数

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

    function.bind(this指向, 参数1, 参数2, ...)
    例:

    bfbind创建出来的函数,bf函数内的this指向己经被强硬指向了bind的参数obj(即对象{name:'liao'}

    function fn() {
        console.log(this)
    }
    
    let obj = {    name:'liao'}
    
    let bf = fn.bind(obj) 
    
    bf() 
    
    //{name: 'liao'}
    一个小坑

    bind方法返回的新函数和原函数长得一样,但是内存地址不一样

    function fn(){}
    
    let fn2 = fn.bind({}) //fn2是新函数,和fn内存地址不一样
    
    console.log(fn == fn2) //false

    总结

    1. call() apply() bind() 都可以替换修改函数this的指向
    2. call()apply()立马调用函数, call()参数需要一个个的传, apply()传参必须是数组形式
    3. bind() 会得到一个新函数, 这个函数绑定死了 this 指向

    Function.prototype.bind() – JavaScript | MDN

  • 环境对象this

    什么是this?

    环境对象指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境

    this的指向

    全局环境

    在一个js文件或<script>标签内,this始终指向window对象

    console.log(this) // 全局环境,即window对象下,this -> window 
    

    局部环境

    严格模式下,函数中的this为undefined

    1.在全局作用域下直接调用函数,this指向window
    function fun() {
     console.log(this)
    }
    fun() // fun() 实际上是window.fun(), 所以this -> window
    
    2.对象函数调用,哪个对象调用就指向哪个对象
    let obj = {
    	name: 'liao',
    	sayHi: function () {
    		console.log('hi~', this.name)
    	},
    }
    let name = 'Li'
    obj.sayHi() //hi~ liao this ---> obj
    
    3.new实例对象,构造函数中的this指向实例对象
    function Person(){
    	this.name = "liao" // 这里的this -> obj对象
    }
    let obj = new Person()
    
    4.事件中的this

    在HTML事件句柄中,this指向了接收事件的HTML元素

    <button onclick="console.log(this)">点我</button>
    this --> button
    

    改变this指向

    call / apply / bind

    总结

    1.在函数调用中,this指向调用它的对象。

    2.在构造函数中,this指向实例化对象。

    3.在事件体中,this指向事件源。

    4.箭头函数中,没有this

    5.其他情况中,this指向window

    JavaScript 的 this 原理 – 阮一峰的网络日志

    JS中的this详解_世平那个张的博客-CSDN博客

  • instanceof与typeof

    typeof

    typeof 用于判断简单数据类型

    例外 null

    typeof null //object
    

    typeof 检测复杂数据类型 结果是object

    例外 function

    typeof function //function
    

    instanceof

    作用

    用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上,存在返回true,不存在返回false

    语法

    实例对象 instanceof 构造函数

    使用instanceof判断是否通过该构造函数创建

    不准确

    let arr = []
    
    arr的原型链

    arr ==> Array.prototype ==> Object.prototype ==> null

    console.log(arr instanceof Array) // true
    console.log(arr instanceof Object) // true
  • 原型链

    是什么

    对象 有 __proto__ 属性,指向原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样形成的一环一环的链式结构,就是原型链。

    老祖宗 function Object()

    function Person() {}
    
    let per = new Person()
    
    //原型链:
    per.__proto__ ==> Person.prototype
    
    Person.prototype.__proto__ ==> Object.prototype
    
    Object.prototype.__proto__ ==> null
    

    属性查找原则

    简单理解:沿着对象的原型链来查找

    1. 先找对象自身,自身有就直接来使用
    2. 对象自身没有,就找原型对象
    3. 如果原型对象也没有,就沿着原型链继续往上找,直到Object.prototype
    4. 如果整个链上都没有,返回undefined