[‘1’, ‘2’, ‘3’].map(parseInt) what & why ?

  • map(function callback(currentValue[, index[, array]]))

    这个 callback 一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

  • parseInt(string, radix)

    接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。

答案是:[1,NaN,NaN]

运算过程:

1
2
3
4
5
6
7
8
(1)[("1", "2", "3")].map(parseInt);
(2)[("1", "2", "3")].map((item, index) => {
return parseInt(item, index);
});
//返回
parseInt("1", 0); // 1
parseInt("2", 1); // NaN
parseInt("3", 2); // NaN, 3 不是二进制

在 radix 为 undefined,或者 radix 为 0 或者没有指定的情况下,JavaScript 作如下处理:

  • 如果字符串 string 以”0x”或者”0X”开头, 则基数是 16 (16 进制).
  • 如果字符串 string 以”0”开头, 基数是 8(八进制)或者 10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用 10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出 radix 参数的值。
  • 如果字符串 string 以其它任何值开头,则基数是 10 (十进制)。

什么是防抖和节流?有什么区别?如何实现?

防抖

触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间

  • 思路

    每次触发事件时都取消之前的延时调用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function debounce(fn) {
    let timeout = null; // 创建一个标记用来存放定时器的返回值
    return function () {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    timeout = setTimeout(() => {
    // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
    fn.apply(this, arguments);
    }, 500);
    };
    }
    function sayHi() {
    console.log("防抖成功");
    }

    var inp = document.getElementById("inp");
    inp.addEventListener("input", debounce(sayHi)); // 防抖

apply()函数

function.apply(thisArg, argsArray)

  • thisArg: 要设置函数执行上下文的对象。
  • argsArray: 要传递给函数的参数数组
  • 示例
1
2
3
4
5
6
7
8
9
const obj = {
name: "John Doe",
};

function sayHello() {
console.log(`Hello, my name is ${this.name}.`);
}

sayHello.apply(obj); // 输出: "Hello, my name is John Doe."

在这个例子中,sayHello() 函数的this 关键字被设置为 obj 对象,因此函数内部的 name 属性将引用 obj 对象的 name 属性。

节流

高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率

  • 思路

    每次触发事件时都判断当前是否有等待执行的延时函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function throttle(fn) {
    let canRun = true; // 通过闭包保存一个标记
    return function () {
    if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
    canRun = false; // 立即设置为false
    setTimeout(() => {
    // 将外部传入的函数的执行放在setTimeout中
    fn.apply(this, arguments);
    // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
    canRun = true;
    }, 500);
    };
    }
    function sayHi(e) {
    console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener("resize", throttle(sayHi));

介绍下 Set、Map、WeakSet 和 WeakMap 的区别?

  • Set
    • 成员唯一、无序且不重复
    • [value, value],键值与键名是一致的(或者说只有键值,没有键名)
    • 可以遍历,方法有:add、delete、has
  • WeakSet
    • 成员都是对象
    • 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏
    • 不能遍历,方法有 add、delete、has
  • Map
    • 本质上是键值对的集合,类似集合
    • 可以遍历,方法很多可以跟各种数据格式转换
  • WeakMap
    • 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
    • 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
    • 不能遍历,方法有 get、set、has、delete

有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣 Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()

Object.prototype.toString.call()

每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用 call 或者 apply 方法来改变 toString 方法的执行上下文。

1
2
3
const an = ["Hello", "An"];
an.toString(); // "Hello,An"
Object.prototype.toString.call(an); // "[object Array]"

这种方法对于所有基本的数据类型都能进行判断,即使是 null 和 undefined 。

1
2
3
4
5
6
7
Object.prototype.toString.call("An"); // "[object String]"
Object.prototype.toString.call(1); // "[object Number]"
Object.prototype.toString.call(Symbol(1)); // "[object Symbol]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(function () {}); // "[object Function]"
Object.prototype.toString.call({ name: "An" }); // "[object Object]"

instanceof

instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。

使用 instanceof 判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false。

1
[] instanceof Array; // true

但 instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true。

1
[] instanceof Object; // true

Array.isArray()

  • 功能:用来判断对象是否为数组
  • instanceof 与 isArray
    当检测 Array 实例时,Array.isArray 优于 instanceof ,因为 Array.isArray 可以检测出 iframes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    xArray = window.frames[window.frames.length - 1].Array;
    var arr = new xArray(1, 2, 3); // [1,2,3]
    // Correctly checking for Array
    Array.isArray(arr); // true
    Object.prototype.toString.call(arr); // true
    // Considered harmful, because doesn't work though iframes
    arr instanceof Array; // false
  • Array.isArray() 与 Object.prototype.toString.call()
    Array.isArray()是 ES5 新增的方法,当不存在 Array.isArray() ,可以用 Object.prototype.toString.call() 实现。
    1
    2
    3
    4
    5
    if (!Array.isArray) {
    Array.isArray = function (arg) {
    return Object.prototype.toString.call(arg) === "[object Array]";
    };
    }

介绍模块化发展历程