JS、ES6面试题(26)

js、es6面试题:

(1)JS的数据类型

  • 基础数据类型StringNumberBooleanUndefinedNull、es6新增两种(SymbolBigInt

  • 引用数据类型: ObjectArrayFunctionDate

  • Number类型包括整数和浮点数(小数),NaN表示Not A Number,检查时返回number。如果使用Number表示的数字超过了最大值,则会返回Infinity(正无穷)

  • String类型数据通常由单引号或双引号包裹,可以双包单或单包双,单引号和双引号不能混用和嵌套,可以使用\进行转义。

  • Boolean只有两个true/false。

  • Undefined 型(未定义)也是只有一个 undefined 值。 undefined 代表了某个变量完全不存在,在内存中完全不存在这个标识符所指向的地址。

  • Null类型(空值型)只有一个 null值,null 值本质上是一个空指针的对象类型。 null 代表了内存中是存在这个变量的,只是我在某些情况下需要把这个变量原本的值给覆盖了,将它设置为一个空。

  • BigInt可以表示任意精度的整数,可以操作超过Number.MAX_SAFE_INTEGER的数字

  • Symbol表示独一无二的值,

引用数据类型和基本数据类型的区别

  • 基本数据类型存储在栈中,操作频繁,内存占用少,大小固定
  • 引用数据类型存储在堆中,内存占用大,大小不固定,根据用户操作动态变化,声明一个引用类型的变量保存引用数据的地址。存在数据共享性问题。

undefined出现的场景

  • 变量被声明了,但是没有被赋值;
  • 调用函数的时候,该传的参数没有传;
  • 访问一个对象中没有的属性;
  • 函数没有返回值时,默认就会返回undefined。

null出现的场景

  • 作为对象原型链的终点出现;
  • 访问一个不存在的dom节点。

(2)判断数据类型的方法

typeof判断基础数据类型(数组、对象、null都会被判断为object)
instanceof判断引用数据类型,不能判断基本数据类型
constructor判断两种数据的类型,弊端(如果声明了一个构造函数,并把原型指向Array,此时将无法判断)
Object.prototype.toString.call()使用 Object 对象的原型方法 toString 来判断数据类型(完美解决上面三种方式存在的问题)

(3)es6新增特性

  • 新增块级作用域let、const关键字
  • 解构赋值、模块化(import,export)、扩展运算符、模版字符串、
  • 箭头函数
  • 新增数据类型和数据结构Symbol、BigInt、Set、Map
  • 新增异步promise、async/await
  • 新增Proxy、Reflect、Generator、Iterator
  • 类和继承
  • 字符串、数组、对象的方法扩展

(4)let、const、var的区别

  • const 定义常量, 不可以重复赋值 ,块级作用域 ,不存在变量提升
  • var 定义变量,可以重复声明 var 全局作用域或函数作用域,有变量提升
  • let 定义变量,不可以重复声明 , 块级作用域 ,不存在变量提升

(5)箭头函数的特点

  • 箭头函数没有自己的this,它的this继承自父级作用域且指向永远不变
  • 箭头函数不能作为构造函数使用
  • 箭头函数没有自己的arguments
  • 箭头函数没有prototype

(6)JS由那几部分组成

  • 由三部分组成时:ECMAScrip(核心)、DOM(文档流对象)、BOM(浏览器对象模型)
  • 由两部分组成时:ECMAScrip(核心)、WEB AIP

(7)构造函数和new

  • 构造函数:用来初始化对象,即为对象成员变量赋初始值,总与new一起使用,可将对象中公共的属性和方法取出来封装到该函数中。
  • 构造函数中的属性和方法称为成员。构造函数中可以再构造函数本身上添加静态成员,也可以在狗仔函数内部的this上添加实例成员。(其中在哪儿添加只能从哪儿访问)
  • new操作具体做了什么
    ①在内存中先创建一个空对象
    ②让this指向该空对象
    ③执行构造函数的代码,给新对象添加属性和方法
    ④返回该新对象(构造函数中不需要return)

(8)原型对象(prototype)、对象原型(_ _ proto_ _)、原型链

  • 原型对象:每一个构造函数都有一个prototype属性(原型对象),指向另一个对象。构造函数拥有prototype对象的所有属性和方法。原型的作用是实现共享方法。

    (注意:一般情况将公共属性定义到构造函数中,公共方法定义到原型对象上。)

  • 对象原型:对象都有_ _ proto_ _属性指向构造函数的prototype原型对象,故我们可以使用prototype原型对象上的属性和方法。(原型对象和对象原型是等价的)

  • 原型链:一个实例对象在调用属性和方法时,会一次从实例对象本身到构造函数,再到原型的原型上去查找,直到找到Object为止,Object的原型是null。这种链式查找的过程称为原型链。

(9)作用域、作用域链

  • 作用域:指程序定义变量的区域,他决定了当前代码对变量的访问权限。

  • JS有三种作用域分别为全局作用域、函数作用域、块级作用域

    • 全局作用域:在代码最外层作用域一直存在,在代码任何地方都能访问。
    • 函数作用域:定义在函数中的变量,函数每次被调用都拥有一个不同的作用域。
    • 块级作用域:在es6中新增了let、const命令,可以用来创建块级作用域,只在其代码作用域中有效。
  • 作用域链:当代码内部访问变量时,会先查找本地作用域,如果目标变量找到即返回,否则去父级作用域中查找,一直找到全局作用域,这种作用域嵌套机制就是作用域链。

(10)闭包

  • 闭包:函数嵌套函数,内部函数可以访问外部函数的变量和参数,内部函数作为外部函数的返回值,再将函数赋值给一个变量保存下来就会产生闭包。
  • 特点: ①可以重复利用变量,该变量不会污染全局②该变量会一直保存在内存中,不会被垃圾回收机制回收
  • 缺点:闭包过多会消耗内存,页面性能下降,造成内存泄漏
  • 使用场景:防抖、节流、函数嵌套、函数避免全局污染

(11)防抖和节流

  • 防抖:单位之间内,频繁触发事件,只执行最后一次。(重新开始)
  • 应用场景:①搜索框搜索输入②文本编辑器实时保存
  • 代码(使用定时器)
let timerId = null
document.querySelector('.pt').onkeyup=function (){
    if(timerId!==null){
        clearTimeOut(timerId)
    }
    timerId=setTimeout(()=>{
        console.log("我是防抖")
    },1000)
}
  • 节流:单位之间内,频繁触发事件,只执行一次函数。(不会重新开始)

  • 应用场景:高频事件(快速点击、鼠标滑动、resize、scroll)、下拉加载、视频播放记录时间

  • 代码

    let timerId = null
    document.querySelector('.pt').onmouseover=function (){
        if(timerId!==null){
            return
        }
        timerId=setTimeout(()=>{
            console.log("我是节流")
            timerId=null
        },1000)
    }
    

(12)js中的堆内存与栈内存

栈内存

  • 存储基本数据类型的值和引用类型的变量的引用。
  • 按值访问
  • 大小固定,按照"后进先出"的顺序进行操作。
  • 有系统自动分配内存空间
  • 空间小,运行效率高
  • 自动分配和释放,变量作用域结束时自动销毁。

堆内存

  • 存储引用类型的对象,如数组和对象。
  • 通过引用地址查找对象。
  • 大小不固定,无需存储。动态分配和释放。
  • 有代码进行指定分配
  • 空间大,运行效率相对校低
  • 需要手动管理对象的创建和销毁。

(13)JS垃圾回收机制

垃圾回收机制:自动管理内存机制,用于清除不再使用的对象。

策略:引用计数法、标记清除法、分代回收

标记清除(Mark and Sweep):(常用)

  • 当变量进入执行环境时,垃圾回收器会标记这些变量为"存活"。
  • 通过根变量(如全局变量)开始遍历内存中的对象,标记所有从根变量可以访问到的对象为"存活"。
  • 未被标记的对象即为"垃圾",将被回收并释放内存空间。

引用计数(Reference Counting):(较少使用)

  • 当一个对象被引用一次则引用数值+1,被取消引用一次则引用数-1
  • 当引用计数为0时,说明该对象不再被引用,即为"垃圾",将被回收。
  • 该算法存在循环引用的问题,即使对象不再被使用,但互相引用的对象的引用计数仍不为0,导致内存无法释放。

分代回收(Generational Collection):(改进算法)

  • 根据对象的存活时间将内存分为不同的代(Generation)。
  • 大部分新创建的对象被认为是临时对象,存活时间较短,分配在较新的代中。
  • 经过多次垃圾回收仍然存活的对象会逐渐晋升到较老的代中,减少频繁回收的成本。
  • 较老的代中的对象会较少被扫描,提高垃圾回收的效率。

(14)内存泄漏

内存泄漏:不再使用的对象保留在内存中,导致内存占用不断增加而无法释放。

内存泄漏因素:

  • 闭包(手动清除,局部变量设置为null)
  • 定时器和回调函数未清除(解决:在定时器完成工作时手动清除)
  • 未清理DOM元素的引用(解决:手动清除存储DOM的变量为null)
  • 全局变量(解决:在函数内使用严格模式"use strict",禁止this关键字指向全局变量)

(15)js事件循环中的宏任务和微任务

  • 宏任务:setTimeout、setInterval、DOM事件、AJAX事件

  • 微任务:Pomise、async/await

  • 微任务 > DOM渲染 > 宏任务

(16)同步和异步的理解

  • 同步:只有前一个任务执行完毕,才能执行后一个任务。
  • 异步:当同步任务执行到某个 WebAPI 时,就会触发异步操作,此时浏览器会单独开线程去处理 这些异步任务。

(17)Promise

Promise:解决毁掉地域问题

在这里插入图片描述

  • 实例方法: then、catch、finally 三种,

  • 静态方法: all、race、allSettled、any、resolve、reject 六种

    • Promise.prototype.then()(核心)

      语法:promise.then(onFulfilled, onRejected)

      当 handler 返回一个正常值的时候,这个值会传递给 Promise 对象的 onFulfilled 方法。定义的 handler 中产生异常的时候,这个值则会传递给 Promise 对象的 onRejected 方法。

    • Promise.prototype.catch()

      Promise 对象的 catch 方法来捕获异步操作过程中 出现的任何异常。

      不建议在 Promise 内部使用 throw 来触发异常,而是使用 reject(new Error()) 的方式来做,因为 throw 的方式并没有改变 Pronise 的状态

    • Promise.prototype.finally()

      不管是 resolve 还是 reject 都会调用 finally ,可以在这里关闭使用的对象

    • Promise.all()

      参数传递 promise数组中所有的 Promise 对象都变为resolve的时候,该方法才会返回。

      如果参数中的任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的 新的 Promise 对象。

      由于参数数组中的每个元素都是由 Promise.resolve 包装(wrap)的,所以Promise.all 可以处理不同 类型的 Promise 对象。

      如果全部成功返回一个顺序排列的数组,如果失败则实例第一个态变为rejected的拒因

      当参数为空时同步的返回一个已完成状态的promise, 终值值一个空数组

    • Promise.race()

      返回最快完成那一个 Promise 实例,参数 promise 数组中的任何一个 Promise 对象如果变为 resolve 或者 reject 的话, 该函数就会返回, 并使用这个 Promise 对象的值进行 resolve 或者 reject。

      当参数为空返回一个pending状态的promise

    • Promise.allSettled()

      返回所有promise实例执行的数组,无论是执行 resolve 回调还是 reject 回调的状态。

      返回一个顺序同promise的输入顺序一致的数组

      当参数为空时同步的返回一个已完成状态的promise, 终值值一个空数组

    • Promise.any()

      返回任意一个最快执行 resolve 回调的 Promise 实例。

      当参数为空同步的返回一个失败状态的promise,拒因是一个AggregateError对象

    • Promise.resolve()

      返回值也是一个 Promise 对象,所以可以接着对其返回值进行 .then 调用。

      Promise.resolve 是 new Promise() 的快捷方式。

    • Promise.reject()

      Promise.reject(error) 是和 Promise.resolve(value) 类似的静态方法,是 new Promise() 方法的快捷方 式。

给出ajax,写出promise

function getPromise(url) {
    return new Promise((resolve, reject) => {
        ajax(url, res => {
        	resolve(res)
        }, err => {
        	reject(err)
        })
    })
}

手写promise:

  // promise
    // 状态会多次用于判断,所以建议用常量保存
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class Promise{
        constructor(handler){
            // 构造函数需要参数,参数必须是一个函数类型 这里面我们叫做handler,这儿会对handler类型进行验证,如果不是函数类型会抛出类型异常
            if(typeof handler !== 'function'){
                throw new TypeError(`Promise构造函数的参数${handler}不是一个函数`)
            }
            this.state = PENDING // 用来存储promise的状态 初始化状态为pending
            this.reason = undefined // 拒因
            this.value = undefined // 终值
            // resolve,reject方法里面会用到实例的this,在调用的时候需要改变this的指向
            handler(this.resolve.bind(this), this.reject.bind(this))
        }
        resolve(value){
            // 该方法只能在promise状态为pending的时候调用,如果promise已经有了状态,则不允许调用
            if(this.state !== PENDING) return
            // 调用方法promise的状态变为fulfilled
            this.state = FULFILLED
            // 调用该方法会得到一个终值value
            this.value = value
        }
        reject(reason){
            // 该方法只能在promise状态为pending的时候调用,如果promise已经有了状态,则不允许调用
            if(this.state !== PENDING) return
            // 调用方法promise的状态变为rejected 
            this.state = REJECTED
            // 调用该方法会得到一个拒因reason
            this.reason = reason
        }
    } 

(18)Async/Await

语法

async function f(){
    const a=await fetch('http://...');
}

陷阱

①当有两个异步时,使用all组合更高效

async function f(){
    const promiseA=await fetch('http://...');
    const promiseB=await fetch('http://...');
    
    const[a,b]=await Promise.all([promiseA,promiseB]);
}

②循环中执行异步操作时,可使用传统的for循环,可以用for await 使循环中的异步并发执行。

async function f(){
    const promises=[
        someAsyncOperation(),
        someAsyncOperation(),
        someAsyncOperation(),
    ]
    
    for await(let res of promises){
        //操作
    }
}

③await必须搭配async一起使用

(19)手写ajax

function ajax(url,method,callback) {
    let xmlhttp
    if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera,
        Safari
        xmlhttp = new XMLHttpRequest()
    } else { // code for IE6, IE5
    	xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
    // 发送请求
    xmlhttp.open(method, url, true)
    xmlhttp.send()
    // 服务端响应
    xmlhttp.onreadystatechange = function() {
    	if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            // console.log(xmlhttp.responseText)
            let obj = JSON.parse(xmlhttp.responseText)
            callback(obj)
    	}
    }
}

promise和async/await的区别

  • 都是处理异步请求方式,都是非阻塞性的

  • promise通过then、catch处理和捕获异常、链式调用代码重叠不好维护,async/await通过try/catch捕获异常

  • async/await遇到await会等待返回结果在执行后续操作、promise.then()可能会出现请求还未返回就进行后续操作的情况。

(20)隐式转换

  • 加(+)
    • 当一侧为 String 类型,被识别为字符串拼接,并会优先将另一侧转换为字符串类型。
    • 当一侧为 Number 类型,另一侧为原始类型,则将原始类型转换为 Number 类型。
    • 当一侧为 Number 类型,另一侧为引用类型,将引用类型和 Number 类型转换成字符串后拼接。
  • 减、乘、除
    • 在对非 Number 类型运用数学运算符(-*/)时,会先将非 Number 类型转换为 Number 类型再进行计算。
  • 单个变量
    • 如果只有单个变量,会先将变量转换为 Boolean 值。只有 nullundefined''NaN0false 这几个会被转换为 false,其他的情况都是 true,比如 {} , []
  • 逻辑运算符==
    • NaN 和任何类型比较永远返回 false(包括它本身)。
    • Boolean 和其他任何类型比较,Boolean 首先被转换为 Number 类型。
    • StringNumber 比较,先将 String 类型转换为 Number 类型。
    • null == undefined 比较结果是 true,除此之外,nullundefined 和其他任何类型的比较都为 false
    • 原始类型引用类型 比较时,引用类型调用对象的 valueOftoString 方法,将参数转换为原始类型。

(21)JS中的this

优先级:new > 显示 > 隐式 > 默认

this绑定规则:(在运行时绑定,取决于函数的调用位置)

  • 默认绑定

    • 当函数不使用任何修饰符如call、apply、new等时,默认绑定全局
    • 当使用严格模式时,不能绑定到全局作用域。
  • 隐式绑定

    • 调用位置是否有上下文对象,如果有则指向该对象
    • 对象属性引用链中只有最后一层灰影响调用位置
    • 存在隐式缺失
  • 显示绑定

    • 通过callapplybind绑定

    • ①第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window

    • ②call是参数列表,apply是数组,call和apply是一次性传入参数

      tFn.call(test(obj,args1,args2,args3))
      tFn.apply(test(obj,[args1,args2,args3]))
      
    • ③bind是参数列表,但可以分为多次传入参数

      function bind(fn,obj){
      	return function(){
      		return fn.apply(obj,arguments);
      	}
      }
      
    • ④bind是返回绑定this之后的函数,apply、call 则是立即执行

    • 如果传入的值四飞引用类型的值,那么该值将自动被转化成它的对象形式,例如new String()。

  • new绑定

    • 创建一个空对象
    • 将对象与原型进行链接
    • 将新对象绑定到函数调用的this
    • 如果函数没有返回其他对象,则new表达式中的函数将返回该对象
  • 箭头函数中的this向外层一级一级查找作用域中的this

(22)JS中ES6数据结构Map 、Set 、WeakMap 、 WeakSet

Set

  • Set是一种存储唯一值的集合,无重复值,值可以是任意数据类型。
  • Array.from方法可以将 Set 结构转为数组
  • Set 结构的实属性:
    • Set.prototype.constructor:构造函数,默认就是Set函数。
    • Set.prototype.size:返回Set实例的成员总数。
  • Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)
  • Set的操作方法
    • Set.prototype.add(value):添加某个值,返回 Set 结构本身。
    • Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    • Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
    • Set.prototype.clear():清除所有成员,没有返回值。
  • Set的遍历方法
    • Set.prototype.keys():返回键名的遍历器
    • Set.prototype.values():返回键值的遍历器
    • Set.prototype.entries():返回键值对的遍历器
    • Set.prototype.forEach():使用回调函数遍历每个成员
    • for...of:可以直接遍历每个成员

WeakSet

  • WeakSet是一种特殊的Set,其中的值只能是对象。
  • WeakSet 没有size属性,也没有迭代器,没有办法遍历它的成员。
  • WeakSet 中的对象都是弱引用,不会阻止对象被垃圾回收。
  • WeakSet 的方法
    • WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
    • WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
    • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

Map

  • Map是一种键值对的集合,其中每个键只能出现一次。键可以是任意数据类型(包括原始类型和对象),值也可以是任意数据类型。
  • Map实例属性:
    • Map.prototype.size:返回Map实例的成员总数。
  • Map操作方法
    • Map.prototype.set(key, value)set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。可以采用链式写法
    • Map.prototype.get(key)get方法读取key对应的键值,如果找不到key,返回undefined
    • Map.prototype.has(key)has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
    • Map.prototype.delete(key)delete方法删除某个键,返回布尔类型。
    • Map.prototype.clear()clear方法清除所有成员,没有返回值。
  • Map遍历方法(返回的顺序都与插入顺序一致)
    • Map.prototype.keys():返回键名的遍历器。
    • Map.prototype.values():返回键值的遍历器。
    • Map.prototype.entries():返回所有成员的遍历器。
    • Map.prototype.forEach():遍历 Map 的所有成员。
    • for...of: 可以直接遍历每个成员

WeakMap

  • WeakMap只接受对象作为键名(null除外),值可以是任意类型。
  • WeakMap中的键是弱引用,不会阻止对象被垃圾回收
  • WeakMap没有size属性,无法遍历

Set和Map区别

  • Set是一种无序且不重复的集合,可以用来存储任何类型的值。Map是一种键值对的集合,可以用来存储任何类型的键和值。
  • Map可以通过get方法获取值,而set不能(它只有值);
  • 都能通过迭代器进行for…of遍历;
  • Set常做数组去重,Map可做数据存储。

(23)深拷贝浅拷贝

浅拷贝:浅拷贝是对象共用的一个内存地址,对象的变化相互印象。

深拷贝:深拷贝是将对象放到新的内存中,两个对象的改变不会相互影响。

实现浅拷贝的方法

  • Object.assign()

    • Object.assign(target, …sources)
    • 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对 象。
    • 不会拷贝对象继承、不可枚举、属性的数据/访问器属性,可以拷贝Symbol类型。
  • 遍历

    function deepClone(source) {
      if (!source || typeof source !== 'object') {
        return source;
      }
      const targetObj = source.constructor === Array ? [] : {};
      for (const keys in source) {
        if (source.hasOwnProperty(keys)) {
            targetObj[keys] = source[keys];
        }
      }
      return targetObj;
    }
    
  • 使用拓展运算符实现的复制([…])

实现深拷贝的方法

  • JSON.parse(JSON.stringfy()) 把对象转成字符串,返回新生成的字符串,然后在通过JSON.parse转成JSON格式,在赋给新的对象

    弊端:具有循环引用的对象时,报错;当值为函数、undefined、或symbol时,无法拷贝。

  • 递归拷贝:在浅拷贝的遍历方法上多加一层判断,进而对所有层级的元素进行遍历赋值

    function deepClone(source) {
      if (!source || typeof source !== 'object') {
        return source;
      }
      const targetObj = source.constructor === Array ? [] : {};
      for (const keys in source) {
        if (source.hasOwnProperty(keys)) {
          if (source[keys] && typeof source[keys] === 'object') {
            targetObj[keys] = source[keys].constructor === Array ? [] : {};
            targetObj[keys] = deepClone(source[keys]);
          } else {
            targetObj[keys] = source[keys];
          }
        }
      }
      return targetObj;
    }
    

(24)操作数组的方法有哪些

map遍历数组,返回回调返回值组成的新数组
forEach无法break,可以用try/catch中throw new Error来停止
filter过滤
some有一项返回true,则整体为`true
every有一项返回false,则整体为`false
join通过指定连接符生成字符串
push / pop末尾推入和弹出,改变原数组。push 返回数组长度, pop 返回原数组最后一项
unshift / shift头部推入和弹出,改变原数组,unshift 返回数组长度,shift 返回原数组第一项 ;
sort(fn) / reverse排序与反转,改变原数组
concat连接数组,不影响原数组, 浅拷贝
slice(start, end)返回截断后的新数组,不改变原数组
splice(start, number, value…)返回删除元素组成的数组,value 为插入项,改变原数组
indexOf / lastIndexOf(value, fromIndex)查找数组项,返回对应的下标
reduce / reduceRight(fn(prev, cur), defaultPrev)两两执行,prev 为上次化简函数的return值,cur 为当前值 当传入 defaultPrev 时,从第一项开始; 当未传入时,则为第二项

(25)JS中的常用循环及区别

  • for循环(常见基础)

    • 可以及时break出循环

      for (初始化表达式; 条件表达式; 更新表达式) { // 循环体 }
      
  • for…in 循环

    • 用于遍历对象的属性(如果遍历数组,得到的是数组的索引)

      for (let 变量 in 对象) { // 循环体 }
      
  • for…of 循环

    • es6新增用于遍历数组等可迭代对象中的所有元素,如Set,Map,String,Array

      for (let 变量 of 可迭代对象) { // 循环体 }
      
  • forEach

    • 与map相同用于遍历数组的每个元素。forEach方法不返回值,只用来操作数据,且循环中途是无法停止的,总是会将所有成员遍历完

      array.forEach((currentValue, index, array)=>{ // 循环体 });
      
  • map

    • map方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。循环中途是无法停止的,总是会将所有成员遍历完。

    • map方法接受一个函数作为参数

    • map方法向它传入三个参数:当前成员、当前位置和数组本身。

      array.map((currentValue, index, array)=>{ // 循环体 });
      
  • filter

    • 用于遍历数组并返回一个包含符合条件元素的新数组。

      const newArray = array.filter(function(currentValue, index, arr) { 
          // return true or false 
      });
      

(26)JS的继承

  • 原型链继承

    • 让一个构造函数的原型是另一个类型的实例,则该构造函数new出来的实例就具有该实例的属性

    • 子类的原型等于父类的实例

      function Parent() {
         this.isShow = true
         this.info = {
             name: "tom",
             age: 18,
         };
      }
      
      function Child() {};
      Child.prototype = new Parent();
      

      缺点:对象实例共享所有继承的属性和方法,无法向父类构造函数传参

  • 借助构造函数继承

    • 在子类型的构造函数的内部调用父类的构造函数,通过 apply,call 方法将父类构造函数绑定在子类对象上。

      function Parent(gender) {
        this.info = {
          name: "tom",
          age: 19,
          gender: gender
        }
      }
       
      function Child(gender) {
          Parent.call(this, gender)
      }
      

      优点:解决原型链继承无法传参问题

      缺点:方法都在构造函数中定义,故无法实现函数复用,父类原型中定义的方法子类不可见,只能使用构造函数模式

  • 组合式继承(经典)

    • 原型链借用构造函数 的组合。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

      function Person(gender) {
        this.info = {
          name: "tom",
          age: 19,
          gender: gender
        }
          
      function Child(gender) {
        Person.call(this, gender) // 使用构造函数法传递参数
      }
       
      Child.prototype = new Person()
      
      
  • Class类继承(es6新增)

    • Class通过extends关键字实现继承,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

      Class Person{
      	constructor(ele){
              this.ele=ele
          }
          getEle(){
              return this.ele;
          }
      }
          
      Class Child extends Person{
        constructor(name)  {
              this.name=name
          }
          
      }
      

      缺点:并非所有浏览器都支持Class

声明:以上内容来自书籍查阅、网络博客教学视频等内容。如有侵权请私信。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又又爱拍照

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值