tomoya06 / web-developer-guidance

Actually it's just a notebook for keeping down some working experience.
4 stars 0 forks source link

JavaScript - Tricks #12

Open tomoya06 opened 4 years ago

tomoya06 commented 4 years ago

业务常用函数实现

防抖

节流

tomoya06 commented 4 years ago

语法常见问题

为什么 0.1 + 0.2 != 0.3

参考两处:这里这里

IEEE 754 双精度(64位)

64位中符号位占1位,指数位占11位,尾数52位。尾数默认第一位都是1,所以只存小数点以后的值。

image

例如十进制的0.1,化为二进制是0.0001100110011001...(无限循环) = 2^-4 * 1.10011(0011循环),保存为【0】【-4】【10011(0011x11次)010】(有进位)

分析

因为 JS 的数字类型就用的是上面的标准,并且只要采用 IEEE 754 的语言都有该问题。数字运算都要先转成二进制,转换的过程中有误差,另外还有末尾进位,又导致误差。

0.1 -> 0.0001100110011001...(无限循环) = 2^-4 * 1.10011(0011x11次)001
0.2 -> 0.0011001100110011...(无限循环) = 2^-3 *  1.1(0011x12次)010

0.1 + 0.2 -> 2^-2 1.0011(0011 11次)0100 -> 0.30000000000000004

解决方法

parseFloat((0.1 + 0.2).toFixed(10))
tomoya06 commented 3 years ago

数据埋点

图片埋点

aka. image beacon

有传闻提出,用1x1透明gif图片发送数据埋点。部分存疑(哪来的图片?)不过用1x1 gif的好处在于:

tomoya06 commented 3 years ago

AJAX

AJAX,全称Asynchronous JavaScript And XML,就是使用 XMLHttpRequest 对象与服务器通信。

可以通过XMLHttpRequest或fetch两个接口发起。自己实现参考这里

XMLHttpRequest

完整示例:

参考MDN文档

function sendRequestWithXML() {
  const httpRequest = new XMLHttpRequest();
  if (!httpRequest) {
    alert('not support XMLHttpRequest');
    return;
  }
  httpRequest.onreadystatechange = handleReadyStateChange;
  httpRequest.open('GET', mockApi);
  httpRequest.send();

  function handleReadyStateChange() {
    if (httpRequest.readyState === XMLHttpRequest.DONE) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
      } else {
        alert('oops: ', httpRequest.status);
      }
    }
  }
}

fetch

完整示例:

function sendRequestWithFetch() {
  fetch(mockApi)
    .then(response => {
      if (response.status === 200) {
        return response.json();
      } else {
        throw new Error(response.status);
      }
    })
    .then(data => {
      alert(JSON.stringify(data));
    }).catch(e => {
      alert('oops: ', e);
    })
}

HOOK

来自本人面试经验。

ajax-hook

AJAX hook的目的是能拦截所有ajax请求,统一处理请求数据和相应数据。目前市面上已经有一款ajax-hook的项目实现了类似的功能。下文参考该项目的实现来设计hook的实现思路。

image

Ajax-hook实现的整体思路是实现一个XMLHttpRequest的代理对象,然后覆盖全局的XMLHttpRequest,这样一旦上层调用 new XMLHttpRequest 这样的代码时,其实创建的是Ajax-hook的代理对象实例。

Ajax-hook也使用了es5的setter/getter方法来设置代理,在setter中把用户的自定义方法hook到XMLHttpRequest实例上。

XMLHttpRequest prototype

来自栈溢出网友回答,感觉是不错的方法,通过改写prototype实现。

(function() {
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
        console.log('request started!');
        this.addEventListener('load', function() {
            console.log('request completed!');
            console.log(this.readyState); //will always be 4 (ajax is completed successfully)
            console.log(this.responseText); //whatever the response was
        });
        origOpen.apply(this, arguments);
    };
})();

fetch promise

对fetch的hook比较方便,引用另一个栈溢出网友的回答,只需包装一个promise来处理即可:

var taperFunction = response => response;
var originalFetch = fetch;
fetch = (input, init) => originalFetch(input, init)
    .then(response => new Promise((resolve) => {
        resolve(taperFunction(response));
    }));
tomoya06 commented 3 years ago

js柯里化

柯里化(Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

例如,下面的foo函数:

var foo = function(a) {
  return function(b) {
    return a * a + b * b;
  }
}

调用方法为foo(3)(4)

主要是写法上的新奇。参考这篇掘金博客,实现multi(2)(3)(4)=24的柯里化代码参考这里

tomoya06 commented 3 years ago

JSONP实践

JSONP的基本思想:通过<script>的src,向服务器请求数据,且这不受同源策略限制(img和iframe的src也是如此);然后服务器将相应的数据放入指定的函数回调名中,返回给前端。

Node.js后端处理

使用<script>请求API时,理论上相当于浏览器把接口返回的数据当成一个js文档来解析并执行。所以接口需要返回一段合法的js语句即可。

前端可以通过约定的API传参给后台提供一个函数名如callback,后台只要返回callback(data)即可。

一种实现参考这里。这个实现灵感来自于这篇博客

前端请求

前端需要动态创建一个<script>标签,src设置为api并设好传参,同时还要声明一个对应的callback方法,让script返回后可以有效执行。最好在收到数据之后,即callback方法执行之后把创建的<script>标签再清除掉。

一种实现参考这里。这个实现的灵感来自于这篇博客。其中使用promise来处理callback的善后。