分类: 笔记

  • 数组方法(二)

    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
  • __proto__隐式原型

    是什么

    对象的一个属性

    有什么用

    对象可以通过__proto__访问到构造函数的原型对象

    当一个实例访问属性时, 在自己身上没有找到时, 会自动根据 __proto__ 找到原型对象, 去找原型对象上的属性···(拓展:原型链)

    function Person() {}
    
    let per = new Person()
    
    per.__proto__ === Person.prototype
    

    总结

    对象的__proto__ 等价于 构造函数的prototype属性

  • 原型prototype

    1. 函数本质上也是对象, 所以函数也有属性
    2. 函数有prototype属性:属性值是个对象,叫做原型(对象)
    3. prototype属性的作用:通过构造函数创建出来的实例对象可以直接去访问这个原型对象上的任意属性和方法

    prototype 是函数特有的属性, 只有函数能使用

    是什么

    函数的一个属性,值是一个对象,我们也称为 prototype 的值为原型(对象)

    有什么作用

    共享方法

    使用目的

    解决内存浪费问题

    使用构造函数批量创建对象,多个对象有共同方法时会产生内存浪费问题

    我们可以把重复的一样的方法,添加到原型对象中,这样所有通过该构造函数创建的实例对象,都可以共享此方法。

    //声明函数
    function Person() {}
    
    //给原型对象添加属性和方法
    Person.prototype.gender = '男'
    
    Person.prototype.doSomething = function(){
      console.log('干啥呢')
    }
    
    //创建实例对象
    let first = new Person()
    
    //实例对象调用原型对象中的属性和方法
    first.gender //男
    first.doSomething() //干啥呢
    

    总结

    在原型对象上添加方法, 让所有实例对象共享, 可以保证内存的不浪费

    1. 对象的属性一般写在构造函数中,属性添加给了实例对象自身
    2. 对象的方法写在原型对象中,方便让所有实例对象共享

    constructor属性

    1. 原型对象自带的属性
    2. 该属性值指向了当前的构造函数

    是什么

    原型对象里的一个属性, 指向了构造函数方法

    function Person () {}
    
    let first = new Person()
    
    Person.prototype === Person
    
    first.__proto__.constructor === Person

    实例对象本身没有constructor属性,实例对象可以直接访问原型对象的属性。