1. call 和 apply 的区别是什么,那个性能更好一些
fn.call(obj, 10, 20, 30); fn.allpy(obj, [10, 20, 30]); // call 的性能要比 apply 好一些(尤其是传递给函数的参数超过三个时)所以后期开发的时候,可以使用call 多一点 let arr = [10, 20, 30], obj = {}; function fn (x, y, z) {} fn.allpy(obj, arr); // x = 10 y = 20 z = 30 fn.call(obj, arr); // x = [10, 20, 30] y = z = undefined fn.call(obj, ...arr); // 基于 es6 的展开运算符也可以实现吧数组中的每一项依次传递给函数
2. 自己实现性能测试(仅供参考)
// 任何的代码性能测试都是和测试的环境有关系的,例如 cpu、内存、gpu 等电脑当前性能不会有相同情况,不同浏览器也会导致性能上的不同;console.time() // 可以测试出一段程序执行的时间console.profile() // 在火狐浏览器中安装 FireBug,可以更精准的获取到程序每一个步骤所消耗的时间console.time('A');for (let i = 0; i < 1000000; i++) {};console.timeEnd('A');
3. 实现 (5).add(3).minus(2), 使其输出结果为:6
~ function () { // 每一个方法执行完,都要返回 number 这个类的实例,这样才可以继续调取 number 类原型中的方法(链式调用) function check (n) { n = Number(n); return isNaN(n) ? 0 : n; } function add (n) { n = check(n); return this + n; } function minus (n) { n = check(n); return this - n; } Number.prototype.add = add; Number.prototype.minus = minus; // ["add", "minus"].forEach (item => {Number.prototype[item] = eval(item)});}console.log((5).add(3).minus(2));
4. 箭头函数与普通函数(function 的区别时什么?构造函数(function)可以使用 new 生成实例,那么箭头函数可以吗?为什么?
/** * 箭头函数和普通函数的区别 * 1. 箭头函数语法上比普通函数更加简洁(es6 中每一种函数都可以使用形参赋默认值和剩余运算符) * 2. 箭头函数中没有自己的 this,它的 this 时继承函数所处上下文中的 this(使用call / apply 等任何方式都没无法改变 this 的指向 * 3. 箭头函数中没有 arguments(类数组),只能基于 ...arg 获取传递的参数集合(数组) * 4. 箭头函数不能被 new 执行(因为:箭头函数没有 this 也没有 prototype) */ function Fn () { this.x = 100; } Fn.prototype.getX = function() {}; let f = new Fn; let Fn = () => { this.x = 200; }; let f = new Fn; // Uncaught TypeError: Fn is not a constructor // 回调函数:把一个函数 B 作为实参传递给另外一个函数 A,函数 A 在执行的时候,可以把传进来的函数 B 去执行(执行 N 次,可传值,可改 this) function each (arr, callBack) { callBack:function(item, index) { for (let i = 0; i < arr.length; i++); // 接受回调函数返回的结果,如果时 false,我们结束循环 if (flag === false) { break; } } } each([10, 20, 30, 40], function (item, index){ // this:原始操作数组 if (index > 1) { return false } }); let fn = (...arg) => { // consonle.log(agruments); Uncaught ReferenceRrror:arguments is not defined console.log(arg); }; fn(10, 20, 30);
5. 如何把一个字符串大小取反(大写变小写、小写变大写)如:’aBc’ 变成 ‘AbC’
let str = 'zhufengPEIxun的周老师很帅!语*100 HAHAHA';str = str.replace(/[a-zA-Z]/g, content => { // content:每一次正则匹配的结果 // 验证是否为大写字母:把字母转换为大写后看和之前是否一样,如果一样,之前也是大写的;在 ascll 表中找到大写字母的取值范围进行判断(65-90) content.toUpperCase() === content; content.charCodeAt() > 65 && content.charCodeAt() <=90; return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();});console.log(str);// 实现一个字符串匹配算法,从字符串 S 中,查找是否存在字符串 T ,弱存在返回所在的位置,不存在返回-1 (如果不能基于 indexOf / includes 等内置方法,你会如何处理~ function () { /** * 循环原始字符串中的每一项,让每一项从当前位置向后截取 T.length 个字符,然后和 T 进行比较,如果不 一样,继续循环,如果一样返回当前索引即可(循环结束) */ function myIndexOf (T) { // this:S let lenT = T.length, lenS = this.length, res = -1; if (lenT > lenS) return -1; for (let i = 0; i <= lenS - lenT; i++) { if (this.substr(i, lenT) === T) { res = i; break; } } return res; } // 正则处理 function myIndexOf (T) { // this:S let reg = new RegExp(T), res = reg.exec(this); return res === null ? -1 : res.index; } String.prototype.myIndexOf = myIndexOf();}();let S = "zhufengpeixun", T = "pei";console.log(S.myIndexOf(T));// 对象的属性名不能是一个对象(遇到对象属性名,会默认转换为字符串)// 普通对象 .toStrong() 调取的是 Objcet.prototype 上的方法(这个方法是用来检测数据类型的)obj = {} // obj.toString() [object object]obj[b] = 'b' // obj['[object object]] = 'b'
6. 在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符和url网址的格式
let str = "https://www.zhufengpeixun.com.cn";let reg = /^(?:(http|https|ftp):\/\/)?((?:[\w-]+\.)+[a-z0-9]+)((?:\/[^/?#]*)+)?(\?[^#]+)?(#.+)?$/i;console.log(reg.exec(str));/*** url格式* 1. 协议:// http / https / ftp* 2. 域名* www.zhufengpeixun.cn* zhufengpeixun.cn* kbs.sports.qq.com* kbs.sports.qq.com.cn* 3. 请求路径* /* /index.html* /str/index.html* /stu/* 4. 问号传参* ?xxx=xxx&xxx=xxx* 5. 哈希值* #xxx*/
7. 正则题
/* 编写一条正则,用来验证此规则:一个6~16位的字符串,必须同时包含有大小写字母和数字 */let reg = /(?!^[a-zA-Z]+$)(?!^[0-9]+$)(?!^[a-z0-9]+$)(?!^[A-Z0-9]+$)^[a-zA-Z0-9]{6,16}$/;/* 1-10位:数字、字母、下划线组成字符串,必须有_ */let reg = /(?!^[a-zA-Z0-9]+$)^\w{1,10}$/;/* 字符串中包含 “\w”,但是必须包含_ */let reg = /(?=_)\w+/;
8. 实现一个$attr(name,value)遍历
// 属性为name// 值为value的元素集合// 例如下面示例:function $attr(property, value) { // 获取当前页面中所有的标签 let elements = document.getElementsByTagName('*'), arr = []; // [].forEach.call(elements, item => {}); elements = Array.from(elements); // 把非数组转换为数组 elements.forEach(item => { // 存储的是当前元素 PROPERTY 对应的属性值 let itemValue = item.getAttribute(property); if (property === 'class') { // 样式类属性名要特殊的处理 new RegExp("\\b" + value + "\\b").test(itemValue) ? arr.push(item) : null; return; } if (itemValue === value) { // 获取的值和传递的值校验成功:当前就是我们想要的 arr.push(item); } }); return arr;}console.log($attr('class', 'box')); */
9. 英文字母汉字组成的字符串,用正则给英文单词前后加空格 */
let str = "no作no死,你能你can,不能no哔哔!", reg = /\b[a-z]+\b/ig; str = str.replace(reg, value => { return " " + value + " "; }).trim();// String.prototype.trim/.trimLeft/.trimRight 去除字符串首尾空格 console.log(str);
10. 编写一个程序,将数组扁平化,并去除其中重复部分数据,最终得到一个升序且不重复的数组
let arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];// 使用ES6中提供的 Array.prototype.flat 处理 arr = arr.flat(Infinity);// 把数组直接变为字符串即可(数组 TOSTRING之后,不管你有多少级,最后都会变为以逗号分隔的字符串,没有中括号和所谓的层级了),相当于直接的扁平化了 arr = arr.toString().split(',').map(item => { return Number(item); });// JSON.stringify 也可以扁平化数组 JSON.stringify(arr) : "[[1,2,2],[3,4,5,5],[6,7,8,9,..." replace(/(\[|\])/g, '') : "1,2,2,3,4,5,5,6,7,8,9..." arr = JSON.stringify(arr).replace(/(\[|\])/g, '').split(',').map(item => Number(item));