There are always ups and downs in a person's life. It will not always rise like the rising sun, nor will it always be miserable. Repeated ups and downs are training for a person. Therefore, those who are floating above do not need to be proud; those who are sinking below do not need to be pessimistic. We must be frank and humble, optimistic and enterprising, and move forward. ——Konosuke Matsushita
Hello everyone, my name is Jiang Chen. In today's Internet environment, everyone must have felt it to some extent. In this impetuous society, only by constantly maintaining one's character can one perceive different gains and encourage each other.
A collection of the latest interview questions in 2023, so be prepared at all times.
This article was first published on WeChat public account: Wild Programmer Jiang Chen
Everyone is welcome to like, collect and follow
Article list
- 2023 front-end interview questions - coding chapter
- 2023 front-end interview questions - CSS
- 2023 front-end interview questions - HTML
- 2023 front-end interview questions - React
- 2023 front-end interview questions - Vue chapter
Please briefly describe this in JavaScript
in JS this
is a relatively complex concept that cannot be explained clearly in a few sentences. Roughly speaking, how the function is called determines this
the value of . I have read a lot of this
articles on the Internet about , and Arnav Aggrawal wrote it more clearly. this
The value complies with the following rules:
Use the keyword when calling a function new
, and the inside the function this
is a brand new object.
If the apply、call
or bind
method is used to call or create a function, the within the function this
is the object passed into these methods as a parameter.
When a function is called as a method on an object, within the function this
is the object that called the function. For example, when obj.method()
is called, inside the function this
will be bound to obj
the object.
If the calling function does not comply with the above rules, then this
the value of points to the global object ( global object
). In a browser environment this
the value of points to window
the object, but in strict mode ( 'use strict'
), this
the value of undefined
.
If more than one of the above rules is met, the higher rule (number 1 is the highest, number 4 is the lowest) will determine this
the value of .
If the function is ES2015
an arrow function in , all rules above are ignored and this
are set to the context in which it was created.
Tell me what you know about AMD and CommonJS.
They are all ways to implement a module system. Until ES2015
the emergence of , JavaScript
there was no module system. CommonJS
is synchronous, while AMD(Asynchronous Module Definition)
it is obvious from the full name that it is asynchronous. CommonJS
is designed with server-side development in mind, while AMD
supports asynchronous loading of modules, which is more suitable for browsers.
I find AMD
the syntax to be very verbose and CommonJS
closer to import
the usage of declaration statements in other languages. In most cases, I think AMD
there is no need to use it, because if you JavaScript
bundle everything into a file, you will not get the benefits of asynchronous loading. In addition, CommonJS
the syntax is closer to Node
the style of writing modules. JavaScript
When switching between front-end and back-end development, the context switching overhead is smaller.
I'm happy to see ES2015
that the module loading scheme supports both synchronous and asynchronous, and we can finally use only one scheme. While it's not yet fully rolled out in browsers and Node
, we can convert it using transcoding tools.
Please explain why the following code cannot be used as an IIFE: function foo(){ }();. What modifications need to be made to make it an IIFE?
IIFE (Immediately Invoked Function Expressions) stands for Immediately Invoked Function Expressions. JavaScript
The parser will function foo(){ }();
parse into function foo(){ }和();
. Among them, the former is a function declaration; the latter (a pair of parentheses) is an attempt to call a function without specifying a name, so it will throw an Uncaught SyntaxError: Unexpected token )
error.
The modification method is: add another pair of brackets, there are two forms: (function foo(){ })()
and (function foo(){ }())
. The above function will not be exposed to the global scope. If you do not need to refer to itself within the function, you can omit the name of the function.
You may use void
operator: void function foo(){ }();
. However, this approach is problematic. The value of the expression is undefined
, so if your IIFE
has a return value, don't use this approach. For example
const foo = void (function bar() {
return 'foo';
})();
console.log(foo); // undefined
What is the difference between null, undefined and undeclared variables? How to check and judge these status values?
When you assign a value to a variable without declaring it with var、let
or in advance const
, the variable is an undeclared variable ( undeclared variables
). Undeclared variables will leave the current scope and become variables defined in the global scope. In strict mode, assigning a value to an undeclared variable will throw ReferenceError
an error. Like using global variables, using undeclared variables is also a very bad practice and should be avoided whenever possible. To check for them, place the code that uses them in try/catch
a statement.
function foo() {
x = 1; // 在严格模式下,抛出 ReferenceError 错误
}
foo();
console.log(x); // 1
When a variable has been declared but not assigned a value, the variable's value is undefined
. If the execution result of a function is assigned to a variable, but the function does not return any value, then the value of the variable is undefined
. To check it, use strict equality ( ===
); alternatively typeof
, it returns 'undefined'
a string. Note that you cannot use non-strict equality ( ==
) to check because null
using non-strict equality will also return if the variable value is true
.
var foo;
console.log(foo); // undefined
console.log(foo === undefined); // true
console.log(typeof foo === 'undefined'); // true
console.log(foo == null); // true. 错误,不要使用非严格相等!
function bar() {}
var baz = bar();
console.log(baz); // undefined
null
Can only be assigned to variables explicitly. It represents a null value, which is different from being explicitly assigned undefined
. To check the predicate null
value, use the strict equality operator. Note that, as before, you cannot use non-strict equality ( ==
) to check, because undefined
using non-strict equality will also return if the variable value is true
.
var foo = null;
console.log(foo === null); // true
console.log(foo == undefined); // true. 错误,不要使用非严格相等!
As a personal habit, I never use undeclared variables. If variables are defined that are not used yet, I will explicitly assign values to them after declaring them asnull
What is a closure and why are we using it?
A closure is a combination of a function and the lexical environment in which the function is declared. The domain used in lexical scope is determined by where the variable is declared in the code. A closure is a function that can still access the scope of the outer (enclosing) function even if it is returned by the outer function.
Why use closures?
- Use closures to privatize data or mock private methods. This approach is also called module mode (
module pattern
). - Partial argument function (
partial applications
) currying (currying
).
Please explain the main difference between .forEach loop and .map() loop. Under what circumstances are they used?
To understand the difference between the two, let’s look at what they do.
forEach
- Iterate over the elements in an array.
- Execute callback for each element.
- No return value.
const a = [1, 2, 3];
const doubled = a.forEach((num, index) => {
// 执行与 num、index 相关的代码
});
// doubled = undefined
map
- Iterate over the elements in an array
- A new array is created by "map" each element to a new element by calling a function on each element.
const a = [1, 2, 3];
const doubled = a.map((num) => {
return num * 2;
});
// doubled = [2, 4, 6]
.forEach
.map()
The main difference between and is that .map()
returns a new array. If you want to get a result without changing the original array, use .map()
. If you only need to make iterative modifications on an array, use forEach
.
What are the typical application scenarios of anonymous functions?
Anonymous functions can be used in IIFEs to encapsulate code in the local scope so that the variables they declare are not exposed to the global scope.
(function () {
// 一些代码。
})();
Anonymous functions can be used as callback functions that are used only once and do not need to be used elsewhere. When handlers are defined inside the program that calls them, the code is more self-contained and readable, and the trouble of finding the location of the function body of the handler is saved.
setTimeout(function () {
console.log('Hello world!');
}, 1000);
Anonymous functions can be used in functional programming or Lodash (similar to callback functions).
const arr = [1, 2, 3];
const double = arr.map(function (el) {
return el * 2;
});
console.log(double); // [2, 4, 6]
What is the difference between .call and .apply?
.call
and are .apply
both used to call a function, the first parameter will be used as this
the value within the function. However, .call
accepts comma-separated parameters as the next parameter, while .apply
accepts an array of parameters as the next parameter. A simple memory method call
is to associate the C in to comma separation ( comma-separated
), apply
and associate the A in to array ( array
).
function add(a, b) {
return a + b;
}
console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3
Please explain the usage of Function.prototype.bind.
Excerpted from MDN:
The bind() method creates a new function, and when called, sets its this keyword to the supplied value. When calling the new function, it provides a given sequence of arguments before any supply.
In my experience, this
it is very useful to bind the value of into a method of a class that you want to pass to other functions. React
This is often done in components .
Please explain Ajax in as much detail as possible.
Ajax (asynchronous JavaScript and XML) is a Web development technology that uses many Web technologies on the client to create asynchronous Web applications. With Ajax, Web applications can send and retrieve data to and from the server asynchronously (in the background) without interfering with the display and behavior of existing pages. By separating the data exchange layer from the presentation layer, Ajax allows web pages and extended Web applications to dynamically change content without reloading the entire page. In fact, XML is now often replaced by JSON because of JavaScript's native support for JSON.
XMLHttpRequest API
Often used for asynchronous communication. There are also recently popular ones fetch API
.
What are the advantages and disadvantages of using Ajax?
advantage
- Better interactivity. New content from the server can be changed dynamically without reloading the entire page.
- Reduces connections to the server since scripts and styles only need to be requested once.
- Status can be maintained on a page. JavaScript variables and DOM state are maintained because the main container page is not reloaded.
- Basically includes most of the advantages of SPA.
shortcoming
- Dynamic web pages are difficult to collect.
- Has no effect if JavaScript has been disabled in the browser.
- Some web crawlers do not execute JavaScript and will not see content loaded by JavaScript.
- Basically includes most of the shortcomings of SPA
Please explain how JSONP works and why is it not true Ajax?
JSONP (JSON with padding) is a method commonly used to bypass cross-domain restrictions in web browsers because Ajax does not allow cross-domain requests.
JSONP <script>
sends cross-domain requests through tags, usually using callback
query parameters, such as: https://example.com?callback=printData
. The server then wraps the data in a printData
function called and returns it to the client.
<!-- https://mydomain.com -->
<script>
function printData(data) {
console.log(`My name is ${data.name}!`);
}
</script>
<script src="https://example.com?callback=printData"></script>
// 文件加载自 https://example.com?callback=printData
printData({name: 'Yang Shun'});
The client must have the function in its global scope printData
, and the function will be executed by the client when a response is received from the cross-domain.
JSONP may have some security implications. Since JSONP is a pure JavaScript implementation, it can do everything JavaScript can do, so the provider of JSONP data needs to be trusted.
Nowadays, Cross-Origin Resource Sharing (CORS) is the recommended mainstream method, and JSONP has been regarded as a more hacky method.
Please explain variable hoisting.
Variable hoisting is a term used to explain the behavior of variable declarations in code. var
Variables declared or initialized using the keyword "raise" the declaration statement to the top of the current scope. However, only declarations will trigger hoisting, assignment statements (if any) will remain intact. Let's explain it with a few examples.
// 用 var 声明得到提升
console.log(foo); // undefined
var foo = 1;
console.log(foo); // 1
// 用 let/const 声明不会提升
console.log(bar); // ReferenceError: bar is not defined
let bar = 2;
console.log(bar); // 2
Function declarations hoist the function body, but function expressions (written in the form of variable declarations) only have variable declarations hoisted.
// 函数声明
console.log(foo); // [Function: foo]
foo(); // 'FOOOOO'
function foo() {
console.log('FOOOOO');
}
console.log(foo); // [Function: foo]
// 函数表达式
console.log(bar); // undefined
bar(); // Uncaught TypeError: bar is not a function
var bar = function () {
console.log('BARRRR');
};
console.log(bar); // [Function: bar]
Please describe event bubbling.
When an event fires on a DOM element, if there is an event listener, it will try to handle the event and then the event bubbles up to its parent element and the same thing happens. Finally until the event reaches the ancestor element. Event bubbling is the principle of implementing event delegation (event delegation).
andWhat is the difference between =
==
is an abstract equality operator, while ===
is a strict equality operator. ==
The operator performs necessary type conversions before comparison. ===
The operator does not perform type conversion, so if the two values are not of the same type, they are returned directly false
. When using ==
, some special things can happen, such as:
1 == '1'; // true
1 == [1]; // true
1 == true; // true
0 == ''; // true
0 == '0'; // true
0 == false; // true
My advice is to never use ==
the operator except for convenience when comparing with null
or , if is or will returnundefined
a == null
a
null
undefined
true
var a = null;
console.log(a == null); // true
console.log(a == undefined); // true
Please explain about JavaScript's Same Origin Policy.
The same-origin policy prevents JavaScript from making cross-origin requests. A source is defined as a combination of URI, hostname, and port number. This policy prevents malicious scripts on a page from accessing sensitive data on another web page through the page's Document Object Model.
How familiar are you with Promises and their polyfills?
Understand how it works. Promise
Is an object that may produce a result at some time in the future: the result of a successful operation or the reason for its failure (for example, a network error occurred). Promise
May be in one of three states: fulfilled
, rejected
or pending
. Users can Promise
add callback functions to handle the results of successful operations or the reasons for failure.
Some common ones polyfill
are Polyfill $.deferred
, Q, and Bluebird, but not all polyfills are compliant with the specification. ES2015 supports Promises, and polyfills are generally not needed now.
What are the advantages and disadvantages of Promise instead of callback function?
advantage
- Avoid unreadable callback hell.
- Sequential asynchronous code written using .then() is simple and easy to read.
- Writing parallel asynchronous code becomes easy with Promise.all().
shortcoming
- Slightly increases the complexity of the code (this is debatable).
- In older browsers that do not support ES2015, a polyfill needs to be introduced to use it.
Please explain the difference between synchronous and asynchronous functions.
Synchronous functions block, while asynchronous functions do not block. In a synchronous function, after the statement is completed, the next statement is executed. In this case, the program can be evaluated exactly in the order of statements, and if one of the statements takes a long time, the program's execution will stall for a long time.
Asynchronous functions usually accept a callback as a parameter and continue execution to the next line immediately after calling the asynchronous function. The callback function is only called when the asynchronous operation completes and the call stack is empty. Heavy load operations such as loading data from a web server or querying a database should be completed asynchronously so that the main thread can continue to perform other operations without blocking until the time-consuming operation completes (in the browser, the interface will freeze) .
What is an event loop? What is the difference between call stack and task queue?
The event loop is a single-threaded loop that monitors the call stack and checks if any work is about to be completed in the task queue. If the call stack is empty and there is a callback function in the task queue, the callback function is dequeued and pushed into the call stack for execution.
What is the difference between creating variables using let, var and const?
The scope of a variable declared with var
is its current execution context, which can be a nested function or a variable declared outside any function. let
and const
are block-scoped, meaning they can only be accessed within the nearest set of curly braces (in a function, if-else block, or for loop).
function foo() {
// 所有变量在函数中都可访问
var bar = 'bar';
let baz = 'baz';
const qux = 'qux';
console.log(bar); // bar
console.log(baz); // baz
console.log(qux); // qux
}
console.log(bar); // ReferenceError: bar is not defined
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
if (true) {
var bar = 'bar';
let baz = 'baz';
const qux = 'qux';
}
// 用 var 声明的变量在函数作用域上都可访问
console.log(bar); // bar
// let 和 const 定义的变量在它们被定义的语句块之外不可访问
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
var
Will hoist the variable, which means the variable can be used before it is declared. let
and const
will not promote the variable, and an error will be reported if used in advance.
console.log(foo); // undefined
var foo = 'foo';
console.log(baz); // ReferenceError: can't access lexical declaration 'baz' before initialization
let baz = 'baz';
console.log(bar); // ReferenceError: can't access lexical declaration 'bar' before initialization
const bar = 'bar';
Repeating var
the statement with will not cause an error, but let
with and const
will.
var foo = 'foo';
var foo = 'bar';
console.log(foo); // "bar"
let baz = 'baz';
let baz = 'qux'; // Uncaught SyntaxError: Identifier 'baz' has already been declared
let
const
The difference between and is that let
multiple assignments are allowed, while const
only one is allowed.
// 这样不会报错。
let foo = 'foo';
foo = 'bar';
// 这样会报错。
const baz = 'baz';
baz = 'qux';
Can you give an example of using an arrow function and how it differs from other functions
An obvious advantage is that arrow functions can simplify the syntax of creating functions. We do not need to add function
keywords in front of arrow functions. And the arrow function this
will be automatically bound to the context of the current scope, which is different from ordinary functions. The value of a normal function this
can only be determined when it is executed. This feature of arrow functions is particularly useful for callback functions, especially for React
components.
What is the definition of higher-order function?
A higher-order function is a function that takes one or more functions as parameters, is used for data processing, and may also return a function as a result. Higher-order functions are used to abstract repetitive operations. A typical example is map
that it takes an array and a function as arguments. map
Use this function to convert each element in an array and return a new array containing the converted elements. Other common examples in JavaScript are forEach
, filter
and reduce
. Higher-order functions are not only used when you need to operate arrays, but there are also many use cases where functions return new functions. Function.prototype.bind
Just an example.
Map example
Suppose we have an array of names and we need to convert each character to uppercase.
const names = ['irish', 'daisy', 'anna'];
The method without using higher-order functions is this:
const transformNamesToUppercase = function (names) {
const results = [];
for (let i = 0; i < names.length; i++) {
results.push(names[i].toUpperCase());
}
return results;
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
Use .map(transformerFn)
to make your code more concise
const transformNamesToUppercase = function (names) {
return names.map((name) => name.toUpperCase());
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
Please give an example of destructuring an object or array.
Destructuring is a new feature in ES6, which provides a concise and convenient way to extract the values of an object or array and put them into different variables.
Array destructuring
// 变量赋值
const foo = ['one', 'two', 'three'];
const [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
// 变量交换
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
Object destructuring
// 变量赋值
const o = {p: 42, q: true};
const {p, q} = o;
console.log(p); // 42
console.log(q); // true
Can you give an example of a curry function? What are its benefits?
Currying is a pattern in which a function with multiple arguments is broken into multiple functions that, when called in series, accumulate all required arguments one at a time. This technique helps write functional style code, making the code more readable and compact. It's worth noting that for a function to be curryed, it needs to start with a function and then break it down into a series of functions, each of which takes a parameter.
function curry(fn) {
if (fn.length === 0) {
return fn;
}
function _curried(depth, args) {
return function (newArgument) {
if (depth - 1 === 0) {
return fn(...args, newArgument);
}
return _curried(depth - 1, [...args, newArgument]);
};
}
return _curried(fn.length, []);
}
function add(a, b) {
return a + b;
}
var curriedAdd = curry(add);
var addFive = curriedAdd(5);
var result = [0, 1, 2, 3, 4, 5].map(addFive); // [5, 6, 7, 8, 9, 10]