热情的王宗岳

热情的王宗岳 查看完整档案

连云港编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

热情的王宗岳 提出了问题 · 2019-08-17

egg的log4如何打印函数名称

问题描述

egg的log4每执行一个函数就打印、请问如何简便处理呢

相关代码

async list() {
    console.log('======ctl.carinfo.list=====')
    const ctx = this.ctx;
    ctx.body = await ctx.service.carinfo.list(ctx.query);
    console.log('======END===========================')
  }

每个函数都要多写两行consol,而log4本身的日志虽然详细,但是看起来不那么清爽

关注 1 回答 0

热情的王宗岳 赞了文章 · 2019-07-20

Vue的computed和watch的细节全面分析

1.computed

1.1 定义

是一个计算属性,类似于过滤器,对绑定到view的数据进行处理

1.2 get用法

  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }

fullName不可在data里面定义,
如果定义会报如下图片的错误,因为对应的computed作为计算属性定义fullName并返回对应的结果给这个变量,变量不可被重复定义和赋值

图片描述

1.3 get和set用法

data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
  fullName:{
   get(){//回调函数 当需要读取当前属性值是执行,根据相关数据计算并返回当前属性的值
      return this.firstName + ' ' + this.lastName
    },
   set(val){//监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据
       //val就是fullName的最新属性值
       console.log(val)
        const names = val.split(' ');
        console.log(names)
        this.firstName = names[0];
        this.lastName = names[1];
   }
   }
  }

2. watch

2.1 定义

watch是一个观察的动作

2.2 示例

  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
     firstName: function (val) {
     this.fullName = val + ' ' + this.lastName
  },
  lastName: function (val) {
     this.fullName = this.firstName + ' ' + val
   }
   }

上面是监听firstName和lastName的变化,但是仅限简单数据类型

2.2 监听简单数据类型

data(){
      return{
        'first':2
      }
    },
    watch:{
      first(){
        console.log(this.first)
      }
    },

2.3 监听复杂数据类型

1.监听复杂数据类型需用深度监听

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    watch:{
      secondChange:{
        handler(oldVal,newVal){
          console.log(oldVal)
          console.log(newVal)
        },
        deep:true
      }
    },

2.console.log打印的结果,发现oldVal和newVal值是一样的,所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面那个属性的变化

3.oldVal和newVal值一样的原因是它们索引同一个对象/数组。Vue 不会保留修改之前值的副本
vm.$watch的深度监听

图片描述

4.深度监听对应的函数名必须为handler,否则无效果,因为watcher里面对应的是对handler的调用

2.4 监听对象单个属性

方法一:可以直接对用对象.属性的方法拿到属性
data(){
          return{
            'first':{
              second:0
            }
          }
        },
        watch:{
          first.second:function(newVal,oldVal){
            console.log(newVal,oldVal);
          }
        },
    

方法二:watch如果想要监听对象的单个属性的变化,必须用computed作为中间件转化,因为computed可以取到对应的属性值

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    computed:{
      secondChange(){
        return this.first.second
      }
    },
    watch:{
      secondChange(){
        console.log('second属性值变化了')
      }
    },

3 computed和watch的区别

3.1 computed特性

1.是计算值,
2.应用:就是简化tempalte里面{{}}计算和处理props或$emit的传值
3.具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数

3.2 watch特性

1.是观察的动作,
2.应用:监听props,$emit或本组件的值执行异步操作
3.无缓存性,页面重新渲染时值不变化也会执行

3 props传值

3.1 常见错误1

传入的值想作为局部变量来使用,直接使用会

props:['listShop'],
    data(){
      return{}
    },
    created(){
      this.listShop=30
}

报错

图片描述

这个错误是说的避免直接修改父组件传入的值,因为会改变父组件的值,贴上官网介绍

3.2 解决方案1

简单数据类型解决方案:
所以可以在data中重新定义一个变量,改变指向,但是也只是针对简单数据类型,因为复杂数据类型栈存贮的是指针,

props:['listShop'],
    data(){
      return{
        listShopChild:this.listShop
      }
    },
    created(){
      this.listShopChild=30
    }
    

这样就可以愉快的更改传入的简单数据类型的数据啦!不会有任何报错,也不会影响父组件!

3.4 存在的问题

复杂数据类型在栈中存贮的是指针,所以赋值给新的变量也会改变原始的变量值.那么应该咋整呢?
1.可以手动深度克隆一个复杂的数据出来,循环或者递归都行

数组深度克隆:

var x = [1,2,3];
var y = [];
for (var i = 0; i < x.length; i++) {
    y[i]=x[i];
}
console.log(y);  //[1,2,3]
y.push(4);
console.log(y);  //[1,2,3,4]
console.log(x);  //[1,2,3]

对象深度克隆:

var x = {a:1,b:2};
var y = {};
for(var i in x){
    y[i] = x[i];
}
console.log(y);  //Object {a: 1, b: 2}
y.c = 3;
console.log(y);  //Object {a: 1, b: 2, c: 3}
console.log(x);  //Object {a: 1, b: 2}

函数深度克隆

var x = function(){console.log(1);};
var y = x;
y = function(){console.log(2);};
x();  //1
y();  //2

为什么函数可以直接赋值克隆?
由于函数对象克隆之后的对象会单独复制一次并存储实际数据,因此并不会影响克隆之前的对象。所以采用简单的复制“=”即可完成克隆。

2.Object.assign
只会对只是一级属性复制,比浅拷贝多深拷贝了一层而已,所以还是无法达到深度克隆的目的.
详请请戳

3.强大的JSON.stringify和JSON.parse

const obj1 = JSON.parse(JSON.stringify(obj));

这是ES5新出来的API,先将对象转化为字符串,就是简单数据类型赋值,再用JSON.parse转化

3.5 解决方案2

直接用computed改变

computed:{
  listShopChild(){
    return this.listShop
   }
}

3.5 存在的问题

注意:此时用computed时,如果是数组this.$set(arr,1,true)对应的值耶不更新
这个很坑,这个bug我找个很久
如果传入的值只是在data定义,并未在methods或生命周期钩子更改,直接改变也会报错
所以还是可以先用局部变量接收,再修改,这个坑比较多

4 应用

4.1 应用1

监听本组件计算和监听

4.2 应用2

计算或监听父传子的props值

4.3 应用3

分为简单数据类型和复杂数据类型监听,监听方法如上watch的使用

4.4 应用4

监听vuex的state或者getters值的变化

computed:{
    stateDemo(){
        return this.$store.state.demoState;
    }
}
watch:{
    stateDemo(){
        console.log('vuex变化啦')
    }
}

5. computed和watch的原理分析

很开心小伙伴们能看到这里,接下来给大家简单罗列下他们的原理!

5.1 computed的原理

深入理解 Vue Computed 计算属性

5.2 watch的原理

分为三个过程:实例化Vue、调用$watch方法、属性变化,触发回调
Vue的数据依赖实现原理简析
vue中$watch源码阅读笔记

6 简单实现computed和watch

公共类

function defineReactive(data, key, val, fn) {
      let subs = [] // 新增
      Object.defineProperty(data, key, {
        configurable: true,
        enumerable: true,
        get: function() {
          // 新增
       if (data.$target) {
        subs.push(data.$target)
      }
      return val
     },
     set: function(newVal) {
      if (newVal === val) return
      fn && fn(newVal)
      // 新增
      if (subs.length) {
        // 用 setTimeout 因为此时 this.data 还没更新
        setTimeout(() => {
          subs.forEach(sub => sub())
        }, 0)
      }
      val = newVal
    },
   })
 }

6.1 computed实现

function computed(ctx, obj) {
  let keys = Object.keys(obj)
  let dataKeys = Object.keys(ctx.data)
  dataKeys.forEach(dataKey => {
    defineReactive(ctx.data, dataKey, ctx.data[dataKey])
  })
  let firstComputedObj = keys.reduce((prev, next) => {
    ctx.data.$target = function() {
      ctx.setData({ [next]: obj[next].call(ctx) })
    }
    prev[next] = obj[next].call(ctx)
    ctx.data.$target = null
    return prev
  }, {})
  ctx.setData(firstComputedObj)
}

6.1 watch实现


function watch(ctx, obj) {
  Object.keys(obj).forEach(key => {
    defineReactive(ctx.data, key, ctx.data[key], function(value) {
      obj[key].call(ctx, value)
    })
  })
}

https://segmentfault.com/a/11...
大家如果发现有什么错误,欢迎指正,共同交流。如果觉得篇文章真的对你有点作用。
谢谢亲们能看完!

查看原文

赞 174 收藏 143 评论 13

热情的王宗岳 提出了问题 · 2019-06-09

pad上用html5录屏录音时回声很严重、原因时把话筒输入的声音也录进去了,求助

start() {
      window.navigator.mediaDevices
        .getUserMedia(this.constraints)
        .then(stream => {
          this.mediaStream = stream;
          this.streamVideo.srcObject = stream;
          this.streamVideo.play();
          this.recorder = new MediaRecorder(stream);
          this.recorder.ondataavailable = e => {
            this.chunk = e.data;
            this.download.href = window.URL.createObjectURL(chunk);
          };
          this.recorder.start();
        });
    },

api文档里没有此说明,求助高手了。

关注 2 回答 1

热情的王宗岳 提出了问题 · 2019-06-09

html5调用摄像头录屏时有刺耳的背景音,其为扬声器声音,请教如何用js关闭

查找相关资料发现并无此配置参数,请教!

关注 2 回答 1

热情的王宗岳 赞了回答 · 2019-04-25

解决sequelize left join语句不知道如何写

用了好长一段时间sequelize 我直接贴我的代码吧,多表首先是定义model时就声明多表之间的关系。

clipboard.png
关系有belongTo hasOne hasMany ... 具体可以去看文档,这里就已经确定关系查询时直接 model.findAll({include: [{model: XX}]})sequelize 会自动处理生成对应的sql。

关注 3 回答 2

热情的王宗岳 提出了问题 · 2019-04-24

解决sequelize left join语句不知道如何写

demo里

var notes = yield Note.findAll({
    'include': [
        {
            'model': Tag
            // 这里可以对tags进行where
        }
]

对应的sql是Note的id 对应Tag的user_id

如果我现在要实现Note.tb_code 对应如何做呢

关注 3 回答 2

热情的王宗岳 赞了回答 · 2019-03-15

解决关于Vue中的 render: h => h(App) 具体是什么含义?

// 写法1:

import App from './App'
new Vue({
    el: '#root',
    render: h => h(App)
})

// 写法2:

import App from './App'
new Vue({
    el: '#root',
    template: '<App></App>',
    components: {
        App
    }
})

上面两种的效果是一样的,可以看出 h(App)函数 的作用是:使用App作为这个Vue实例的template(同时一并了注册App组件)

以上个人见解,有错误望指正

关注 32 回答 10

热情的王宗岳 提出了问题 · 2018-11-15

请教sequelize下这条sql改如何写

select cost1,cost2,(cost1-cost2) as cost3 from money
_.model.findAndCountAll({ ... })

请教...里面的内容该如何写呢?这个属于计算字段!多谢啦!

关注 1 回答 0

热情的王宗岳 赞了回答 · 2018-10-27

解决为什么要先commit,然后pull,最后再push?而不是commit然后直接push?

见解

1.本地算一个clone体。

2.是得,如果远程有一个分支 dev,那么pull origin dev,本地就会有一个dev分支。

3.仓库是整个项目,分支算其中一个生产线。就和阿里巴巴集团不是只有一个淘宝一样

4.push会进行分析,当然不是所有,你可以自己测试,弄一些大文件,第一次新建项目的push会很慢,如果你加一个几k的文本,那这次传输很快

5.commit是防止远程直接覆盖你本地,只要有修改都会让你commit,提示你pull原因是因为你远程当中有最新的东西和你本地不一致,git知道,远程分支的东西不能丢掉,所以让你pull下来存到本地,让本地变成最新的最后push上去,难么同理的方式你本地就是最新,便会去修改远程的。

回答完毕,么么哒

关注 15 回答 5

热情的王宗岳 赞了回答 · 2018-10-04

解决es6如何快速的删除数组元素

ES6 findIndexMDN :Array.prototype.findIndex()
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

arr.splice(arr.findIndex(item => item.id === 8), 1)

推荐文章:【深度长文】JavaScript数组所有API全解密 | louis blog

关注 14 回答 13

认证与成就

  • 获得 14 次点赞
  • 获得 249 枚徽章 获得 5 枚金徽章, 获得 69 枚银徽章, 获得 175 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-02-16
个人主页被 1.2k 人浏览