Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS语法和API —— 一名【合格】前端工程师的自检清单答案整理 #7

Open
akeymo opened this issue Jan 6, 2020 · 0 comments

Comments

@akeymo
Copy link
Owner

akeymo commented Jan 6, 2020

语法和API

理解ECMAScript和JavaScript的关系

完整的JavaScript实现应该由三部分组成:

  • 核心(ECMAScript)
  • 文档对象模型(DOM)
  • 浏览器模型(BOM)

ECMAScript只是定义了基础的语法和语义的标准,跟具体的浏览器环境没有关系。也就是说,ECMAScript来源于JavaScript,又反向作为JavaScript的标准。

熟练应用map、reduce、filter 等高阶函数解决问题

map

  • 生成一个新数组,不修改调用它的原数组本身(可以在callback执行时改变原数组)
// callback:生成新数组元素的函数,使用三个参数
// -- currentValue:callback数组中正在处理的当前元素
// -- index(可选):数组中正在处理的当前元素的索引
// -- array(可选):map中调用的当前数组
// thisArg(可选):执行callback的函数时值被用作this,否则undefined作为this的值

Array.prototype.map(function callback(currentValue[, index[, array]]){
	// Return element for new array
}[, thisArg])

reduce

  • 对数组中的每个元素执行一个提供的reducer函数(升序执行),将其结果汇总为__单个__返回值
// callback:执行数组中每个值的函数,包含四个参数
// -- accumulator:累计器累计回调的返回值,它是上一次调用回调时返回的累积值,或initialValue
// -- currentValue:数组中正在处理的元素
// -- index(可选):数组中正在处理的当前元素的索引。如果提供了initialValue则起始索引为0,否则从1开始
// -- array(可选):调用reduce()的数组
// initialValue(可选):作为第一次调用callback函数时第一个参数的值,如果没有提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用reduce将报错

Array.prototype.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

例子:

  • 计算数组中每个元素出现的次数
     const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
     
     const countedNames = names.reduce((allNames, name)=>{
         if(name in allNames){
             allNames[name]++;
         }else{
             allNames[name] = 1;
         }
     
         return allNames;
     }, {});
    
  • 数组去重
     const myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];
     
     const myOrderedArray = myArray.reduce((accumulator, currentValue) => {
         if(accumulator.indexOf(currentValue) === -1){
             accumulator.push(currentValue);
         }
     
         return accumulator;
     }, []);
    
  • 按顺序执行Promise
     /**
      * Runs promises from array of functions that can return promises
      * in chained manner
      *
      * @param {array} arr - promise arr
      * @return {Object} promise object
      */
     function runPromiseInSequence(arr, input) {
         return arr.reduce(
             (promiseChain, currentFunction) => promiseChain.then(currentFunction),
             Promise.resolve(input)
         );
     }
     
     // promise function 1
     function p1(a) {
         return new Promise((resolve, reject) => {
             resolve(a * 5);
         });
     }
     
     // promise function 2
     function p2(a) {
         return new Promise((resolve, reject) => {
             resolve(a * 2);
         });
     }
     
     // function 3  - will be wrapped in a resolved promise by .then()
     function f3(a) {
         return a * 3;
     }
     
     // promise function 4
     function p4(a) {
         return new Promise((resolve, reject) => {
             resolve(a * 4);
         });
     }
     
     const promiseArr = [p1, p2, f3, p4];
     runPromiseInSequence(promiseArr, 10)
         .then(console.log);   // 1200
    
  • 使用reduce实现map
     if (!Array.prototype.mapUsingReduce) {
         Array.prototype.mapUsingReduce = function (callback, thisArg) {
             return this.reduce(function (mappedArray, currentValue, index, array) {
                 mappedArray[index] = callback.call(thisArg, currentValue, index, array);
                 return mappedArray;
             }, []);
         };
     }
     
     [1, 2, , 3].mapUsingReduce(
         (currentValue, index, array) => currentValue + index + array.length
     ); // [5, 7, , 10]
    

filter

  • 创建一个新数组,其包含通过所提供函数实现的测试的所有元素。如果没有任何数组元素通过测试,则返回空数组
  • 如果没有提供thisArg值,在非严格模式下this是全局对象,严格模式下为undefined
// callback:用来测试数组的每个元素的函数,返回true表示通过保留该元素,返回false则不保留。接受三个参数
// -- element:数组中当前正在处理的元素
// -- index(可选):正在处理的元素在数组中的索引
// -- array(可选):调用了filter的数组本身
// thisArg(可选):执行callback时,用于this的值

Array.prototype.filter(callback(element[, index[, array]])[, thisArg])

setInterval需要注意的点,使用setTimeout实现setInterval

setInterval的注意点

  • setInterval并不考虑任务执行本身所消耗的时间,例如,如果指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95ms,第二次执行就会开始,也就是说这个时间间隔小于设定的时间。如果执行任务长时间不执行完,超过了间隔时间,那么在执行完任务的时候,就会跳过时间间隔又立即执行任务。

使用setTimeout实现setInterval

function mySetInterval(fn, delay) {
    function interval() {
        setTimeout(interval, delay);
        fn();
    }
    setTimeout(interval, delay);
}

JavaScript提供的正则表达式API、可以使用正则表达式(邮箱校验、URL解析、去重等)解决常见问题

JS提供的正则表达式

创建正则表达式有两种方式:const reg = /ab+c/或者const reg = new RegExp('ab+c')
方法:

方法 描述
exec 一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回null
test 一个在字符串中测试是否匹配的RegExp方法,它返回truefalse
match 一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null
matchAll 一个在字符串中执行查找__所有__匹配的String方法,它返回一个迭代器(iterator)
search 一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1
replace 一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串
split 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的String方法

常用的正则表达式

邮箱校验
  • 以大写字母[A-Z]、小写字母[a-z]、数字[0-9]、下滑线[_]、减号[-]及点号[.]开头,并需要重复一次至多次[+]
  • 中间必须包括@符号
  • @之后需要连接大写字母[A-Z]、小写字母[a-z]、数字[0-9]、下滑线[_]、减号[-]及点号[.],并需要重复一次至多次[+]
  • 结尾必须是点号[.]连接2至4位的大小写字母[A-Za-z]{2,4}
const reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/

参考:https://juejin.im/post/5aa637146fb9a028d663d09d

URL解析

解析一个完整的url,返回Object包含域与window.location相同
一个window.location包含的内容:

location = {
    href: '包含完整的url',
    origin: '包含协议到pathname之前的内容',
    protocol: 'url使用的协议,包含末尾的:',
    host: '完整主机名,包含:和端口',
    hostname: '主机名,不包含端口',
    port: '端口号',
    pathname: '服务器上访问资源的路径/开头',
    search: 'query string,?开头',
    hash: '#开头的fragment identifier'
}

答案:

function parseUrl(url) {
    var result = {};
    var keys = ['href', 'origin', 'protocol', 'host',
        'hostname', 'port', 'pathname', 'search', 'hash'];
    var i, len;
    var regexp = /(([^:]+:)\/\/(([^:\/\?#]+)(:\d+)?))(\/[^?#]*)?(\?[^#]*)?(#.*)?/;

    var match = regexp.exec(url);
    console.info('match=', match);

    if (match) {
        for (i = keys.length - 1; i >= 0; --i) {
            result[keys[i]] = match[i] ? match[i] : '';
        }
    }
    console.info('result=', result);
    return result;
}

参考:https://juejin.im/post/5aab72fd518825188038af9b

去重

单行去重:

function DistinctString(s) {
    var a;

    while ((a = s.replace(/(.)(.*?)\1/, "$1$2")) != s) {
        s = a;
    }
    
    return s;
}

参考:https://www.cnblogs.com/xxcanghai/p/5178177.html

JavaScript异常处理的方式,统一的异常处理方案

try-catch

  • 可预见错误区域使用
  • 只能捕获同步的运行时错误
  • 语法错误和异步错误无法捕获

window.onerror

  • 全局监控JS异常
  • 可以捕获同步错误和异步错误
  • 不能捕获语法错误和网络请求异常
  • return true才能阻止异常向上抛出,否则即使知道异常的发生控制台还是会显示Uncaught Error: xxxxx

window.addEventListener

  • 全局监控静态资源异常
  • 资源加载失败,加载资源的元素会触发一个event接口的error事件,并执行该元素上的onerror()处理函数,这些error事件不会向上冒泡到window,但(至少在Firefox)能被单一的window.addEventListener捕获
  • 需要做兼容处理
  • 需要注意避免重复监听

Promise Catch

  • 没有写catchPromise中抛出的错误无法被onerrortry-catch捕获到
  • 为了防止漏写,可以在全局增加一个对unhandledrejection的监听,用来全局监听Uncaught Promise Error。如果要去掉控制台的异常显示,需要添加event.preventDefault()

监控网页崩溃

  • 利用window对象的loadbeforeload

错误上报

  1. 通过Ajax发送数据,但其本身也有可能发生异常,而且可能有跨域问题
  2. 动态创建img标签
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant