工作问题与思考

81 阅读3分钟

7 月

  1. top bottom等 是相对于上一个有定位(relative absolute等)的父元素来说
  2. yarn的时候报错error An unexpected error occurred: "registry.npm.taobao.org/webpack-ali…: Request failed "404 Not Found"". 原因是在npm中没有指定的aliyun-oss版本,改用0.3.12版本
  3. 封装组件需要给出足够的灵活性,就如日期选择器来说,一开始我只写了value,onChange,placeholder这三个属性,这样的话使用组件的时候就只能传入这三个属性,所以封装的组件灵活性就会受限。因此,使用Partial<DateProps & DatePickerProps>的交叉类型来获取组件的属性,再用...rest来获取剩余的属性。并且在组件用使用。这样使用者可以传入NutUI组件所拥有的任意属性,极大拓宽了组件的灵活性。
`const reLocation = () =>
{` ```setIsLoading(true) //开始加载效果``  
const options = { ` `showButton: false, //是否显示定位按钮` 
`buttonPosition: 'LB', //定位按钮的位置` `/* LT LB RT RB */` 
`buttonOffset: new AMap.Pixel(10, 20), //定位按钮距离对应角落的距离` 
`showMarker: true, //是否显示定位点` 
`markerOptions,` `showCircle: false, //是否显示定位精度圈` `}` `AMap.plugin(['AMap.Geolocation'], 
function () 
{` `const geolocation = new AMap.Geolocation(options)` `map.current.addControl(geolocation)`
`geolocation.getCurrentPosition(function (` 
`status,` `result: {` 
`formattedAddress: string` 
`position: mapLocation` `message: string` `}`
`) {` `if (status == 'complete') 
{` `setAddress(result?.formattedAddress)` 
`setIsMap(true)` 
`locationChange?.({`
`locationLongitude: result.position.lng,` 
`locationLatitude: result.position.lat,`
`location: result?.formattedAddress,` 
`})`
`} else {` 
`showToast({`
`title: 定位失败-${result?.message ?? '请检查是否获取定位权限'},`
`icon: 'error',` `})` 
`}` 
`})` 
```setIsLoading(false) //加载结束 修改后` 
`})``setIsLoading(false) //加载结束 修改前`
`}`

在方法中setIsLoading不生效,原因是 setIsLoading 的调用位置不正确。AMap.plugin 方法是异步执行的,而 geolocation.getCurrentPosition 方法也是异步的。这意味着setIsLoading(false) 会在内部回调函数之前被调用,因此加载状态将立即被设置为 false,无法正确显示加载效果。解决方案是将 setIsLoading(false) 移动到geolocation.getCurrentPosition 的回调函数中,确保在获取位置信息完成后再将加载状态设置为 false

  1. 平原小程序线上问题,原因是在运行"dev:weapp": "npm run build:weapp -- --watch"的情况下走的是开发环境的代理,这样在线上是获取不到数据的。

  2. 在js中 ?? 和 || 和 && 的区别为:2.在js中 ?? 和 || 和 && 的区别为: A ?? B :如果A为null或者undefined则返回B,否则返回A A || B :如果A为false则返回B,否则返回A A && B :如果A为 false0''nullundefined 或者 NaN。直接返回 A,否则继续判断B**

  3. 之前一直不知道hooks的钩子含义到底是什么意思,现在了解到:如果说函数组件是一台轻巧的快艇,那么 React-Hooks 就是一个内容丰富的零部件箱。“重装战舰”所预置的那些设备,这个箱子里基本全都有,同时它还不强制你全都要,而是允许你自由地选择和使用你需要的那些能力,然后将这些能力以 Hook(钩子)的形式“钩”进你的组件里,从而定制出一个最适合你的“专属战舰”。(引用自《深入浅出搞定 React》)

8月

  1. useEffectuseLayoutEffect是React提供的两个钩子函数,它们都可以在组件渲染完成后执行副作用操作。它们的主要区别在于执行时机。
  • useEffectuseEffect是异步执行的,它会在浏览器绘制完成后才执行,不会阻塞渲染线程,不会影响视觉效果。适合大多数情况下的副作用操作,如数据获取、订阅事件、操作DOM等。
  • useLayoutEffectuseLayoutEffect是同步执行的,它会在所有的DOM变更计算完成后、浏览器绘制之前执行。这意味着它会阻塞渲染线程,可能会导致视觉上的阻塞。建议在需要立即处理或依赖DOM准确布局信息的副作用操作时使用,比如测量DOM节点的尺寸、手动处理样式等。

一般来说,优先选择使用useEffect,因为它的异步特性使得它的性能表现更好,并且不会引起视觉阻塞。只有在某些特定场景下,如果需要在浏览器绘制之前执行副作用操作,才考虑使用useLayoutEffect

需要注意的是,由于useLayoutEffect会阻塞渲染线程,过度使用或使用不当可能会导致性能问题和页面卡顿。因此,只有在确实需要同步操作DOM布局或获取准确信息时才应该使用useLayoutEffect,并在使用时要谨慎评估其对性能的影响。

  1. React setState
 increment = () => {

  // 进来先锁上

  isBatchingUpdates = true

  console.log('increment setState前的count', this.state.count)

  this.setState({

    count: this.state.count + 1

  });

  console.log('increment setState后的count', this.state.count)

  // 执行完函数再放开

  isBatchingUpdates = false

}
reduce = () => {

  // 进来先锁上

  isBatchingUpdates = true

  setTimeout(() => {

    console.log('reduce setState前的count', this.state.count)

    this.setState({

      count: this.state.count - 1

    });

    console.log('reduce setState后的count', this.state.count)

  },0);

  // 执行完函数再放开

  isBatchingUpdates = false

}

react中setState是异步的,但是放在setTimeout中会逃脱异步约束,成为一个同步事件的原因是:

isBatchingUpdates锁 的true和false会在事件循环中先执行,所以无法对setState造成约束。即——在特定的情境下,它会从 React 的异步管控中“逃脱”掉。

  1.   const uploadRes = await Taro.uploadFile({
         url: OSS_URL,
         filePath: path,
         name: 'file',
         formData: {
           bucket: OSS_BUCKET,
           name: `biz/n400/rtc/${Date.now().toString(32)}${index}.${path.split('.').pop()}.html`,
         },
         fail(errMsg) {
           Taro.showToast({
             title: '图片上传失败',
           });
           realtimeLogger.error('图片上传失败', {
             errMsg,
           });
           console.log('uploadFile fail', errMsg);
         },
         complete() {
           Taro.hideLoading();
         },
       });
    

image.png 用户可以主动在name中修改文件后缀,可以绕过检查,通过传递script标签,达到xss攻击。

  1. 3.Function.proto===Function.prototype的原因

因为Function本身也是一个Function对象,也就是var Function = new Function(),这看起来有点鸡和蛋的意思,不过如果先给你一个蛋,那必然就是先有蛋后有鸡了。所以如果先给你一个Function对象的原形[[Prototype]],那么就可以通过一个函数构建出Function的实例了,这个函数就是Function本身。

引自:segmentfault.com/q/101000001…

5.闭包实现的原因是在执行上下文中维护的作用域链,让已经被销毁的函数中的值依然能被引用到。

6.作用域

var value = 1;
function foo() {console.log(value);}
function bar() {var value = 2;foo();}
bar();// 结果是 1

因为 js 采用的是词法作用域,函数的作用域在函数定义的时候就决定了。所以当 value 向上查找的时候,查找的到的是 value=1 而不是 2。

  //用数组序号[0]是不安全的方法,后端数组返回顺序有问题的话会出错
  let options:fraudOpt[]=[]
   variableField[0]?.fieldOptions?.forEach(element => {
     options.push({value:element.optionValue,label:element.optionName})
   });
  setFraudOptions(options)
 //此处优化为根据fieldName值来找到对应的对象
 const {fieldOptions} = variableField.find((item)=>
    item.fieldName === '诈骗类型') || {}
    const map= fieldOptions?.map((item)=>{
        return {value:item.optionValue,label:item.optionName}
    })
 //返回值只有一行,利用箭头函数语法糖
 const {fieldOptions} = variableField.find((item)=>
    item.fieldName === '诈骗类型') || {}
    setFraudOptions(fieldOptions?.map(({ optionValue, optionName })
    =>
    ({value: optionValue,label: optionName,})
    ))

可以通过使用解构赋值来筛选不需要的字段

const {templateVersion,...rest} =values
var data = [];

for (var i = 0; i < 3; i++) {
 data[i] = (function (i) {
       return function(){
           console.log(i);
       }
 })(i);  // 立即执行函数,可以立即压入上下文栈,保存 i 在作用域链中  
}

data[0]();
data[1]();
data[2]();
var data = [];

for (var i = 0; i < 3; i++) {
  data[i] = function () {
    console.log(i);       //函数需要执行才能压入上下文栈
  };
}

data[0]();
data[1]();
data[2]();
  • 1===1===1(a===b===1) 结果为 false

因为 1===1 结果是 true,然后 true === 1 结果为false, 可以修改为(a===1&&b===1)

  • 1== 1== 1 结果为 true
  1. 当有一个 for 循环的时候
    for(let i=0;i<arr.length;i++){
    }
    
    循环过程中不要修改 arr 数组,会同步影响到 for 循环中 arr.length的长度,影响循环次数