Heim  >  Artikel  >  Web-Frontend  >  JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

WBOY
WBOYnach vorne
2022-10-10 14:43:001353Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über JavaScript. Er stellt hauptsächlich eine Zusammenfassung einiger häufiger Fragen im Vorstellungsgespräch dar. Ich hoffe, dass er für alle hilfreich ist.

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

[Verwandte Empfehlungen: JavaScript-Video-Tutorial, Web-Frontend]

1. JS-Grundlagen

1.1 Welche Datentypen gibt es in Js

Es gibt acht Datentypen in JavaScript

Basisdatentyp: Undefiniert, Null, Boolesch, Zahl, Zeichenfolge, Symbol, BigInt.

Komplexer Datentyp: Object

Symbol und BigInt sind neue Datentypen in ES6:

  • Symbol stellt einen einzigartigen und unveränderlichen Datentyp nach der Erstellung dar. Er dient hauptsächlich der Lösung möglicher globaler Variablenkonflikte.

  • BigInt ist ein numerischer Datentyp, der Ganzzahlen in jedem Präzisionsformat darstellen kann. Mit BigInt können große Ganzzahlen sicher gespeichert und verarbeitet werden, auch wenn die Zahl den sicheren Ganzzahlbereich überschreitet, den Number darstellen kann.

1.2 Sprechen Sie über Ihr Verständnis des Heap-Bereichs und des Stapelbereichs.

Im Betriebssystem ist der Speicher in den Stapelbereich und den Heap-Bereich unterteilt.

  • Der Speicher im Stapelbereich ist Wird vom Compiler automatisch zugewiesen und freigegeben. Speichern Sie Funktionsparameterwerte, lokale Variablenwerte usw. Es funktioniert wie ein Stapel in einer Datenstruktur.

  • Der Speicher im Heap-Bereich wird im Allgemeinen vom Entwickler zugewiesen und freigegeben. Wenn der Entwickler ihn nicht freigibt, kann er am Ende des Programms vom Garbage Collection-Mechanismus zurückgefordert werden.

In der Datenstruktur:

  • In der Datenstruktur ist die Zugriffsmethode für Daten im Stapel „First In, Last Out“.

  • Der Heap ist eine Prioritätswarteschlange, die nach Priorität sortiert ist. Die Priorität kann nach Größe angegeben werden.

Datenspeichermethode

  • Der ursprüngliche Datentyp wird direkt im einfachen Datensegment im Stapel gespeichert, der wenig Platz einnimmt und eine feste Größe hat. Da es sich um häufig verwendete Daten handelt, werden sie im Stapel gespeichert Stapel;

  • Der Referenzdatentyp ist ein im Heap gespeichertes Objekt, das viel Platz einnimmt und keine feste Größe hat. Wenn es auf dem Stapel gespeichert wird, wirkt es sich auf die Leistung des Programms aus. Der Referenzdatentyp speichert einen Zeiger auf dem Stapel, der auf die Startadresse der Entität im Heap zeigt. Wenn der Interpreter nach einem Referenzwert sucht, ruft er zunächst seine Adresse auf dem Stapel ab und ruft dann die Entität vom Heap ab.

1.3 Welche Methoden gibt es zur Datentyperkennung?

Dann kann die Methode zur Beurteilung des Datentyps im Allgemeinen über vier gängige Methoden erfolgen: typeof, Instanzof, Konstruktor, toString

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

1.4 Beurteilung des Arrays Welche Methoden gibt es?

  • Urteilen Sie über Object.prototype.toString.call()

  • Urteilen Sie über die Prototypenkette

  • Urteilen Sie über Array.isArray() von ES6

  • Durch Instanz von Urteilen

  • durch Array.prototype.isPrototypeOf

1.5 Der Unterschied zwischen null und undefiniert

Zuallererst sind Undefiniert und Null jeweils grundlegende Datentypen Datentypen haben nur einen Wert, der undefiniert und null ist.

undefiniert bedeutet undefiniert und null bedeutet leeres Objekt. Im Allgemeinen wird undefiniert zurückgegeben, wenn eine Variable deklariert, aber nicht definiert ist. Null wird hauptsächlich verwendet, um einigen Variablen Werte zuzuweisen, die möglicherweise Objekte als Initialisierung zurückgeben.

undefiniert ist kein reserviertes Wort in JavaScript, was bedeutet, dass Sie undefiniert als Variablennamen verwenden können. Dies ist jedoch sehr gefährlich und beeinträchtigt die Beurteilung undefinierter Werte. Mit einigen Methoden können wir sichere undefinierte Werte erhalten, z. B. void 0.

Wenn typeof zur Beurteilung dieser beiden Typen verwendet wird, gibt die Null-Typisierung „Objekt“ zurück, was ein historisches Problem darstellt. Gibt „true“ zurück, wenn ein doppeltes Gleichheitszeichen zum Vergleich zweier Wertetypen verwendet wird, und gibt „false“ zurück, wenn ein dreifaches Gleichheitszeichen verwendet wird.

1.6 Was ist das Ergebnis von typeof null und warum? Das Ergebnis von

typeof null ist Object.

In der ersten Version von JavaScript wurden alle Werte in 32-Bit-Einheiten gespeichert, und jede Einheit enthielt ein kleines Typ-Tag (1-3 Bit) und die tatsächlichen Daten des zu speichernden aktuellen Werts. Typbezeichnungen werden in den unteren Bits jeder Zelle gespeichert und es gibt fünf Datentypen:

000: object   - 当前存储的数据指向一个对象。
  1: int      - 当前存储的数据是一个 31 位的有符号整数。
010: double   - 当前存储的数据指向一个双精度的浮点数。
100: string   - 当前存储的数据指向一个字符串。
110: boolean  - 当前存储的数据是布尔值。

Wenn das niedrigste Bit 1 ist, beträgt die Länge des Typetiketten-Flags nur ein Bit. Wenn das niedrigste Bit 0 ist, beträgt die Länge des Typetiketten-Flags drei Bits, wodurch zwei zusätzliche Bits zum Speichern der anderen vier Daten bereitgestellt werden Typen. Länge.

Es gibt zwei spezielle Datentypen:

  • undefinierter Wert ist (-2)30 (eine Zahl außerhalb des Bereichs von Ganzzahlen);

  • null-Wert ist ein Maschinencode-NULL-Zeiger (der Wert eines Nullzeigers). ist alles 0)

Das bedeutet, dass die Typbezeichnung von null ebenfalls 000 ist, was mit der Typbezeichnung von Object identisch ist, sodass es als Objekt beurteilt wird.

1,7 Warum 0,1+0,2 ! == 0,3, wie man es gleich macht (Genauigkeit geht verloren)

Computer speichern Daten binär, wenn der Computer also 0,1+0,2 berechnet, berechnet er tatsächlich die Binärsumme von zwei Zahlen.

In JS gibt es nur einen Zahlentyp: Zahl. Seine Implementierung folgt dem IEEE 754-Standard und verwendet eine 64-Bit-Festlänge, um ihn darzustellen, was eine standardmäßige Gleitkommazahl mit doppelter Genauigkeit ist. In der binären wissenschaftlichen Schreibweise kann der Dezimalteil einer Gleitkommazahl mit doppelter Genauigkeit nur bis zu 52 Ziffern plus der vorherigen 1 behalten, tatsächlich bleiben 53 signifikante Ziffern erhalten. Die restlichen Ziffern müssen verworfen werden und der Rundung auf „0“ folgen 1"-Prinzip. Im Prinzip.

Nach diesem Prinzip ergibt die Addition der Binärzahlen 0,1 und 0,2 und deren Umwandlung in Dezimalzahlen: 0,30000000000000004. Also nicht gleich

Die Lösung besteht darin, eine Fehlermarge festzulegen, die oft als „Maschinenpräzision“ bezeichnet wird. Für JavaScript beträgt dieser Wert normalerweise 2-52. In ES6 wird das Attribut Number.EPSILON bereitgestellt. Beurteilen Sie einfach, ob 0,1+0,2-0,3 kleiner ist als Number.EPSILON. dann kann es als 0,1+0,2 ===0,3

function numberepsilon(arg1,arg2){                   
  return Math.abs(arg1 - arg2) < Number.EPSILON;        
}        
console.log(numberepsilon(0.1 + 0.2, 0.3)); // true

1,8 beurteilt werden. Wie erhält man einen sicheren undefinierten Wert?

Da undefiniert ein Bezeichner ist, kann er als Variable verwendet und zugewiesen werden. Dies wirkt sich jedoch auf die normale Beurteilung von undefiniert aus. Der Ausdruck void ___ hat keinen Rückgabewert, daher ist das Ergebnis undefiniert. void ändert das Ergebnis des Ausdrucks nicht, sondern führt lediglich dazu, dass der Ausdruck keinen Wert zurückgibt. Sie können also void 0 verwenden, um undefiniert zu werden.

1.9 Was ist das Ergebnis von typeof NaN?

NaN bedeutet „keine Zahl“, NaN ist ein „Sentinel-Wert“ (regulärer Wert mit besonderem Zweck), der zur Anzeige von Fehlerbedingungen in numerischen Typen verwendet wird, d. h. „Mathematik durchführen“. Der Vorgang war nicht erfolgreich ist das Ergebnis, das nach einem Fehler zurückgegeben wird.“

typeof NaN; // "number"

NaN ​​​​ist ein besonderer Wert, der sich selbst nicht gleicht und der einzige nicht reflexive Wert ist. Das sogenannte Irreflexiv bedeutet, dass NaN niemandem gleich ist, auch sich selbst nicht, sondern in NaN! = NaN gibt true zurück

1.10 Was ist der Unterschied zwischen den Funktionen isNaN und Number.isNaN?

Nach dem Empfang eines Parameters versucht die isNaN-Funktion, den Parameter in einen numerischen Wert umzuwandeln, der nicht in einen numerischen Wert umgewandelt werden kann. Daher wird er zurückgegeben, wenn ein nicht numerischer Wert übergeben wird wird auch true zurückgeben, was sich auf die Beurteilung von NaN auswirkt.

Die Funktion Number.isNaN ermittelt zunächst, ob es sich bei dem eingehenden Parameter um eine Zahl handelt, und ermittelt dann weiterhin, ob es sich um eine NaN-Datentypkonvertierung handelt .

1.11 Was sind die Casting-Regeln für den ==-Operator?

Wenn bei == die Typen der beiden Vergleichsparteien unterschiedlich sind, wird eine Typkonvertierung durchgeführt. Wenn x und y verglichen werden, um festzustellen, ob sie gleich sind, wird der folgende Beurteilungsprozess durchgeführt:

Zunächst wird beurteilt, ob die beiden Typen gleich sind. Wenn sie gleich sind, wird die Größe der beiden beurteilt wird verglichen;

Wenn die Typen nicht identisch sind, wird zunächst festgestellt, ob null und undefiniert verglichen werden. Wenn ja, wird true zurückgegeben, um festzustellen, ob die beiden Typen identisch sind Wenn ja, wird die Zeichenfolge in eine Zahl umgewandelt, um zu bestimmen, ob eine davon boolesch ist. Wenn ja, wird sie in eine Zahl umgewandelt und dann beurteilt, ob eine der Parteien eine ist Objekt und das andere ist eine Zeichenfolge, eine Zahl oder ein Symbol. Wenn ja, wird das Objekt in den ursprünglichen Typ konvertiert und dann beurteilt andere Werttypen in Strings konvertieren?

Typen Null und Undefiniert, null wird in „null“ konvertiert, undefiniert wird in „undefiniert“ konvertiert,

Boolean-Typ, true wird in „true“ konvertiert, false wird in „false“ konvertiert.

Zahlentypwerte werden direkt konvertiert, aber diese sehr kleinen und großen Zahlen verwenden die Exponentialform.

Symboltypwerte werden direkt konvertiert, aber nur explizite Umwandlungen sind zulässig. Die Verwendung impliziter Umwandlungen führt zu einem Fehler.

对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

1.13. 其他值类型转成数字的转换规则?

Undefined 类型的值转换为 NaN。

Null 类型的值转换为 0。

Boolean 类型的值,true 转换为 1,false 转换为 0。

String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。

Symbol 类型的值不能转换为数字,会报错。

对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

为了将值转换为相应的基本类型值, 隐式转换会首先检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。

如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。

1.14 其他值类型转成布尔类型的转换规则?

以下这些是假值: undefined 、 null 、 false 、 +0、-0 和 NaN 、 ""

假值的布尔强制类型转换结果为 false。从逻辑上说,假值列表以外的都应该是真值。

1.15. || 和 && 操作符的返回值?

|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先强制转换为布尔类型,然后再执行条件判断。

  • 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数的值,如果为 false 就返回第二个操作数的值。

  • && 则相反,如果条件判断结果为 true 就返回第二个操作数的值,如果为 false 就返回第一个操作数的值。

|| 和 && 返回它们其中一个操作数的值,而非条件判断的结果

1.16. Object.is() 与比较操作符 “===”、“==” 的区别?

  • 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。

  • 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。

  • 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

1.17. 什么是 JavaScript 中的包装类型?

在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象。如:

const a = "abc";
a.length; // 3

在访问'abc'.length时,JavaScript 将'abc'在后台转换成String('abc'),然后再访问其length属性。

1.18 Js中隐式转换规则

在 if 语句、逻辑语句、数学运算逻辑、== 等情况下都可能出现隐式类型转换。

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

坑: 判断时, 尽量不要用 = = , 要用 = = = ( 两个等号判断, 如果类型不同, 默认会进行隐式类型转换再比较)

1.19 说说你对this的理解

this是一个在运行时才进行绑定的引用,在不同的情况下它可能会被绑定不同的对象。

1.20 如何判断 this 的指向

第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。

第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。

第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。

第四种是 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

this绑定的优先级

new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级

1.21 Map和Object的区别

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

1.22 说说你对JSON的理解

JSON 是一种基于文本的轻量级的数据交换格式。它可以被任何的编程语言读取和作为数据格式来传递。

在项目开发中,使用 JSON 作为前后端数据交换的方式。在前端通过将一个符合 JSON 格式的数据结构序列化为 JSON 字符串,然后将它传递到后端,后端通过 JSON 格式的字符串解析后生成对应的数据结构,以此来实现前后端数据的一个传递。

因为 JSON 的语法是基于 js 的,因此很容易将 JSON 和 js 中的对象弄混,但是应该注意的是 JSON 和 js 中的对象不是一回事,JSON 中对象格式更加严格,比如说在 JSON 中属性值不能为函数,不能出现 NaN 这样的属性值等,因此大多数的 js 对象是不符合 JSON 对象的格式的。

在 js 中提供了两个函数来实现 js 数据结构和 JSON 格式的转换处理,

JSON.stringify 函数,通过传入一个符合 JSON 格式的数据结构,将其转换为一个 JSON 字符串。如果传入的数据结构不符合 JSON 格式,那么在序列化的时候会对这些值进行对应的特殊处理,使其符合规范。在前端向后端发送数据时,可以调用这个函数将数据对象转化为 JSON 格式的字符串。

JSON.parse() 函数,这个函数用来将 JSON 格式的字符串转换为一个 js 数据结构,如果传入的字符串不是标准的 JSON 格式的字符串的话,将会抛出错误。当从后端接收到 JSON 格式的字符串时,可以通过这个方法来将其解析为一个 js 数据结构,以此来进行数据的访问。

1.222 String和JSON.stringify的区别

console.log(String("abc")); // abc
console.log(JSON.stringify("abc")); // "abc"
console.log(String({ key: "value" })); // [object Object]
console.log(JSON.stringify({ key: "value" })); // {"key":"value"}
console.log(String([1, 2, 3])); // 1,2,3
console.log(JSON.stringify([1, 2, 3])); // [1,2,3]
const obj = {
    title: "devpoint",
    toString() {
        return "obj";
    },
};
console.log(String(obj)); // obj
console.log(JSON.stringify(obj)); // {"title":"devpoint"}

当需要将一个数组和一个普通对象转换为字符串时,经常使用JSON.stringify。

如果需要对象的toString方法被重写,则需要使用String()。

在其他情况下,使用String()将变量转换为字符串。

1.23 什么是伪数组(类数组)

一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法。

常见的类数组对象有 arguments 和 DOM 方法的返回结果,还有一个函数也可以被看作是类数组对象,因为它含有 length 属性值,代表可接收的参数个数。

1.24 类数组转换成数组的方法有哪些

常见的类数组转换为数组的方法有这样几种:

通过 call 调用数组的 slice 方法来实现转换

Array.prototype.slice.call(arrayLike);

通过 call 调用数组的 splice 方法来实现转换

Array.prototype.splice.call(arrayLike, 0);

通过 apply 调用数组的 concat 方法来实现转换

Array.prototype.concat.apply([], arrayLike);

通过 Array.from 方法来实现转换

Array.from(arrayLike);

1.25 Unicode、UTF-8、UTF-16、UTF-32的区别?

Unicode 是编码字符集(字符集),而UTF-8、UTF-16、UTF-32是字符集编码(编码规则);

UTF-16 使用变长码元序列的编码方式,相较于定长码元序列的UTF-32算法更复杂,甚至比同样是变长码元序列的UTF-8也更为复杂,因为其引入了独特的代理对这样的代理机制;

UTF-8需要判断每个字节中的开头标志信息,所以如果某个字节在传送过程中出错了,就会导致后面的字节也会解析出错;而UTF-16不会判断开头标志,即使错也只会错一个字符,所以容错能力教强;

如果字符内容全部英文或英文与其他文字混合,但英文占绝大部分,那么用UTF-8就比UTF-16节省了很多空间;而如果字符内容全部是中文这样类似的字符或者混合字符中中文占绝大多数,那么UTF-16就占优势了,可以节省很多空间;

1.26 常见的位运算符有哪些?其计算规则是什么?

现代计算机中数据都是以二进制的形式存储的,即0、1两种状态,计算机对二进制数据进行的运算加减乘除等都是叫位运算,即将符号位共同参与运算的运算。

常见的位运算有以下几种:

JavaScript-Interviewzusammenfassung mit 10.000 Wörtern

1.27 为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?

arguments是一个对象,它的属性是从 0 开始依次递增的数字,还有callee和length等属性,与数组相似;但是它却没有数组常见的方法属性,如forEach, reduce等,所以叫它们类数组。

要遍历类数组,有三个方法:

(1)将数组的方法应用到类数组上,这时候就可以使用call和apply方法,如:

function foo(){ 
  Array.prototype.forEach.call(arguments, a => console.log(a))
}

(2)使用Array.from方法将类数组转化成数组:‌

function foo(){ 
  const arrArgs = Array.from(arguments) 
  arrArgs.forEach(a => console.log(a))
}

(3)使用展开运算符将类数组转化成数组

function foo(){ 
    const arrArgs = [...arguments] 
    arrArgs.forEach(a => console.log(a)) 
}

1.28 escape、encodeURI、encodeURIComponent 的区别

encodeURI 是对整个 URI 进行转义,将 URI 中的非法字符转换为合法字符,所以对于一些在 URI 中有特殊意义的字符不会进行转义。

encodeURIComponent 是对 URI 的组成部分进行转义,所以一些特殊字符也会得到转义。

escape 和 encodeURI 的作用相同,不过它们对于 unicode 编码为 0xff 之外字符的时候会有区别,escape 是直接在字符的 unicode 编码前加上 %u,而 encodeURI 首先会将字符转换为 UTF-8 的格式,再在每个字节前加上 %。

1.29 什么是尾调用,使用尾调用有什么好处?

尾调用指的是函数的最后一步调用另一个函数。代码执行是基于执行栈的,所以当在一个函数里调用另一个函数时,会保留当前的执行上下文,然后再新建另外一个执行上下文加入栈中。使用尾调用的话,因为已经是函数的最后一步,所以这时可以不必再保留当前的执行上下文,从而节省了内存,这就是尾调用优化。

但是 ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。

1.30 use strict是什么? 它有什么用?

use strict 是一种 ECMAscript5 添加的(严格模式)运行模式,这种模式使得 Javascript 在更严格的条件下运行。设立严格模式的目的如下:

消除 Javascript 语法的不合理、不严谨之处,减少怪异行为;

消除代码运行的不安全之处,保证代码运行的安全;

提高编译器效率,增加运行速度;

为未来新版本的 Javascript 做好铺垫。

区别:

禁止使用 with 语句。

禁止 this 关键字指向全局对象。

对象不能有重名的属性。

1.31 如何判断一个对象是否属于某个类?

第一种方式,使用 instanceof 运算符来判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。

第二种方式,通过对象的 constructor 属性来判断,对象的 constructor 属性指向该对象的构造函数,但是这种方式不是很安全,因为 constructor 属性可以被改写。

第三种方式,如果需要判断的是某个内置的引用类型的话,可以使用 Object.prototype.toString() 方法来打印对象的[[Class]] 属性来进行判断。

1.32 强类型语言和弱类型语言的区别

强类型语言:强类型语言也称为强类型定义语言,是一种总是强制类型定义的语言,要求变量的使用要严格符合定义,所有变量都必须先定义后使用。Java和C++等语言都是强制类型定义的,也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。例如你有一个整数,如果不显式地进行转换,你不能将其视为一个字符串。

Schwach typisierte Sprache: Schwach typisierte Sprache wird auch als schwach typisierte Definitionssprache bezeichnet, was das Gegenteil einer stark typisierten Definition ist. Die JavaScript-Sprache ist eine schwach typisierte Sprache. Einfach ausgedrückt handelt es sich um eine Sprache, in der Variablentypen ignoriert werden können. Beispielsweise ist JavaScript schwach typisiert. In JavaScript können Sie die Zeichenfolge „12“ und die Ganzzahl 3 verketten, um die Zeichenfolge „123“ zu erhalten, und beim Hinzufügen wird eine erzwungene Typkonvertierung durchgeführt.

Vergleich der beiden: Stark typisierte Sprachen sind möglicherweise etwas schneller als schwach typisierte Sprachen, aber die Genauigkeit, die stark typisierte Sprachen mit sich bringen, kann effektiv dazu beitragen, viele Fehler zu vermeiden.

1.33 Der Unterschied zwischen interpretierten Sprachen und kompilierten Sprachen

(1) Interpretierte Sprachen verwenden einen speziellen Interpreter, um das Quellprogramm Zeile für Zeile in Maschinencode für eine bestimmte Plattform zu interpretieren und auszuführen sofort. Der Code wird vom Interpreter bei der Ausführung dynamisch übersetzt und Zeile für Zeile ausgeführt, anstatt vor der Ausführung übersetzt zu werden. Interpretierte Sprachen müssen nicht im Voraus kompiliert werden. Sie interpretieren den Quellcode direkt in Maschinencode und führen ihn sofort aus. Solange eine bestimmte Plattform einen entsprechenden Interpreter bereitstellt, kann das Programm ausgeführt werden. Seine Eigenschaften werden wie folgt zusammengefasst:

Jedes Mal, wenn eine interpretierte Sprache ausgeführt wird, muss der Quellcode in Maschinencode interpretiert und ausgeführt werden, was ineffizient ist.

Solange die Plattform den entsprechenden Interpreter bereitstellt, kann der Quellcode sein ausgeführt werden, sodass die Transplantation des Quellprogramms erleichtert werden kann ;

JavaScript, Python usw. sind interpretierte Sprachen.

(2) Kompilierte Sprachen verwenden einen speziellen Compiler, um Hochsprachen-Quellcode für eine bestimmte Plattform in Maschinencode zu kompilieren, der von der Hardware der Plattform ausgeführt werden kann, und ihn in eine ausführbare Datei zu verpacken, die von der Plattform erkannt werden kann . Format sexueller Prozeduren. Bevor ein in einer kompilierten Sprache geschriebenes Programm ausgeführt wird, ist ein spezieller Kompilierungsprozess erforderlich, um den Quellcode in eine Maschinensprachendatei zu kompilieren, z. B. eine Datei im EXE-Format. Bei der zukünftigen Ausführung können Sie das Kompilierungsergebnis direkt verwenden, z als direktes Ausführen des exe-Dokuments. Da sie nur einmal kompiliert werden muss und bei späterer Ausführung nicht kompiliert werden muss, weisen kompilierte Sprachen eine hohe Ausführungseffizienz auf. Seine Eigenschaften lassen sich wie folgt zusammenfassen:

Es wird gleichzeitig in plattformbezogene Maschinensprachendateien kompiliert, ist beim Ausführen von der Entwicklungsumgebung getrennt und weist eine hohe Betriebseffizienz auf.

Es bezieht sich auf eine bestimmte Plattform und kann dies im Allgemeinen nicht sein auf andere Plattformen übertragen;

C, C++ usw. gehören zur kompilierten Sprache.

Der Hauptunterschied zwischen den beiden besteht darin, dass das erstere Quellprogramm nach der Kompilierung auf der Plattform ausgeführt werden kann, während das letztere während des Betriebs kompiliert wird. Daher läuft Ersteres schnell und Letzteres bietet eine gute plattformübergreifende Leistung.

1.34 Der Unterschied zwischen for...in und for...of

for...of ist eine neue Traversal-Methode in ES6, die das Traversieren einer Datenstruktur (Array, Objekt usw.) ermöglicht. Enthält die Iteratorschnittstelle und gibt zurück. Der Unterschied zwischen dem Wert jedes Elements und for...in in ES3 ist wie folgt: for... von Durchläufen, um den Schlüsselwert des Objekts zu erhalten, während for... in den Schlüssel erhält Name des Objekts;

for...in durchläuft das gesamte Objekt. Die Prototypenkette hat eine sehr schlechte Leistung und wird nicht empfohlen, während for...of nur das aktuelle Objekt und nicht die Prototypenkette durchquert ;

Für die Array-Durchquerung gibt for...in alle aufzählbaren Eigenschaften im Array zurück (einschließlich der aufgezählten Attribute in der Prototypenkette), for...of gibt nur den Attributwert zurück, der dem Index des Arrays entspricht;

Zusammenfassung: Die for...in-Schleife dient hauptsächlich zum Durchlaufen von Objekten und ist nicht zum Durchlaufen von Arrays geeignet. Die for...of-Schleife kann zum Durchlaufen von Arrays, arrayähnlichen Objekten, Zeichenfolgen, Mengen und Karten verwendet werden und Generatorobjekte.

1.35 Der Unterschied zwischen Ajax, Axios und Fetch (1) AJAX Ajax ist „AsynchronousJavascriptAndXML“ (asynchrones JavaScript und XML), was sich auf eine Webentwicklungstechnologie zum Erstellen interaktiver Webanwendungen bezieht. Dabei handelt es sich um eine Technologie, die Teile einer Webseite aktualisieren kann, ohne die gesamte Webseite neu laden zu müssen. Ajax ermöglicht die asynchrone Aktualisierung von Webseiten, indem im Hintergrund eine kleine Datenmenge mit dem Server ausgetauscht wird. Das bedeutet, dass Teile einer Webseite aktualisiert werden können, ohne dass die gesamte Seite neu geladen werden muss. Herkömmliche Webseiten (die kein Ajax verwenden) müssen die gesamte Webseite neu laden, wenn der Inhalt aktualisiert werden muss. Seine Mängel sind wie folgt:

    selbst ist auf die MVC-Programmierung ausgerichtet und entspricht nicht dem Trend der Front-End-MVVM
  • wird auf Basis von nativem XHR entwickelt
  • entspricht nicht dem Grundsatz der Interessenstrennung (Separation of Concerns).
  • Die Konfigurations- und Aufrufmethoden sind sehr verwirrend und das ereignisbasierte asynchrone Modell ist unfreundlich.
  • (2) Fetch fetch ist als Ersatz für AJAX bekannt. Es erschien in ES6 und verwendet das Promise-Objekt in ES6. Fetch basiert auf Versprechen. Die Codestruktur von Fetch ist viel einfacher als die von Ajax. Fetch ist keine weitere Kapselung von Ajax, sondern natives JS, das das XMLHttpRequest-Objekt nicht verwendet.

Vorteile von Fetch:

    Die Syntax ist präziser und semantischer.
  • Basiert auf der Standard-Promise-Implementierung und unterstützt Async/Await.
  • Es ist auf niedrigerer Ebene und bietet umfangreiche APIs (Anfrage, Antwort).
  • Detachment XHR ist eine neue Implementierungsmethode in der ES-Spezifikation
  • Nachteile von Fetch:
  • fetch meldet nur Fehler für Netzwerkanfragen. Wenn der Server 400- und 500-Fehlercodes zurückgibt, wird er nicht abgelehnt. Nur wenn Netzwerkfehler dazu führen, dass die Anfrage nicht abgeschlossen werden kann wird abgelehnt.

  • fetch hat standardmäßig keine Cookies, Sie müssen Konfigurationselemente hinzufügen: fetch(url, {credentials: 'include'})

  • fetch unterstützt keinen Abbruch, unterstützt keine Timeout-Steuerung, verwenden Sie setTimeout und Promise.reject-Implementierung Die Timeout-Kontrolle verhindert nicht, dass der Anforderungsprozess im Hintergrund weiterläuft, was zu einer Verschwendung von Datenverkehr führt. Fetch hat keine Möglichkeit, den Fortschritt der Anforderung nativ zu überwachen, XHR kann dies jedoch

    (3) Axios Axios ist ein Promise-basierter Kapselungs-HTTP-Client. Seine Eigenschaften sind wie folgt:
  • Der Browser initiiert XMLHttpRequests-Anfragen.

Knoten initiiert HTTP-Anfragen. Unterstützt Promise. API n zu Anfragen und Retouren
  • Anfragen und Retouren Konvertieren
  • Anfrage abbrechen
  • JSON-Daten automatisch konvertieren
  • Der Client unterstützt die Abwehr von XSRF-Angriffen
  • 1.36 Was sind die Traversierungsmethoden von Arrays

  • 1.37 forEach Was ist der Unterschied zwischen der Map-Methode und der Map-Methode? Der Unterschied zwischen den beiden ist wie folgt: Die forEach()-Methode führt die aus Für jedes Element wird eine Funktion bereitgestellt, und die Operation an den Daten ändert den ursprünglichen Array-Wert. Die Methode

  • map() ändert nicht den Wert des ursprünglichen Arrays, sondern gibt einen neuen Array-Wert zurück ​​im neuen Array sind die Werte des ursprünglichen Arrays nach dem Aufruf der Funktion;

1.38 Erzählen Sie mir von Ihrer Meinung zu Qian. Verständnis von Kopie und tiefer Kopie

Flache KopieJavaScript-Interviewzusammenfassung mit 10.000 Wörtern

Flache Kopie bezieht sich auf die Erstellung neuer Daten. Diese Daten haben eine exakte Kopie des ursprünglichen Datenattributwerts.

Wenn es sich bei dem Attribut um einen Basistyp handelt, wird der Basistypwert kopiert. Wenn das Attribut ein Referenztyp ist, wird die Speicheradresse kopiert. Das heißt, die flache Kopie kopiert eine Ebene und der tiefe Referenztyp teilt die Speicheradresse. Gemeinsame flache Kopie: Object.assign Object.create

slice

concat()

Expand-Operator

deep copy

deep copy öffnet einen neuen Stapel. Die beiden Objekte sind gleich vervollständigt, entsprechen aber zwei Verschiedene Adressen. Das Ändern der Eigenschaften eines Objekts ändert nicht die Eigenschaften eines anderen Objekts: ( )

Handgeschriebene Schleifenrekursion

  • 1.39 Nachteile von JSON.stringify Deep Copy

  • Wenn in obj ein Zeitobjekt vorhanden ist, wird das Ergebnis von JSON.stringify und dann JSON.parse die Zeit sein sei nur eine Zeichenfolge Die Form, nicht die Form des Objekts

  • Wenn RegExp in obj vorhanden ist, wird es als leeres Objekt gedruckt
  • Wenn das Objekt eine Funktion oder undefiniert enthält, wird es direkt verworfen

  • Wenn es in JSON ein Objekt gibt, das vom Konstruktor generiert wird, geht die Konstruktion des Objekts verloren
  • 1.40 Kennen Sie Lodash? Welche gemeinsamen APIs gibt es?
  • Lodash ist eine konsistente, modulare und leistungsstarke JavaScript-Dienstprogrammbibliothek.

_.cloneDeep Deep Copy

_.reject entfernt ein Element basierend auf Bedingungen.

_.drop(array, [n=1] ) Funktion: Entfernen Sie die ersten n Elemente im Array und geben Sie dann die verbleibenden Teile zurück.

  • 1.41 LHS- und RHS-Abfrage

  • LHS (linke Seite ) und RHS (rechte Seite) sind zwei Möglichkeiten für die JS-Engine, Variablen während der Codeausführungsphase zu bedienen. Der Unterschied zwischen den beiden besteht darin, dass der Zweck der Variablenabfrage die Variablenzuweisung oder -abfrage ist.

  • LHS kann so verstanden werden, dass sich die Variable auf der linken Seite des Zuweisungsoperators (=) befindet, zum Beispiel a = 1. Der Zweck der Suche der aktuellen Engine nach Variable a ist die Variablenzuweisung. In diesem Fall ist es der Engine egal, was der ursprüngliche Wert der Variablen a ist, sie weist der Variablen a lediglich den Wert 1 zu.
  • RHS kann als Variable auf der rechten Seite des Zuweisungsoperators (=) verstanden werden, zum Beispiel: console.log(a) Der Zweck der Suche der Engine nach Variable a besteht darin, sie abzufragen Wert, der der Variablen a entspricht. Dann können Sie ihn ausdrucken.

  • 1.42 Inwiefern ist Includes besser als indexOf?

includes kann NaN erkennen, indexOf kann NaN nicht erkennen, include verwendet Number.isNaN intern, um NaN abzugleichen1.43 Was ist der Unterschied zwischen AMD und CMD?

1,44 (a == 1 && a == 2 && a == 3) Ist es möglich, wahr zu sein?

方案一:重写toString()或valueOf()

let a = {  
    i: 1,  
    toString: function () {    
        return a.i++;  
    }
}
console.log(a == 1 && a == 2 && a == 3); // true

方案二:数组

数组的toString接口默认调用数组的join方法,重写join方法。定义a为数字,每次比较时就会调用 toString()方法,我们把数组的shift方法覆盖toString即可:

let a = [1,2,3];
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true

当然把toString改为valueOf也是一样效果:

let a = [1,2,3];
a. valueOf  = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true

方案三:使用Object.defineProperty()

Object.defineProperty()用于定义对象中的属性,接收三个参数:object对象、对象中的属性,属性描述符。属性描述符中get:访问该属性时自动调用。

var  _a = 1;
Object.defineProperty(this,&#39;a&#39;,{  
    get:function(){    
        return _a++  
    }
})
console.log(a===1 && a===2 && a===3)//true

1.45 JS中的 MUL 函数

MUL表示数的简单乘法。在这种技术中,将一个值作为参数传递给一个函数,而该函数将返回另一个函数,将第二个值传递给该函数,然后重复继续。例如:xyz可以表示为

const mul = x => y => z => x * y * z
console.log(mul(1)(2)(3)) // 6

1.46 深度遍历广度遍历的区别?

对于算法来说 无非就是时间换空间 空间换时间

1、深度优先不需要记住所有的节点, 所以占用空间小, 而广度优先需要先记录所有的节点占用空间大

2、深度优先有回溯的操作(没有路走了需要回头)所以相对而言时间会长一点

3、深度优先采用的是堆栈的形式, 即先进后出

4、广度优先则采用的是队列的形式, 即先进先出

1.47 JS中的设计模式有哪些?

  • 单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。

  • 策略模式

定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。

  • 代理模式

为一个对象提供一个代用品或占位符,以便控制对它的访问。

  • 中介者模式

通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,当其中的一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。

  • 装饰者模式

在不改变对象自身的基础上,在程序运行期间给对象动态地添加方法。

1.48 forEach如何跳出循环?

forEach是不能通过break或者return来实现跳出循环的,为什么呢?实现过forEach的同学应该都知道,forEach的的回调函数形成了一个作用域,在里面使用return并不会跳出,只会被当做continue

可以利用try catch

  function getItemById(arr, id) {
        var item = null;
        try {
            arr.forEach(function (curItem, i) {
                if (curItem.id == id) {
                    item = curItem;
                    throw Error();
                }
            })
        } catch (e) {
        }
        return item;
    }

1.49 JS中如何将页面重定向到另一个页面?

1、使用 location.href:window.location.href ="url"

2、使用 location.replace: window.location.replace("url");

1.50 移动端如何实现上拉加载,下拉刷新?

上拉加载

上拉加载的本质是页面触底,或者快要触底时的动作

判断页面触底我们需要先了解一下下面几个属性

scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值

clientHeight:它是一个定值,表示屏幕可视区域的高度;

scrollHeight:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body所有元素的总长度(包括body元素自身的padding)

综上我们得出一个触底公式:

scrollTop + clientHeight >= scrollHeight

下拉刷新

下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作

关于下拉刷新的原生实现,主要分成三步:

监听原生touchstart事件,记录其初始位置的值,e.touches[0].pageY;

监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;

监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY重设为0,元素回到初始位置

1.51 JS 中的数组和函数在内存中是如何存储的?

Array-Speicher in JavaScript muss grob in zwei Situationen unterteilt werden:

Arrays mit demselben Datentyp weisen kontinuierlichen Speicherplatz zu.

Arrays mit nicht demselben Datentyp verwenden Hash-Mapping, um Speicherplatz zuzuweisen.

Warme Erinnerung: Ja Stellen Sie sich vor, dass der kontinuierliche Speicherplatz nur den Speicherort basierend auf dem Index (Zeiger) direkt berechnen muss. Wenn es sich um eine Hash-Map handelt, müssen Sie zuerst den Indexwert berechnen. Wenn dann ein Konflikt im Indexwert vorliegt, müssen Sie eine zweite Suche durchführen (Sie müssen wissen, wie der Hash gespeichert wird).

2. Abschluss und Geltungsbereich

2.1 Was ist Abschluss?

Offizielle Aussage: Ein Abschluss bezieht sich auf eine Funktion, die das Recht hat, auf Variablen im Gültigkeitsbereich einer anderen Funktion zuzugreifen.

MDN sagt: Der Abschluss ist eine besondere Art von Objekt. Es besteht aus zwei Teilen: der Funktion und der Umgebung, in der die Funktion erstellt wird. Die Umgebung besteht aus allen lokalen Variablen, die zum Zeitpunkt der Erstellung des Abschlusses im Gültigkeitsbereich waren.

Ausführliche Antwort

Wenn der Browser die Seite lädt, legt er den Code zur Ausführung im Stapelspeicher (ECStack) ab. Durch das Schieben der Funktion in den Stapel wird ein privater Kontext (EC) generiert Verwenden Sie Variablen (AO) im Inneren vor externen Eingriffen. Wenn ein Teil des Inhalts im aktuellen Ausführungskontext durch Inhalte außerhalb des Kontexts belegt wird, wird der aktuelle Kontext nicht vom Stapel freigegeben, sodass die Variablen und Variablenwerte in Es kann gespeichert werden, daher denke ich, dass der Abschluss eine Art Erhaltungs- und Schutzmechanismus für interne private Variablen ist.

2.2 Die Rolle von Abschlüssen

Abschlüsse haben zwei häufige Verwendungszwecke:

Die erste Verwendung von Abschlüssen besteht darin, uns den Zugriff auf Variablen innerhalb der Funktion von außerhalb der Funktion zu ermöglichen. Durch die Verwendung von Abschlüssen können Sie extern auf die Variablen innerhalb der Funktion zugreifen, indem Sie die Abschlussfunktion extern aufrufen. Mit dieser Methode können Sie private Variablen erstellen.

Eine weitere Verwendung des Abschlusses besteht darin, zuzulassen, dass das Variablenobjekt im beendeten Funktionskontext im Speicher verbleibt. Da die Abschlussfunktion einen Verweis auf das Variablenobjekt beibehält, wird das Variablenobjekt nicht recycelt.

2.3 Die Referenzszenarien von Abschlüssen in Projekten und die damit verbundenen Probleme

In tatsächlichen Projekten verpacken Sie den Inhalt der von Ihnen geschriebenen Module basierend auf Abschlüssen, damit Sie Ihren eigenen Code schützen können privat, um Konflikte mit globalen Variablen oder anderem Code zu verhindern. Dies wird durch die Verwendung eines Schutzmechanismus erreicht.

Es wird jedoch nicht empfohlen, zu viele Abschlüsse zu verwenden, da die Verwendung eines nicht freigegebenen Kontexts Stapelspeicherplatz beansprucht und eine übermäßige Verwendung zu Speicherverlusten führen kann.

Die Möglichkeit, das durch Schließungen verursachte Speicherverlustproblem zu lösen, besteht darin, die Schließungsfunktion nach der Verwendung manuell freizugeben. 2.4 Verwendungsszenarien von Schließungen

Funktionscurrying

2.5 Der Ausführungsprozess des Abschlusses

bildet einen privaten Kontext

Schieben in den Stapel, um eine Reihe von Operationen auszuführen

(1). Initialisieren Sie die Bereichskette (beide Enden

(3) Argumente initialisieren

(5). Wenn Sie auf eine Variable stoßen, prüfen Sie zunächst, ob sie für Sie privat ist. Wenn sie nicht die übergeordnete ist, suchen Sie online weiter, bis EC(G). Die Variable ist eigentlich eine Bereichskette. Die Spleißabfragekette ist die Bereichskette.

Unter normalen Umständen wird der private Kontext nach Abschluss der Codeausführung vom Stapel entfernt und recycelt. Wenn jedoch unter besonderen Umständen etwas im aktuellen privaten Kontext von etwas anderem als dem Ausführungskontext belegt ist, nachdem die Ausführung des aktuellen privaten Kontexts abgeschlossen ist, wird der aktuelle private Kontext nicht vom Stapel freigegeben, d. h. ein Kontext und der Verschluss wird nicht zerstört.

2.6 Arten von Ausführungskontexten

(1) Globaler Ausführungskontext

Alles, was sich nicht innerhalb einer Funktion befindet, ist ein globaler Ausführungskontext. Zuerst wird ein globales Fensterobjekt erstellt und dessen Wert auf diesen Wert gesetzt globales Objekt, es gibt nur einen globalen Ausführungskontext in einem Programm.

(2) Funktionsausführungskontext

Wenn eine Funktion aufgerufen wird, wird ein neuer Ausführungskontext für die Funktion erstellt. Es kann eine beliebige Anzahl von Funktionskontexten geben.

(3) Ausführungskontext der Auswertungsfunktion

Der in der Auswertungsfunktion ausgeführte Code verfügt über einen eigenen Ausführungskontext, aber die Auswertungsfunktion wird nicht häufig verwendet und wird nicht eingeführt.

2.7 Was ist der Ausführungskontextstapel?

Die JavaScript-Engine verwendet den Ausführungskontextstapel, um den Ausführungskontext zu verwalten

Wenn JavaScript Code ausführt, trifft es zuerst auf globalen Code, erstellt einen globalen Ausführungskontext und schiebt ihn auf den Ausführungsstapel. Immer wenn es auf einen Funktionsaufruf trifft, erstellt es einen neuen Ausführungskontext für die Funktion und schiebt ihn an die Spitze des Stapels . Die Engine führt die Funktion oben im Ausführungskontextstapel aus. Wenn die Funktionsausführung abgeschlossen ist, wird der Ausführungskontext vom Stapel entfernt und mit der Ausführung des nächsten Kontexts fortgefahren. Wenn der gesamte Code ausgeführt wurde, wird der globale Ausführungskontext vom Stapel entfernt.

2.8 Drei Phasen des Ausführungskontexts

Erstellungsphase → Ausführungsphase → Recyclingphase

Erstellungsphase

(1) diese Bindung

Im globalen Ausführungskontext zeigt dies auf das globale Objekt (Fensterobjekt). )

Im Funktionsausführungskontext hängt dies davon ab, wie die Funktion aufgerufen wird. Wenn es von einem Referenzobjekt aufgerufen wird, wird dies auf dieses Objekt gesetzt, andernfalls wird der Wert von this auf das globale Objekt oder undefiniert gesetzt

(2) Erstellen Sie eine lexikalische Umgebungskomponente

Die lexikalische Umgebung ist ein Bezeichner – eine Variable Eine zugeordnete Datenstruktur, bei der sich der Bezeichner auf den Variablen-/Funktionsnamen bezieht und die Variable eine Referenz auf das tatsächliche Objekt oder die Rohdaten ist.

In der lexikalischen Umgebung gibt es zwei Komponenten: Fettdruck: Umgebungsrekorder: Wird zum Speichern der tatsächlichen Position von Variablen und Funktionsdeklarationen verwendet. Externe Umgebungsreferenzen: Kann auf den übergeordneten Bereich zugreifen.

(3) Variablenumgebungskomponenten erstellen.

Die Variable Die Umgebung ist ebenfalls eine lexikalische Umgebung, und ihr Umgebungsrekorder speichert die Bindungsbeziehungen, die durch die Variablendeklarationsanweisung im Ausführungskontext erstellt wurden.

Ausführungsphase

In dieser Phase werden die Variablenzuweisung und die Codeausführung durchgeführt

Wenn die Javascript-Engine den Wert der Variablen an der tatsächlichen im Quellcode deklarierten Position nicht finden kann, wird ihr ein undefinierter Wert zugewiesen

Recyclingphase

Ausführung Der Kontext wird vom Stapel entfernt und wartet darauf, dass die virtuelle Maschine den Ausführungskontext recycelt

2.9 Sprechen Sie über Ihr Verständnis des Bereichs

Der Bereich kann als eine Reihe von Regeln betrachtet werden Regeln werden verwendet, um zu verwalten, wie die Engine im aktuellen Bereich arbeitet und verschachtelt. Der Unterbereich der Variablensuche basierend auf dem Bezeichnernamen.

Einfach ausgedrückt ist der Umfang der effektive Bereich einer Variablen. Variablendaten können in einem bestimmten Bereich gelesen und geschrieben werden, und dieser Bereich ist der Gültigkeitsbereich der Variablen.

(1) Globaler Bereich

JS-Code, der direkt in das Skript-Tag geschrieben wird, befindet sich im globalen Bereich. Im globalen Bereich deklarierte Variablen werden als globale Variablen bezeichnet (Variablen, die außerhalb der Blockebene definiert sind).

Globale Variablen können überall auf der Welt verwendet werden; auf Variablen im lokalen Bereich kann im globalen Bereich nicht zugegriffen werden.

Der globale Bereich wird beim Öffnen der Seite erstellt und beim Schließen der Seite zerstört.

Alle Eigenschaften des Fensterobjekts haben einen globalen Gültigkeitsbereich.

Globale Variablen und Funktionen, die von den Befehlen var und function deklariert werden, sind Eigenschaften und Methoden des Fensterobjekts.

Globale Variablen, die von den Befehlen let, const und class deklariert werden, sind nicht gültig gehören zum Fensterobjekt Attribute

(2) Funktionsumfang (lokaler Geltungsbereich)

Beim Aufruf einer Funktion wird ein Funktionsumfang erstellt. Nach der Ausführung der Funktion wird der Geltungsbereich zerstört. Bei jedem Aufruf einer Funktion wird ein neuer Funktionsumfang erstellt, und sie sind unabhängig voneinander.

Auf globale Variablen kann im Funktionsumfang zugegriffen werden, auf Variablen innerhalb der Funktion kann jedoch nicht außerhalb der Funktion zugegriffen werden.

Wenn eine Variable im Funktionsbereich betrieben wird, wird sie zunächst in ihrem eigenen Bereich gesucht. Wenn nicht, wird sie im vorherigen Bereich durchsucht befindet sich immer noch im globalen Bereich. Wenn es nicht gefunden wird, wird ein Fehler gemeldet.

(3) Bereich auf Blockebene

Vor ES6 verwendete JavaScript den Funktionsbereich + lexikalischen Bereich, und ES6 führte den Bereich auf Blockebene ein.

Jeder Satz von Anweisungen, der in ein Paar geschweifter Klammern {} eingeschlossen ist, gehört zu einem Block. Auf Variablen, die mit let und const in einem Block deklariert werden, kann nicht von außen zugegriffen werden. Diese Art von Bereichsregel wird als Bereich auf Blockebene bezeichnet.

Variablen, die über var- oder Funktionsdeklarationen deklariert wurden, die im nicht strikten Modus erstellt wurden, haben keinen Gültigkeitsbereich auf Blockebene.

(4) Lexikalischer Geltungsbereich

Der lexikalische Geltungsbereich ist ein statischer Geltungsbereich. Unabhängig davon, wo die Funktion aufgerufen wird oder wie sie aufgerufen wird, wird ihr lexikalischer Geltungsbereich nur durch die Funktion bestimmt, wenn sie deklariert wird.

Die lexikalische Analysephase der Kompilierung kann grundsätzlich wissen, wo und wie alle Bezeichner deklariert werden, sodass sie vorhersagen kann, wie sie während der Ausführung gefunden werden.

Mit anderen Worten bedeutet lexikalischer Geltungsbereich, dass Sie den Geltungsbereich der Variablen beim Schreiben des Codes festgelegt haben.

2.10 Was ist eine Bereichskette?

Bei Verwendung einer Variablen in js versucht die js-Engine zunächst, die Variable im aktuellen Bereich zu finden. Wenn sie nicht gefunden wird, sucht sie in ihrem oberen Bereich. usw., bis die Variable gefunden wird oder den globalen Gültigkeitsbereich erreicht hat. Eine solche Kettenstruktur des Variablenbereichszugriffs wird als Bereichskette bezeichnet.

Ausführliche Antwort

Eine Bereichskette ist im Wesentlichen eine Liste von Zeigern auf variable Objekte. Ein Variablenobjekt ist ein Objekt, das alle Variablen und Funktionen in der Ausführungsumgebung enthält. Das vordere Ende der Bereichskette ist immer das variable Objekt des aktuellen Ausführungskontexts. Das variable Objekt des globalen Ausführungskontexts (dh das globale Objekt) ist immer das letzte Objekt in der Bereichskette.

2.11 Die Rolle der Bereichskette

Die Rolle der Bereichskette besteht darin, einen ordnungsgemäßen Zugriff auf alle Variablen und Funktionen sicherzustellen, auf die die Ausführungsumgebung Zugriff hat zugänglich sind und funktionieren.

2.12 Häufige Anwendungsszenarien von Scope

Eines der häufigsten Anwendungsszenarien von Scope ist die Modularisierung.

Da JavaScript die Modularisierung nicht nativ unterstützt, hat dies zu vielen verlockenden Problemen geführt, wie z. B. globaler Bereichsverschmutzung und Variablennamenkonflikten, aufgeblähter Codestruktur und geringer Wiederverwendbarkeit. Bevor die formale Modularisierungslösung eingeführt wurde, dachten Entwickler zur Lösung dieser Art von Problem darüber nach, den Funktionsumfang zum Erstellen von Modulen zu nutzen.

2.13 Sprechen Sie über das Vorparsen in Js?

Wenn die JS-Engine einen Code ausführt, funktioniert er gemäß den folgenden Schritten:

1. Befördern Sie die Deklaration der Variablen an den Anfang des aktuellen Bereichs. Es wird nur die Deklaration befördert, nicht die Zuweisung

2. Befördern Sie die Funktionsdeklaration an den Anfang des aktuellen Bereichs, aber der Aufruf wird nicht beworben.

3 Befördern Sie zuerst die Funktion und dann die Variable Variablenförderung und Funktionsförderung?

VariablenheraufstufungEinfach ausgedrückt führt die Engine eine Vorkompilierung durch, bevor der JavaScript-Code ausgeführt wird. Während der Vorkompilierung werden die Variablendeklaration und die Funktionsdeklaration an die Spitze ihrer entsprechenden Bereiche heraufgestuft Nur an die Spitze des Funktionsbereichs anheben Wenn eine innerhalb der Funktion definierte Variable mit der Außenseite übereinstimmt, wird die Variable im Funktionskörper an die Spitze angehoben.

Funktionsförderung

Funktionsförderung verbessert nur das deklarative Schreiben von Funktionen, das Schreiben von Funktionsausdrücken existiert nicht. Funktionsförderung

Die Priorität der Funktionsförderung ist höher als die Priorität der Variablenförderung, das heißt, die Funktionsförderung steht über der Variablenförderung

2.14 Wie kann die Scope-Kette erweitert werden?

Die Scope-Kette kann erweitert werden. Erweiterte Bereichskette: Es gibt nur zwei Arten von Ausführungsumgebungen: global und lokal (Funktion). Einige Anweisungen können jedoch vorübergehend ein Variablenobjekt am vorderen Ende der Bereichskette hinzufügen, und das Variablenobjekt wird nach der Codeausführung entfernt.

Insbesondere, wenn diese beiden Anweisungen ausgeführt werden, wird die Gültigkeitskette gestärkt.

try-catch-Block der Catch-Anweisung: Es wird ein neues Variablenobjekt erstellt, das die Deklaration des ausgelösten Fehlerobjekts enthält.

with-Anweisung: Die with-Anweisung fügt das angegebene Objekt zur Bereichskette hinzu. 2.15 Browser-Garbage-Collection-Mechanismus Das System weist ihnen automatisch Speicher zu.

Speichernutzung: Das heißt, Speicher lesen und schreiben, also Variablen, Funktionen usw. verwenden.

Speicherrecycling: Nach der Verwendung wird der nicht mehr verwendete Speicher automatisch recycelt durch Garbage Collection

Globale Variablen werden im Allgemeinen nicht recycelt. Im Allgemeinen werden die Werte lokaler Variablen automatisch recycelt, wenn sie nicht mehr verwendet werden

(2) Das Konzept der Garbage Collection

Garbage Collection: Wenn JavaScript Wenn der Code ausgeführt wird, muss Speicherplatz zum Speichern von Variablen und Werten zugewiesen werden. Wenn die Variablen nicht mehr an der Operation teilnehmen, muss das System den belegten Speicherplatz zurückgewinnen. Dies ist eine Garbage Collection.

Recycling-Mechanismus:

Javascript verfügt über einen automatischen Garbage-Collection-Mechanismus, der regelmäßig den von nicht mehr verwendeten Variablen und Objekten belegten Speicher freigibt. Das Prinzip besteht darin, die nicht mehr verwendeten Variablen zu finden und dann den Speicher freizugeben von ihnen besetzt.

In JavaScript gibt es zwei Arten von Variablen: lokale Variablen und globale Variablen. Der Lebenszyklus globaler Variablen wird fortgesetzt, bis die Seite entladen wird, während lokale Variablen in einer Funktion deklariert werden und ihr Lebenszyklus von der Ausführung der Funktion bis zum Ende der Funktionsausführung beginnt ihre Werte im Heap oder Stack. Wenn die Funktionsausführung endet, werden diese lokalen Variablen nicht mehr verwendet und der von ihnen belegte Platz wird freigegeben.

Wenn jedoch lokale Variablen von externen Funktionen verwendet werden, ist eine der Situationen der Abschluss. Nach dem Ende der Funktionsausführung verweisen die Variablen außerhalb der Funktion immer noch auf die lokalen Variablen innerhalb der Funktion wird verwendet und wird daher nicht recycelt.

(3) Garbage-Collection-Methoden

1

Dieser vom IE verwendete Referenzzählalgorithmus wird relativ selten verwendet. Durch die Referenzzählung wird erfasst, wie oft auf jeden Wert verwiesen wird. Wenn eine Variable deklariert und ihr ein Referenztyp zugewiesen wird, beträgt die Anzahl der Referenzen auf den Wert 1. Wenn umgekehrt die Variable, die einen Verweis auf diesen Wert enthält, einen anderen Wert erhält, wird die Anzahl der Verweise auf diesen Wert um eins dekrementiert. Wenn die Anzahl der Referenzen 0 wird, bedeutet dies, dass die Variable keinen Wert hat. Daher wird der von dieser Variablen belegte Speicherplatz bei der nächsten Ausführung während des Maschinenrecyclingzeitraums freigegeben.

Diese Methode führt zu Zirkelverweisproblemen: Beispiel: obj1 und obj2 verweisen aufeinander über Attribute, und die Anzahl der Verweise beider Objekte beträgt 2. Bei Verwendung der Schleifenzählung bleiben obj1 und obj2 weiterhin vorhanden, da nach Ausführung der Funktion beide Objekte den Gültigkeitsbereich verlassen und die Funktionsausführung endet, sodass ihre Anzahl an Referenzen niemals 0 ist, was zu einem Zirkelverweis führt.

  • 2. Markierungslöschmethode

Moderne Browser verwenden den Referenzzählalgorithmus nicht mehr.

Die meisten modernen Browser basieren auf einigen verbesserten Algorithmen, die auf dem Mark- und Clear-Algorithmus basieren, und die Grundidee ist dieselbe.

Mark Clearing ist eine gängige Garbage-Collection-Methode in Browsern. Wenn eine Variable in die Ausführungsumgebung gelangt, wird sie als „in die Umgebung gelangen“ markiert. Variablen, die als „in die Umgebung gelangen“ markiert sind, können nicht recycelt werden, da sie verwendet werden. Wenn eine Variable die Umgebung verlässt, wird sie als „die Umgebung verlassen“ markiert und die als „die Umgebung verlassen“ markierte Variable wird aus dem Speicher freigegeben.

Der Garbage Collector markiert bei seiner Ausführung alle im Speicher gespeicherten Variablen. Anschließend werden die Variablen in der Umgebung und die Tags entfernt, auf die die Variablen in der Umgebung verweisen. Variablen, die danach markiert werden, werden als zu löschende Variablen betrachtet, da Variablen in der Umgebung nicht mehr auf diese Variablen zugreifen können. endlich. Der Garbage Collector führt die Speicherbereinigung durch, zerstört die markierten Werte und gewinnt den von ihnen belegten Speicherplatz zurück.

(4) So reduzieren Sie die Garbage Collection

Obwohl der Browser automatisch Garbage sammeln kann, sind die Kosten für die Garbage Collection bei komplexerem Code relativ hoch, sodass die Garbage Collection so weit wie möglich reduziert werden sollte.

Arrays optimieren: Beim Löschen eines Arrays besteht die einfachste Möglichkeit darin, ihm den Wert [] zuzuweisen. Gleichzeitig wird jedoch ein neues leeres Objekt erstellt. Sie können die Länge des Arrays auf 0 setzen, um dies zu erreichen. Zweck des Löschens des Arrays.

Objekte optimieren: Objekte, die nicht mehr verwendet werden, so oft wie möglich wiederverwenden, setzen Sie sie auf Null und recyceln Sie sie so schnell wie möglich.

Funktionen optimieren: Wenn der Funktionsausdruck in der Schleife wiederverwendet werden kann, versuchen Sie, ihn außerhalb der Funktion zu platzieren.

(5) Was ist ein Speicherverlust?

bezieht sich auf das Versagen des Programms, Speicher freizugeben, der aufgrund von Fahrlässigkeit oder Fehler nicht mehr verwendet wird.

(6) Welche Situationen führen zu Speicherverlusten

Die folgenden vier Situationen verursachen Speicherlecks:

Unerwartete globale Variablen: Aufgrund der Verwendung nicht deklarierter Variablen wurde versehentlich eine globale Variable erstellt, sodass diese Variable im Speicher verbleibt und nicht recycelt werden kann.

Timer oder Callback-Funktion vergessen: Stellen Sie den setInterval-Timer ein und vergessen Sie, ihn abzubrechen. Wenn die Schleifenfunktion einen Verweis auf eine externe Variable hat, bleibt die Variable im Speicher und kann nicht recycelt werden.

Referenz aus dem DOM: Rufen Sie einen Verweis auf ein DOM-Element ab und löschen Sie das Element. Da der Verweis auf dieses Element immer erhalten bleibt, kann er nicht wiederverwendet werden.

Abschlüsse: Die unsachgemäße Verwendung von Abschlüssen führt dazu, dass einige Variablen im Speicher verbleiben.

3. Funktionen und funktionale Programmierung Imperative Programmierung, deklarative Programmierung und funktionale Programmierung

Im Vergleich zur imperativen Programmierung legt die funktionale Programmierung mehr Wert auf die Ergebnisse der Programmausführung als auf den Ausführungsprozess und befürwortet die Verwendung einer Reihe einfacher Ausführungseinheiten, um die Berechnungsergebnisse schrittweise zu gestalten , leiten Sie komplexe Operationen Schicht für Schicht ab, anstatt einen komplexen Ausführungsprozess zu entwerfen , können wir diese Unbekannten minimieren, Code optimieren und Fehler reduzieren

Einfachere Wiederverwendung: feste Eingabe -> feste Ausgabe, kein Einfluss anderer externer Variablen und keine Nebenwirkungen. Auf diese Weise ist es bei der Wiederverwendung von Code nicht erforderlich, dessen interne Implementierung und externe Einflüsse zu berücksichtigen. Eine elegantere Kombination: Im Großen und Ganzen besteht eine Webseite aus verschiedenen Komponenten. Vereinfacht ausgedrückt kann eine Funktion auch aus mehreren kleinen Funktionen bestehen. Eine stärkere Wiederverwendbarkeit bringt leistungsfähigere Kombinationen – versteckte Vorteile. Reduzieren Sie die Codemenge und verbessern Sie die WartbarkeitNachteile

性能:函数式编程相对于指令式编程,性能绝对是一个短板,因为它往往会对一个方法进行过度包装,从而产生上下文切换的性能开销

资源占用:在 JS 中为了实现对象状态的不可变,往往会创建新的对象,因此,它对垃圾回收所产生的压力远远超过其他编程方式

递归陷阱:在函数式编程中,为了实现迭代,通常会采用递归操作

3.3 什么是纯函数,它有什么优点

纯函数是对给定的输入返还相同输出的函数,并且要求你所有的数据都是不可变的,即纯函数=无状态+数据不可变

特性:

函数内部传入指定的值,就会返回确定唯一的值

不会造成超出作用域的变化,例如修改全局变量或引用传递的参数

优势:

使用纯函数,我们可以产生可测试的代码

不依赖外部环境计算,不会产生副作用,提高函数的复用性

可读性更强 ,函数不管是否是纯函数 都会有一个语义化的名称,更便于阅读

可以组装成复杂任务的可能性。符合模块化概念及单一职责原则

3.4 什么是组合函数 (compose)

在函数式编程中,有一个很重要的概念就是函数组合,实际上就是把处理的函数数据像管道一样连接起来,然后让数据穿过管道连接起来,得到最终的结果。

组合函数,其实大致思想就是将 多个函数组合成一个函数,c(b(a(a(1)))) 这种写法简写为 compose(c, b, a, a)(x) 。但是注意这里如果一个函数都没有传入,那就是传入的是什么就返回什么,并且函数的执行顺序是和传入的顺序相反的。

var compose = (...funcs) => {
  // funcs(数组):记录的是所有的函数
  // 这里其实也是利用了柯里化的思想,函数执行,生成一个闭包,预先把一些信息存储,供下级上下文使用
  return (x) => {
    var len = funcs.length;
    // 如果没有函数执行,直接返回结果
    if (len === 0) return x;
    if (len === 1) funcs[0](x);
    return funcs.reduceRight((res, func) => {
      return func(res);
    }, x);
  };
};
var resFn = compose(c, b, a, a);
resFn(1);

组合函数的思想,在很多框架中也被使用,例如:redux,实现效果来说是其实和上面的代码等价。

3.5 什么是惰性函数

惰性载入表示函数执行的分支只会在函数第一次掉用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了

惰性函数相当于有记忆的功能一样,当它已经判断了一遍的话,第二遍就不会再判断了。

比如现在要求写一个test函数,这个函数返回首次调用时的new Date().getTime(),注意是首次,而且不允许有全局变量的污染

//一般会这样实现
var test = (function () {
    var t = null;
    return function () {
        if (t) {
            return t;
        }
        t = new Date().getTime();
        return t;
    }
})();
// 用惰性函数实现
var test = function () {
    var t = new Date().getTime();
    test = function () {
        return t;
    }
    return test();
}
console.log(test());
console.log(test());
console.log(test());

3.6 什么是高阶函数

高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。

3.7 说说你对函数柯里化的理解

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

函数柯里化的好处:

(1)参数复用:需要输入多个参数,最终只需输入一个,其余通过 arguments 来获取

(2)提前确认:避免重复去判断某一条件是否符合,不符合则 return 不再继续执行下面的操作

(3)延迟运行:避免重复的去执行程序,等真正需要结果的时候再执行

3.8 什么是箭头函数,有什么特征

使用 "箭头" ( => ) 来定义函数. 箭头函数相当于匿名函数, 并且简化了函数定义

箭头函数的特征:

箭头函数没有this, this指向定义箭头函数所处的外部环境

箭头函数的this永远不会变,call、apply、bind也无法改变

箭头函数只能声明成匿名函数,但可以通过表达式的方式让箭头函数具名

箭头函数没有原型prototype

箭头函数不能当做一个构造函数 因为 this 的指向问题

箭头函数没有 arguments 在箭头函数内部访问这个变量访问的是外部环境的arguments, 可以使用 ...代替

3.9 说说你对递归函数的理解

如果一个函数在内部调用自身本身,这个函数就是递归函数

其核心思想是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

一般来说,递归需要有边界条件、递归前进阶段和递归返回阶段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回

优点:结构清晰、可读性强

缺点:效率低、调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。

3.10 什么是尾递归

尾递归,即在函数尾位置调用自身(或是一个尾调用本身的其他函数等等)。

在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,递归次数过多容易造成栈溢出

这时候,我们就可以使用尾递归,即一个函数中所有递归形式的调用都出现在函数的末尾,对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误

3.11 函数传参,传递复杂数据类型和简单数据类型有什么区别

传递复杂数据类型传递的是引用的地址,修改会改变

简单数据类型传递的是具体的值,不会相互影响

/* let a = 8
    function fn(a) {
      a = 9
    }
    fn(a)
    console.log(a) // 8 */
    let a = { age: 8 }
    function fn(a) {
      a.age = 9
    }
    fn(a)
    console.log(a.age) // 9

3.12 函数声明与函数表达式的区别

函数声明: funtion开头,有函数提升

函数表达式: 不是funtion开头,没有函数提升

3.13 什么是函数缓存,如何实现?

概念

函数缓存,就是将函数运算过的结果进行缓存

本质上就是用空间(缓存存储)换时间(计算过程)

常用于缓存数据计算结果和缓存对象

如何实现

实现函数缓存主要依靠闭包、柯里化、高阶函数

应用场景

对于昂贵的函数调用,执行复杂计算的函数

对于具有有限且高度重复输入范围的函数

对于具有重复输入值的递归函数

对于纯函数,即每次使用特定输入调用时返回相同输出的函数

3.14 call、apply、bind三者的异同

  • 共同点 :

都可以改变this指向;

三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window

  • 不同点:

call 和 apply 会调用函数, 并且改变函数内部this指向.

call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递,且apply和call是一次性传入参数,而bind可以分为多次传入

bind是返回绑定this之后的函数

  • 应用场景

call 经常做继承.

apply经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值

bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指

【相关推荐:JavaScript视频教程web前端

Das obige ist der detaillierte Inhalt vonJavaScript-Interviewzusammenfassung mit 10.000 Wörtern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen