面试题

Posted on Mar 14, 2024

正则表达式

exec方法

正则.exec(字符串),方法返回一个数组,比普通数组多了index、input、groups等字段

数量

? 意为 0 或 1 次 + 意为 1 次以上 * 意为 0 次以上

array

sort方法

不传参数:如果没有提供 compareFn,所有非 undefined 的数组元素都会被转换为字符串,并按照 UTF-16 码元顺序比较字符串进行排序。例如“banana”会被排列到“cherry”之前。在数值排序中,9 出现在 80 之前,但因为数字会被转换为字符串,在 Unicode 顺序中“80”排在“9”之前。所有的 undefined 元素都会被排序到数组的末尾。sort() 方法保留空槽。如果源数组是稀疏的,则空槽会被移动到数组的末尾,并始终排在所有 undefined 元素的后面。 传参数:(a,b) => number,a-b就是升序,b-a就是降序。

变量提升

变量

console.log(num) 
var num = 1

相当于

var num
console.log(num)
num = 1

函数

//函数声明式:
function foo () {}
//变量形式声明: 
var fn = function () {}

fn()
var fn = function () {
	console.log(1)  
}
// 输出结果:Uncaught TypeError: fn is not a function

foo()
function foo () {
	console.log(2)
}
// 输出结果:2

JS 引擎会搜集所有的变量声明,并且提前让声明生效。而剩下的语句需要等到执行阶段、等到执行到具体的某一句时才会生效。这就是变量提升背后的机制。

变量与函数同名

函数会提升到变量之前,所以同名的函数会被变量覆盖。

forof和forin的区别?

  • for…in 对象 => key,理解对象是一个整体,所以用 in 遍历,拿到的是 key
  • for…of 数组 => value,数组是一个集合,元素是个体,用 of 遍历,拿到的是 value

触摸事件

包括start end move cancel四个touch事件

不会冒泡的事件

resize、error、load、unload、mouseenter、mouseleave、blur、focus

finally

var i = 100;
function foo() {
    bbb: try {
        console.log("position1");
        return i++;  
    } finally {
        break bbb;
    }
    console.log("position2");
    return i;
}
foo();

因为 finally 会是 try/catch 中的 return 失效,所以第一个 return 就失效了,但是 i++ 会执行。所以输出结果是 position1、position2、101

this

this有四种情况

  1. 当在函数调用的时候指向widow
  2. 当方法调用的时候指向调用对象
  3. 当用apply和call上下文调用的时候指向传入的第一个参数
  4. 构造函数调用指向实例对象

同名变量

var foo = {n:1};
(function(foo){
    console.log(foo.n);
    foo.n = 3;
    var foo = {n:2};
    console.log(foo.n);
})(foo);
console.log(foo.n);

局部变量低于形参,let才会涉及到暂时死区,var不会,所以不会报错。 输出结果为1、2、3

call方法

thisArg的值为null或者undefined调用时函数内部的this指向window对象

URL API

URL和URLSearchParams,URLSearchParams是处理query字符串的工具类,可以对它的实例用a.forEach进行遍历,还有has、append、has的方法。

typeof和instanceof的区别

typeofinstanceof 是 JavaScript 中用于检查数据类型的两种不同的方法。

  1. typeof:

    • typeof 是一个操作符,用于确定给定变量的数据类型。
    • 它返回一个表示变量类型的字符串。
    • 常用的返回值包括:“undefined”、“boolean”、“number”、“string”、“object”、“function” 和 “symbol”。
    • typeof 对于数组和 null 的返回值会有些许特殊,数组返回 “object”,null 返回 “object”,这是 JavaScript 语言本身的一个历史遗留问题。
    typeof 42; // "number"
    typeof "hello"; // "string"
    typeof true; // "boolean"
    typeof {}; // "object"
    typeof []; // "object"
    typeof null; // "object" (历史遗留问题)
    typeof function() {}; // "function"
    typeof undefined; // "undefined"
    
  2. instanceof:

    • instanceof 是一个操作符,用于检查一个对象是否属于某个特定的类(构造函数)的实例。
    • 它返回一个布尔值,表示对象是否是该类的实例。
    • 它会检查整个原型链,如果对象是指定类的实例或者是指定类的子类的实例,则返回 true,否则返回 false
    var arr = [];
    arr instanceof Array; // true
    
    function Person(name) {
        this.name = name;
    }
    var john = new Person("John");
    john instanceof Person; // true
    

所以,typeof 用于检查基本数据类型和函数,而 instanceof 则用于检查对象是否是某个类的实例。

__proto__和prototype以及原型和原型链

在 JavaScript 中,每个对象都有一个 __proto__ 属性,用于指向其原型对象。而原型对象又有一个 prototype 属性,用于指向构造函数的原型。理解这些概念有助于理解 JavaScript 中的原型继承和原型链。

  1. __proto__

    • __proto__ 是每个 JavaScript 对象上都有的一个非标准属性(在 ECMAScript 6 中被标准化为 Object.getPrototypeOf 方法),它指向该对象的原型。
    • 通过 __proto__ 属性,对象可以访问其原型链上的属性和方法。
    • 在许多现代浏览器中,可以使用 Object.getPrototypeOf(obj) 方法来获取对象 obj 的原型,而不必直接访问 obj.__proto__
  2. prototype

    • prototype 是函数对象特有的一个属性,当一个函数被定义时,它会自动创建一个 prototype 属性,该属性的值是一个对象,这个对象包含了函数的原型方法和属性。
    • 如果这个函数被用作构造函数(通过 new 关键字调用),则创建的对象将会继承这个 prototype 对象上的属性和方法。
  3. 原型(Prototype)

    • 每个 JavaScript 对象都有一个原型。对象通过原型实现属性和方法的继承。
    • 当访问一个对象的属性或方法时,如果该对象本身没有定义这个属性或方法,则会沿着原型链向上查找,直到找到匹配的属性或方法为止。
    • 对象的原型可以通过 __proto__ 属性来访问。
  4. 原型链(Prototype Chain)

    • JavaScript 中的对象之间通过原型链相互关联。
    • 当需要查找对象的属性或方法时,JavaScript 引擎会沿着对象的原型链向上查找,直到找到匹配的属性或方法为止。
    • 这种原型链的查找机制使得对象可以共享属性和方法,实现了简单而强大的继承模型。

例如,假设有如下代码:

function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function() {
    console.log("Hello, my name is " + this.name);
};

var john = new Person("John");
john.sayHello(); // 输出 "Hello, my name is John"

console.log(john.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true

在这个例子中:

  • john 对象的原型指向 Person.prototype,因此它可以访问 Person.prototype 中定义的 sayHello 方法。
  • Person.prototype 的原型指向 Object.prototype,因为所有的 JavaScript 对象都是从 Object 构造函数派生而来的。

这就是原型和原型链在 JavaScript 中的基本概念和工作原理。

new 函数

function myNew(constructor_) {
    var obj = {};
    obj.__proto__ = constructor_.prototype
    return obj
} 

什么是作用域?

作用域(Scope)是在程序中定义变量的可访问范围,即确定在代码中的哪些部分可以访问或引用变量。在 JavaScript 中,作用域规定了变量的可见性和生命周期。

JavaScript 中有两种主要的作用域:

  1. 全局作用域(Global Scope)

    • 全局作用域是在代码中任何地方都可以访问的作用域。在浏览器环境中,全局作用域通常指的是全局对象 window,而在 Node.js 环境中,全局作用域指的是 global 对象。
    • 在全局作用域中定义的变量或函数可以在程序的任何地方被访问。
  2. 局部作用域(Local Scope)

    • 局部作用域是在函数内部定义的作用域,只能在函数内部访问其中定义的变量或函数。
    • 每次调用函数时都会创建一个新的局部作用域,函数执行完毕后,局部作用域会被销毁,其中定义的变量也会被释放。

JavaScript 中的作用域是通过词法作用域(也称为静态作用域)来实现的,这意味着作用域是由代码中变量的声明位置来确定的,而不是由其运行时的调用位置决定的。因此,在函数内部定义的变量在函数外部是不可见的,而在函数内部可以访问外部作用域的变量。

作用域的概念对于理解变量的可见性、避免命名冲突、优化代码和调试错误等都至关重要。JavaScript 中的作用域规则帮助开发者编写更可维护、更可靠的代码。