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));