前端复习------js篇(中)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 前端复习------js篇

mutationobserver


Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。


概念上,它很接近事件,可以理解为 DOM 发生变动就会触发 Mutation Observer 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说,DOM 的变动立刻会触发相应的事件;Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。


Mutation Observer 有以下特点。


  • 它等待所有脚本任务完成后,才会运行(即异步触发方式)。


  • 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。


  • 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。


MutationObserver构造函数


通过new创建一个观察者对象,改构造函数需要传递一个回调函数。


var observer = new MutationObserver(callback);


该回调函数接收两个参数,参一:变动dom的数组,参二:观察者实例。


let callback = function (mutations, self) {
}


实例方法:


1.observe(变动元素,观察选项)


let odiv = document.getElementById('#div');
let  options = {
  'childList': true,
  'attributes':true
} ;
observer.observe(odiv, options);


以下是 options对象的各属性及其描述:


属性 类型 描述
childList Boolean 是否观察子节点的变动
attributes Boolean 是否观察属性的变动
characterData Boolean 是否节点内容或节点文本的变动
subtree Boolean 是否观察所有后代节点的变动
attributeOldValue Boolean 观察 attributes 变动时,是否记录变动前的属性值
characterDataOldValue Boolean 观察 characterData 变动时,是否记录变动前的属性值
attributeFilter Array 表示需要观察的特定属性(比如['class','src']),不在此数组中的属性变化时将被忽略


注意:


  1. 对一个节点添加观察器,就像使用addEventListener方法一样,多次添加同一个观察器是无效的,回调函数依然只会触发一次。但是,如果指定不同的options对象,就会被当作两个不同的观察器。


  1. 监听选项中必须指定 childList、attributes 和 characterData 中的一种或多种。


Failed to execute 'observe' on 'MutationObserver': The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.


2.disconnect()


该方法是停止监听dom变化的。


observer.disconnect();


3.takeRecords()


用来清除变动记录,即不再处理未处理的变动。该方法返回变动记录的数组。


// 保存所有没有被观察器处理的变动
observer.takeRecords();


MutationRecord 对象


即每次dom发生变化所产生的状态值。


属性 类型 描述
type String 根据变动类型,值为 attributes, characterData 或 childList
target Node 发生变动的DOM节点
addedNodes NodeList 被添加的节点,或者为 null
removedNodes NodeList 被删除的节点,或者为 null
previousSibling Node 被添加或被删除的节点的前一个兄弟节点,或者为 null
nextSibling Node 被添加或被删除的节点的后一个兄弟节点,或者为 null
attributeName String 发生变更的属性的本地名称,或者为 null
attributeNamespace String 发生变更的属性的命名空间,或者为 null
oldValue String 如果 type 为 attributes,则返回该属性变化之前的属性值;如果 type 为 characterData,则返回该节点变化之前的文本数据;如果 type为 childList,则返回 null


参考 JavaScript 标准参考教程(alpha))DOM模型Mutation Observer API


优化js中的逻辑判断


普通的写法:if-else if-else, switch-case


一元判断:Map, 对象


Map: [[条件, 逻辑参数],[条件, 逻辑参数],...]


对象: {条件:逻辑参数}


/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  if(status == 1){
    sendLog('processing')
    jumpTo('IndexPage')
  }else if(status == 2){
    sendLog('fail')
    jumpTo('FailPage')
  }else if(status == 3){
    sendLog('fail')
    jumpTo('FailPage')
  }else if(status == 4){
    sendLog('success')
    jumpTo('SuccessPage')
  }else if(status == 5){
    sendLog('cancel')
    jumpTo('CancelPage')
  }else {
    sendLog('other')
    jumpTo('Index')
  }
}


const actions = {
  '1': ['processing','IndexPage'],
  '2': ['fail','FailPage'],
  '3': ['fail','FailPage'],
  '4': ['success','SuccessPage'],
  '5': ['cancel','CancelPage'],
  'default': ['other','Index'],
}
/**
 * 按钮点击事件
 * @param {number} status 活动状态:1开团进行中 2开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions[status] || actions['default'],
      logName = action[0],
      pageName = action[1]
  sendLog(logName)
  jumpTo(pageName)
}


const actions = new Map([  [1, ['processing','IndexPage']],
  [2, ['fail','FailPage']],
  [3, ['fail','FailPage']],
  [4, ['success','SuccessPage']],
  [5, ['cancel','CancelPage']],
  ['default', ['other','Index']]
])
/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions.get(status) || actions.get('default')
  sendLog(action[0])
  jumpTo(action[1])
}


多层判断:Map


Map: [[条件,() => {}], [条件,() => {}], ....]


  • 条件可以是多个条件合并的字符串


  • 条件可以是一个对象


  • 条件可以是正则,为了匹配更多相同逻辑不同条件的处理


  • .....


对象:{条件:() => {}, 条件:() => {}, ...}


  • 条件可以是多个条件合并的字符串


/**
 * 按钮点击事件
 * @param {number} status 活动状态:1开团进行中 2开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 * @param {string} identity 身份标识:guest客态 master主态
 */
const onButtonClick = (status,identity)=>{
  if(identity == 'guest'){
    if(status == 1){
      //do sth
    }else if(status == 2){
      //do sth
    }else if(status == 3){
      //do sth
    }else if(status == 4){
      //do sth
    }else if(status == 5){
      //do sth
    }else {
      //do sth
    }
  }else if(identity == 'master') {
    if(status == 1){
      //do sth
    }else if(status == 2){
      //do sth
    }else if(status == 3){
      //do sth
    }else if(status == 4){
      //do sth
    }else if(status == 5){
      //do sth
    }else {
      //do sth
    }
  }
}


const actions = new Map([
  ['guest_1', ()=>{/*do sth*/}],
  ['guest_2', ()=>{/*do sth*/}],
  ['guest_3', ()=>{/*do sth*/}],
  ['guest_4', ()=>{/*do sth*/}],
  ['guest_5', ()=>{/*do sth*/}],
  ['master_1', ()=>{/*do sth*/}],
  ['master_2', ()=>{/*do sth*/}],
  ['master_3', ()=>{/*do sth*/}],
  ['master_4', ()=>{/*do sth*/}],
  ['master_5', ()=>{/*do sth*/}],
  ['default', ()=>{/*do sth*/}],
])
/**
 * 按钮点击事件
 * @param {string} identity 身份标识:guest客态 master主态
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 */
const onButtonClick = (identity,status)=>{
  let action = actions.get(`${identity}_${status}`) || actions.get('default')
  action.call(this)
}


const actions = {
  'guest_1':()=>{/*do sth*/},
  'guest_2':()=>{/*do sth*/},
  //....
}
const onButtonClick = (identity,status)=>{
  let action = actions[`${identity}_${status}`] || actions['default']
  action.call(this)
}


const actions = new Map([
  [{identity:'guest',status:1},()=>{/*do sth*/}],
  [{identity:'guest',status:2},()=>{/*do sth*/}],
  //...
])
const onButtonClick = (identity,status)=>{
  // ...actions表示将[[],[],[]]内部的数组取出[],[],[]
  let action = [...actions].filter(([key,value])=>(key.identity == identity && key.status == status))
  action.forEach(([key,value])=>value.call(this))
}


const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  return new Map([
    [{identity:'guest',status:1},functionA],
    [{identity:'guest',status:2},functionA],
    [{identity:'guest',status:3},functionA],
    [{identity:'guest',status:4},functionA],
    [{identity:'guest',status:5},functionB],
    //...
  ])
}
const onButtonClick = (identity,status)=>{
  let action = [...actions()].filter(([key,value])=>(key.identity == identity && key.status == status))
  action.forEach(([key,value])=>value.call(this))
}


const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  const functionC = ()=>{/*send log*/}
  return new Map([
    [/^guest_[1-4]$/,functionA],
    [/^guest_5$/,functionB],
    [/^guest_.*$/,functionC],
    //...
  ])
}
const onButtonClick = (identity,status)=>{
  let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}


学习自 掘金Think.大佬


promise


常用的静态方法:all,race,resolve, reject。


常用的实例方法:then, catch。


对于all方法来说,参数是一个若干个promise组成的数组,如果这些promise定义了自己的then,catch方法,并且有返回值,不管是成功还是失败,那么执行all方法的then就会执行,catch就不会执行。


const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(res => res)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch();//这里没有返回值,才会执行all的catch方法。
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
//执行结果
Error: 报错了


axios对其还做了一步简化。将接收到的请求参数封装成一个函数接收spread()


function getUserAccount() {
  return axios.get('/user/12345');
}
function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));


promise只执行一次,但是同一个promise的then,catch可以被执行多次。


const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})
const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})
//只会打印出一次once


.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。


Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)


.then抛出的错误不会被第二个参数函数捕获,只能被后面的catch捕获。


Promise.resolve()
  .then(function success (res) {
  //注意这里是抛出错误,而非返回错误。
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .catch(function fail2 (e) {
    console.error('fail2: ', e)
  })


手写promise


class Promise {
  constructor(executor) {//执行器函数
    let _this = this
    _this.status = 'pending'  //保存当前状态
    _this.value = undefined //执行成功时,传递的值
    _this.error = undefined//执行失败时,传递的值
    function resolve(value) {
      if (_this.status === 'pending') {
        _this.status = 'resolved'
        _this.value = value
      }
    }
    function reject(error) {
      if (_this.status === 'pending') {
        _this.status = 'rejected'
        _this.error = error
      }
    }
    executor(resolve, reject)//调用执行器函数
  }
  then(onfulfilled, onRejected) {
    let _this = this
    if (_this.status === 'resolved') {
      onfulfilled(_this.value)
    } else if (_this.status === 'rejected') {
      onRejected(_this.error)
    }
  }
}
//测试,此代码的问题是不能实现异步方法
let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('我是张昊')
    reject('我是李龙淼')
  }, 1000)
}).then(res => {
  console.log(res)
}, res => {
  console.log(res)
})
//这里什么也不输出


原因是我们在then函数中只对成功态和失败态进行了判断,而实例被new时,执行器中的代码会立即执行,但setTimeout中的代码将稍后执行,也就是说,then方法执行时,Promise的状态没有被改变依然是pending态,所以我们要对pending态也做判断,而由于代码可能是异步的,那么我们就要想办法把回调函数进行缓存,并且,then方法是可以多次使用的,所以要能存多个回调,那么这里我们用一个数组。


创建两个数组,为了存储成功的回调(resolve)和失败的回调(reject)


_this.onResolvedCallbacks = []; // 存放then成功的回调,这里存的都是resolve()的函数
    _this.onRejectedCallbacks = []; // 存放then失败的回调,这里存的都是reject()的函数


在then中判断pending的判断,将then中的回调分别存入onResolvedCallbacksonRejectedCallbacks数组中


if (_this.status === 'pending') {
   // 每一次then时,如果是等待态,就把回调函数push进数组中,什么时候改变状态什么时候再执行
      //缓存成功时的回调函数,等到状态变为resolved的时候,在执行
      _this.onResolvedCallbacks.push(function () {
        onfulfilled(_this.value)
      })
      //缓存失败时的回调函数,等到状态变为rejected的时候,在执行
      _this.onRejectedCallbacks.push(function () {
        onRejectedCallbacks(_this.error)
      })
 } 


在resolve方法中缓存异步执行的成功回调,在reject方法中缓存异步执行的失败的回调


function resolve(value) {
      if (_this.status === 'pending') {
        _this.status = 'resolved'
        _this.value = value
        // 当成功的函数 (resolve()) 被调用时,之前缓存的回调函数会被一一调用
        _this.onResolvedCallbacks.map(callback => callback())
      }
    }
    function reject(error) {
      if (_this.status === 'pending') {
        _this.status = 'rejected'
        _this.error = error
        // 当失败的函数 (reject()) 被调用时,之前缓存的回调函数会被一一调用
        _this.onRejectedCallbacks.map(callback => callback())
      }
    }


为了防止promise在执行出现错误,我们需要做错误处理


try {
      executor(resolve, reject)
    } catch (e) {
      console.log(e)
    }


promise的链式调用。由于promise的状态会发生改变,所以then返回的promise是一个全新的。


有点复杂!!! promise的其他原型方法


// 捕获错误的方法,在原型上有catch方法,返回一个没有resolve的then结果即可
    Promise.prototype.catch = function (callback) {
        return this.then(null, callback)
    }
    // 解析全部方法,接收一个Promise数组promises,返回新的Promise,遍历数组,都完成再resolve
    Promise.all = function (promises) {
        //promises是一个promise的数组
        return new Promise(function (resolve, reject) {
            let arr = []; //arr是最终返回值的结果
            let i = 0; // 表示成功了多少次
            function processData(index, y) {
                arr[index] = y;
                if (++i === promises.length) {
                    resolve(arr);
                }
            }
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(function (y) {
                    processData(i, y)
                }, reject)
            }
        })
    }
    // 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
    Promise.race = function (promises) {
        return new Promise(function (resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                promises[i].then(resolve,reject)
            }
        })
    }
    // 生成一个成功的promise
    Promise.resolve = function(value){
        return new Promise(function(resolve,reject){
            resolve(value);
        })
    }
    // 生成一个失败的promise
    Promise.reject = function(error){
        return new Promise(function(resolve,reject){
            reject(error);
        })
    }


学习自


promise必知必会


rocYoung对promise的分析


前端的路由跳转


Hash 方法是在路由中带有一个 #,主要原理是通过监听 # 后的 URL 路径标识符的更改而触发的浏览器 hashchange 事件,然后通过获取 location.hash 得到当前的路径标识符,再进行一些路由跳转的操作。


class RouterClass {
  constructor() {
    this.isBack = false
    this.routes = {}        // 记录路径标识符对应的cb
    this.currentUrl = ''    // 记录hash只为方便执行cb
    this.historyStack = []  // hash栈
    window.addEventListener('load', () => this.render())
    window.addEventListener('hashchange', () => this.render())
  }
  /* 初始化 */
  static init() {
    window.Router = new RouterClass()
  }
  /* 记录path对应cb */
  route(path, cb) {
    this.routes[path] = cb || function() {}
  }
  /* 入栈当前hash,执行cb */
  render() {
    if (this.isBack) {      // 如果是由backoff进入,则置false之后return
      this.isBack = false   // 其他操作在backoff方法中已经做了
      return
    }
    this.currentUrl = location.hash.slice(1) || '/'
    //将每一个路径都加入到栈中,为了back的判断
    this.historyStack.push(this.currentUrl)
    this.routes[this.currentUrl]()
  }
  /* 路由后退 */
  back() {
    this.isBack = true
    this.historyStack.pop()                   // 移除当前hash,回退到上一个
    const { length } = this.historyStack
    if (!length) return //如果栈中没有路径了,将直接结束
    let prev = this.historyStack[length - 1]  // 拿到要回退到的目标hash
    location.hash = `#${ prev }`   //为了使手动跳转正常进行,需要将当前路径加上一个#,来满足slice的分割
    this.currentUrl = prev
    this.routes[prev]()                       // 执行对应cb
  }
}


history


  1. history.go(n):路由跳转,比如n为 2 是往前移动2个页面,n为 -2 是向后移动2个页面,n为0是刷新页面


  1. history.back():路由后退,相当于 history.go(-1)


  1. history.forward():路由前进,相当于 history.go(1)


  1. history.pushState():添加一条路由历史记录,如果设置跨域网址则报错,浏览器有记录。


  1. history.replaceState():替换当前页在路由历史记录的信息,浏览器无记录。


  1. popstate 事件:当活动的历史记录发生变化,就会触发 popstate 事件,在点击浏览器的前进后退按钮或者调用上面前三个方法的时候也会触发,参见 MDN


何为闭包?


闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量该函数内部绑定的符号),也要包括自由变量在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用。


而闭包则意味着同时包括函数指针环境两个关键元素。在编译优化当中,没有捕捉自由变量的闭包可以被优化成普通函数。


闭包中引入的变量何时被销毁?


闭包中访问的外部变量是存放在堆内存中的。


变量的生命周期取决于闭包的生命周期。被闭包引用的外部作用域中的变量将一直存活直到闭包函数被销毁。如果一个变量被多个闭包所引用,那么直到所有的闭包被垃圾回收后,该变量才会被销毁。


维基百科


数组方法(存在高阶函数)的返回值


map:该方法的返回值就是回调函数的返回值组成的数组。


filter: 该方法的返回值就是回调函数符合条件的返回值组成的数组。


let arr = [1, 2, 3, 4]
let resArr = arr.filter(item => {
  if (item > 2) {
    return item
  }
})
//等价于
arr.filter(item => item > 2)
console.log(resArr)


forEach:该方法没有返回值。


reduce:该方法返回的值是累计器(回调函数的第一个参数)累计后的值。


let arr = [
  { id: 1, name: 'zh', age: 20 },
  { id: 2, name: 'hy', age: 19 },
  { id: 3, name: 'llm', age: 19 }
]
let reArr = arr.reduce((pre, next) => {
  if (next.age === 19) {
    return pre.concat(Object.assign({}, next, { sex: 'female' }))
  }
  return []//这里必须有返回值,不然会报错,因为每遍历一项都需要有返回值。如果上面用到了pre,下面没有返回就会报错,pre的值是每次回调函数返回的值。
}, [])
console.log(reArr)
// {id: 2, name: "hy", age: 19, sex: "female"}
// {id: 3, name: "llm", age: 19, sex: "female"}


every: 该方法的返回值是布尔值,只有数组中的元素都满足条件,才回返回true,否则返回false。


let arr = [1, 2, 3, 4]
let resArr = arr.every(item => item >= 1)
console.log(resArr)


some:该方法返回的是布尔值,表示只要数组中有一个元素满足条件就返回true,否则返回false。


find:该方法返回的是第一个满足条件的值。


findIndex:该方法返回的是第一个满足条件的值的下标。


URLsearchParams


URLsearchParams(url)用来解析url参数的。


//URLSearchParams用来解析参数的
let url = '?name=zh&age=20';
let searchParams = new URLSearchParams(url)
// console.log(searchParams)//map对象
let arr = [...searchParams]
console.log(arr) //[ [ 'name', 'zh' ], [ 'age', '20' ] ]


获取单个参数。


searchParams.get('name')


校验参数是否存在。


searchParams.has('sex') // false
searchParams.has('age') // true


添加参数。


searchParams.append('sex', 'male')
console.log(searchParams)//URLSearchParams { 'name' => 'zh', 'age' => '20', 'sex' => 'male' }
console.log(url)//?name=zh&age=20,注意url并不会添加上该参数,但是解析后是有该参数的


删除参数。


searchParams.delete('sex');
searchParams.has('sex'); // false


修改参数。


searchParams.set('age', 22)
console.log(searchParams)//URLSearchParams { 'name' => 'zh', 'age' => '22', 'sex' => 'male' }


将解析后的参数,再转为查询字符串。


searchParams.toString() //name=zh&age=22&sex=male


重写数组方法


重写map方法,利用for循环


const selfMap = function (fn, context = this) {
  //这里的context会被当做fn函数中的this,如果不传入context,那么this就是调用的数组。
  let arr = Array.prototype.slice.call(context)
  let mappedArr = Array()
  for (let i = 0; i < arr.length; i++) {
    //判断稀疏数组的情况
    if (!arr.hasOwnProperty(i)) continue;
    mappedArr[i] = fn.call(context, arr[i], i, this)
    // console.log(context)
  }
  return mappedArr
}
Array.prototype.selfMap = selfMap
let resArr = [0, 0, 0, 1].selfMap(number => number * 2, [2, 3, 4])
console.log(resArr)//[4,6,8]


我对map方法的错误理解,context只是改变了this指向,然而并不是改变函数执行的数组。


作者大大,第二个方法,即map方法,我感觉应该把context初始为this,然后slice方法中传入context,这样传入第二个参数的时候,this的值才回改变。不然没有效果 let resArr = [0, 0, 0, 1].selfMap(number => number * 2, [2, 3, 4]) console.log(resArr)//这里仍然是[0,0,0,2],而不是[4,6,8] //下面这样就是对的 const selfMap = function (fn, context = this) { //这里的context会被当做fn函数中的this let arr = Array.prototype.slice.call(context) let mappedArr = Array() for (let i = 0; i number * 2, [2, 3, 4]) console.log(resArr)//[4,6,8] 如果不对,望告知。


这里是js原生的map测试


let resArr = [4, 5, 6].map(function (item, index, arr1) {
  console.log(arr1)//[4,5,6]
  console.log('this', this)//[1,2,3]
  return item * 2//作用的是[4,5,6]
}, [1, 2, 3])
console.log(resArr)


重写map方法。利用reduce方法。


const selfMap = function (fn, context) {
  let arr = Array.prototype.slice.call(this)
  return arr.reduce((pre, cur, index) => {
    //这个返回值就是pre,然后将完全处理后的元素,都返回给pre,然后展开pre即可。
    //也就是这里我有一个疑问,他每次都返回pre,每次都展开pre,每次展开都会重复上一次返回的pre中的元素呀,所以应该会重复很多呀。
    return [...pre, fn.call(context, cur, index, this)]
  }, [])
}
Array.prototype.selfMap = selfMap
let resArr = [1, 2, 3].selfMap(item => item * 2)
console.log(resArr)


解决疑惑:因为数组的内存地址都是一样的,pre的内存地址一样的,只是展开了最后一次赋值的值。


let a = new Array(10)
let resArr = []
for (let i = 0; i <= a.length; i++) {
  let arr = [i]
  resArr = [...arr, 2, 3, 4]
}
console.log(resArr)//[ 10, 2, 3, 4 ]


重写filter方法,利用for循环。


const selfFilter = function (fn, context) {
  //要处理的数组
  let arr = Array.prototype.slice.call(this)
  let resArr = Array()
  for (let i = 0; i < arr.length; i++) {
    //判断返回的条件是否正确,并且加入到数组中。
    fn.call(context, arr[i], i, this) && resArr.push(arr[i])
  }
  return resArr
}
Array.prototype.selfFilter = selfFilter
let arr = [1, 2, 3]
let arr1 = arr.selfFilter(item => item > 2)
console.log(arr1)


重写filter,利用reduce。


const selfFilter = function (fn, context) {
  let arr = Array.prototype.slice.call(this)
  let resArr = []
  return arr.reduce((pre, cur, index) => {
    // if (fn.call(context, cur, index, this)) {
    //   resArr.push(cur)
    //   return resArr
    // }
    return fn.call(context, cur, index, this) ? [...pre, cur] : [...pre]
  }, [])
}
Array.prototype.selfFilter = selfFilter
let arr = [0, 2, 3]
let arr1 = arr.selfFilter(item => item > 2)
console.log(arr1)


重写some,利用for循环。


const someFilter = function (fn, context) {
  let arr = Array.prototype.slice.call(this)
  for (let i = 0; i < arr.length; i++) {
    if (fn.call(context, arr[i], i, this))
      return true
  }
  return false
}
Array.prototype.someFilter = someFilter
let arr = [1, 2, 3]
let arr1 = arr.someFilter(item => item > 2)
console.log(arr1)


重写flat方法,利用reduce。


const selfFlat = function (depth = 1) {
  let arr = Array.prototype.slice.call(this)
  // let resArr = []
  if (depth === 0) return arr
  return reduce((pre, cur) => {
    if (Array.isArray(cur)) {
      //反正就是递归
      return [...pre, ...selfFlat.call(cur, depth - 1)]
    } else {
      return [...pre, cur]
    }
  }, [])
}


es6的面向对象class语法


ES6 的 class 内部是基于寄生组合式继承


function inherit(subType, superType) {
  subType.prototype = Object.create(superType.prototype, {
    constructor: {
      value: subType,
      enumerable: false,
      configurable: true,
      writable: true
    }
  })
  // 让类的静态方法也可以被继承。
  Object.setPrototypeOf(subType, superType)
}


相关文章
|
5天前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
|
5天前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
17 0
|
23小时前
|
前端开发 JavaScript 安全
JavaScript前端开发技术
JavaScript(简称JS)是一种广泛使用的脚本语言,特别在前端开发领域,它几乎成为了网页开发的标配。从简单的表单验证到复杂的单页应用(SPA),JavaScript都扮演着不可或缺的角色。
10 3
|
5天前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
38 0
|
5天前
|
前端开发 JavaScript 程序员
【从前端入门到全栈】Node.js 之核心概念
【从前端入门到全栈】Node.js 之核心概念
|
5天前
|
Web App开发 JavaScript 前端开发
前端Node.js面试题
前端Node.js面试题
|
5天前
|
Web App开发 JavaScript 前端开发
对于 前端 解释下 node.js的必要性
对于 前端 解释下 node.js的必要性
7 0
|
6天前
|
监控 JavaScript 前端开发
深入了解Vue.js:构建现代前端应用的利器
【10月更文挑战第11天】深入了解Vue.js:构建现代前端应用的利器
10 0
|
5天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
|
5天前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。