What are imaginary values in JavaScript?
const falsyValues = ['', 0, null, undefined, NaN, false];
Copy the code
Simply put, an imaginary value is a value that becomes false when converted to a Boolean value.
How do I check if a value is virtual?
Use Boolean functions or!! Operator.
24. What is the value of ‘this’ in JavaScript?
Basically, this refers to the value of the object on which the function is currently being executed or called. The value of this varies depending on the context in which we use it and where we use it.
const carDetails = {
name: "Ford Mustang",
yearBought: 2005,
getName(){
return this.name;
},
isRegistered: true
};
console.log(carDetails.getName()); // Ford Mustang
Copy the code
This is usually what we expect, because in the getName method we return this.name, and in this context this points to the carDetails object, which is currently the “owner” object of the executing function.
Now let’s do something weird:
var name = "Ford Ranger";
var getCarName = carDetails.getName;
console.log(getCarName()); // Ford Ranger
Copy the code
It prints Ford Ranger, which is strange because Ford Mustang is printed in the first console.log statement. The reason for this is that the getCarName method has a different “owner” object, the Window object. Declaring a variable using the var keyword in the global scope appends the same properties to the window object as the variable name. Remember, when “use strict” is not used, this refers to the window object in the global scope.
console.log(getCarName === window.getCarName); // true
console.log(getCarName === this.getCarName); // true
Copy the code
In this case, this and Window refer to the same object.
One way to solve this problem is to use the Apply and call methods in functions.
console.log(getCarName.apply(carDetails)); // Ford Mustang
console.log(getCarName.call(carDetails)); // Ford Mustang
Copy the code
The Apply and Call methods expect the first argument to be an object that is the value of this inside the function.
IIFE or immediately-executed function expressions, functions declared in global scope, anonymous functions in methods inside the object, and this of the internal function have default values that point to the window object.
(function (){ console.log(this); }) (); Function iHateThis(){console.log(this); } iHateThis(); // Print "window" object const myFavoriteObj = {guessThis(){function getName(){console.log(this.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); }}; myFavoriteObj.guessThis(); / / print "window" object myFavoriteObj. ThisIsAnnoying (function () {the console. The log (this); // Print the "window" object});Copy the code
If we want to get the value of the Name attribute (Marko Polo) in the myFavoriteObj object, there are two ways to solve this problem.
One is to store the this value in a variable.
const myFavoriteObj = { guessThis(){ const self = this; Function getName(){console.log(self.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); }};Copy the code
The second way is to use the arrow function
const myFavoriteObj = { guessThis(){ const getName = () => { console.log(this.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); }};Copy the code
Arrow functions do not have their own this. It copies the closed lexical scope this value, which in this case is outside the getName inner function, the myFavoriteObj object.
What is the prototype of the object?
Simply put, a prototype is a blueprint for an object. If it exists in the current object, it is used as a fallback for properties and methods. It’s a way of sharing properties and functionality between objects, which is at the heart of JavaScript implementation inheritance.
const o = {};
console.log(o.toString()); // logs [object Object]
Copy the code
Even if the O.tostring method does not exist in the O object, it does not raise an error, but returns the string [Object object]. When an object does not have an attribute, it looks at its prototype, and if it still does not, it looks to the prototype’s prototype, and so on, until it finds an attribute with the same attribute in the prototype chain. At the end of the prototype chain is Object.Prototype.
console.log(o.toString === Object.prototype.toString); // logs true
Copy the code
What is IIFE and what is it used for?
An IIFE or immediately invoked function expression is a function that will be called or executed after it has been created or declared. The syntax for creating IIFE is to wrap function(){} inside parentheses () and then call it with another parentheses (), as in :(function(){})()
(function(){ ... } ()); (function () { ... }) (); (function named(params) { ... }) (); (() = > {}); (function (global) { ... })(window); const utility = (function () { return { ... }})Copy the code
These examples are valid IIFE. The penultimate one shows that we can pass arguments to the IIFE function. The last example shows that we can save IIFE results to variables for later use.
One of the main functions of IIFE is to avoid naming conflicts with other variables in the global scope or contaminating the global namespace, for example.
<script src="https://cdnurl.com/somelibrary.js"></script>
Copy the code
Suppose we introduce a link to omelibr.js that provides some global functions that we use in our code, but the library has two methods that we don’t use: createGraph and drawGraph, because those methods are buggy. We want to implement our own createGraph and drawGraph methods.
One way to solve this problem is to override it directly:
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
function createGraph() {
// createGraph logic here
}
function drawGraph() {
// drawGraph logic here
}
</script>
Copy the code
When we use this solution, we override the two methods that the library provides us.
Another way is to change the name ourselves:
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
function myCreateGraph() {
// createGraph logic here
}
function myDrawGraph() {
// drawGraph logic here
}
</script>
Copy the code
When we use this solution, we change those function calls to the new function names.
Another way is to use IIFE:
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
const graphUtility = (function () {
function createGraph() {
// createGraph logic here
}
function drawGraph() {
// drawGraph logic here
}
return {
createGraph,
drawGraph
}
})
</script>
Copy the code
In this solution, we declare the graphUtility variable to store the results of IIFE execution, and this function returns an object containing the two methods createGraph and drawGraph.
IIFE can also be used to solve a common interview question:
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
li[i].addEventListener('click', function (e) {
console.log(i);
})
Copy the code
Suppose we have a UL element with a list-group class that has five li child elements. When we click on a single LI element, we print the corresponding subscript value. But in addition to that the above code doesn’t work, here each click on Li prints the value of I is 5 because of the closure.
Closures are simply the function’s ability to remember variable references to its current scope, parent function scope, and global scope. Global variable I is created when we declare variables in the global scope using the var keyword. Therefore, when we click on the Li element, it will print 5 because that is the value of I when it is referenced later in the callback function.
Using IIFE you can solve this problem:
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
(function (currentIndex) {
li[currentIndex].addEventListener('click', function (e) {
console.log(currentIndex);
})
})(i);
}
Copy the code
This solution works because IIFE creates a new scope for each iteration, and we capture the value of I and pass it to the currentIndex parameter, so IIFE is called with a different currentIndex value for each iteration.
Function.prototype. what is the use of the apply method?
The apply() method calls a function with a given this value and the arguments supplied as an array (or array-like object).
const details = { message: 'Hello World! '}; function getMessage(){ return this.message; } getMessage.apply(details); // 'Hello World! 'Copy the code
The call() method is similar to apply() except that call() takes a list of parameters, while apply() takes an array of parameters.
const person = {
name: "Marko Polo"
};
function greeting(greetingMessage) {
return `${greetingMessage} ${this.name}`;
}
greeting.apply(person, ['Hello']); // "Hello Marko Polo!"
Copy the code
What is the Function. Prototype. call ‘method used for?
The call() method calls a function with a specified this value and one or more arguments given separately.
const details = { message: 'Hello World! '}; function getMessage(){ return this.message; } getMessage.call(details); // 'Hello World! 'Copy the code
Note: The syntax and actions of this method are similar to those of apply(), except that call() accepts a list of arguments, while apply() accepts an array of arguments.
const person = {
name: "Marko Polo"
};
function greeting(greetingMessage) {
return `${greetingMessage} ${this.name}`;
}
greeting.call(person, 'Hello'); // "Hello Marko Polo!"
Copy the code
What’s the difference between function.prototype. apply and function.prototype. call?
The apply() method can invoke a function or method that uses a specified this value and an array of arguments (or array-like objects). The call() method is similar to apply(), except that call() takes a list of arguments.
const obj1 = { result:0 }; const obj2 = { result:0 }; function reduceAdd(){ let result = 0; for(let i = 0, len = arguments.length; i < len; i++){ result += arguments[i]; } this.result = result; } reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // 15 reduceAdd.call(obj2, 1, 2, 3, 4, 5); / / 15Copy the code
What is function.prototype. bind used for?
The bind() method creates a new function, and when bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function.
import React from 'react'; class MyComponent extends React.Component { constructor(props){ super(props); this.state = { value : "" } this.handleChange = this.handleChange.bind(this); HandleChange (e){//do something amazing here} render(){return (<> <input) type={this.props.type} value={this.state.value} onChange={this.handleChange} /> </> ) } }Copy the code
What is functional programming? What features of JavaScript make it a candidate for a functional language?
Functional programming (often abbreviated FP) is the process of building software by writing pure functions that avoid shared state, variable data, and side effects. Numerical programming is declarative rather than imperative, and application state flows through pure functions. In contrast to object-oriented programming, the state of an application is often shared and co-existed with methods in an object.
Functional programming is a programming paradigm, which means it’s a way of thinking about software construction based on some basic defining principles (listed above). Of course, other examples of programming paradigms include object-oriented programming and procedural programming.
Functional code tends to be cleaner, more predictable, and easier to test than imperative or object-oriented code – but without familiarity with it and the common patterns associated with it, functional code can also seem denser and cluttered, and the literature can be confusing to newcomers.
JavaScript support for closures and higher-order functions is characteristic of functional programming languages.
What is a higher-order function?
Higher-order functions are simply functions that take functions as arguments or return values.
function higherOrderFunction(param,callback){
return callback(param);
}
Copy the code
Why are functions called first-class citizens?
Function func(x,callback){callback(); function func(x,callback){callback(); }), return (function(){return function(){}}). In addition, functions in JavaScript act as constructors of classes and as instances of Function classes. Such multiple identities make JavaScript functions very important.
Implement the array.prototype.map method manually
The map() method creates a new array, and the result is the result returned when each element in the array calls one of the provided functions.
Function map(arr, mapCallback) {// First check whether the parameters passed are correct. if (! Array.isArray(arr) || ! arr.length || typeof mapCallback ! == 'function') { return []; } else { let result = []; // Every time we call this function, we create a result array because we don't want to change the original array. for (let i = 0, len = arr.length; i < len; i++) { result.push(mapCallback(arr[i], i, arr)); // Push the result returned by mapCallback into the result array} return result; }}Copy the code
Implement the array.prototype. filter method manually
The filter() method creates a new array containing all the elements of the test implemented through the provided function.
Function filter(arr, filterCallback) {// First, check whether the argument passed is correct. if (! Array.isArray(arr) || ! arr.length || typeof filterCallback ! == 'function') { return []; } else { let result = []; // Every time we call this function, we create a result array because we don't want to change the original array. for (let i = 0, len = arr.length; i < len; If (filterCallback(arr[I], I, arr)) {if (arr[I], arr)) { Result.push (arr[I]); } } return result; // return the result array } }Copy the code
36. Implement ‘array.prototype.reduce’ method manually
The reduce() method performs a reducer function (in ascending order) that you provide on each element in the array, summarizing its results into a single return value.
Function reduce(ARR, reduceCallback, initialValue) {// First, check whether the parameters passed are correct. if (! Array.isArray(arr) || ! arr.length || typeof reduceCallback ! == 'function') { return []; } else {// If initialValue is not passed to the function, we will use the first array entry as initialValue let hasInitialValue = initialValue! == undefined; let value = hasInitialValue ? initialValue : arr[0]; // If initialValue is passed, then the index starts from 1, otherwise from 0 for (let I = hasInitialValue? 0 : 1, len = arr.length; i < len; i++) { value = reduceCallback(value, arr[i], i, arr); } return value; }}Copy the code
37. What are arguments’ objects?
The Arguments object is a collection of parameter values passed in a function. It is an array-like object in that it has a length property and we can use array index notation arguments[1] to access individual values, but it does not have the built-in methods in arrays such as forEach, reduce, filter, and Map.
We can use array.prototype. slice to convert arguments objects to an Array.
function one() {
return Array.prototype.slice.call(arguments);
}
Copy the code
Note: not in the arrow functionarguments
Object.
function one() {
return arguments;
}
const two = function () {
return arguments;
}
const three = function three() {
return arguments;
}
const four = () => arguments;
four(); // Throws an error - arguments is not defined
Copy the code
When we call the function four, it raises a ReferenceError: Arguments is not defined error. Using rest syntax, you can solve this problem.
const four = (... args) => args;Copy the code
This automatically puts all parameter values into an array.
38. How do I create an object without a prototype?
We can use the object.create method to create objects without prototypes.
const o1 = {};
console.log(o1.toString()); // [object Object]
const o2 = Object.create(null);
console.log(o2.toString());
// throws an error o2.toString is not a function
Copy the code
39. Why does’ b ‘in the code become a global variable when this function is called?
function myFunc() {
let a = b = 0;
}
myFunc();
Copy the code
The reason is that the assignment operator evaluates from right to left. This means that when multiple assignment operators appear in an expression, they evaluate from right to left. So the code above looks like this:
function myFunc() {
let a = (b = 0);
}
myFunc();
Copy the code
First, the expression b = 0 is evaluated, in this case b is not declared. Therefore, the JS engine creates a global variable b outside of this function, after which the expression b = 0 returns 0 and assigns the new local variable A.
We can solve this problem by declaring variables before assigning them.
function myFunc() {
let a,b;
a = b = 0;
}
myFunc();
Copy the code
What is an arrow function?
Arrow function expressions have a much cleaner syntax than function expressions and don’t have their own this, arguments, super, or new.target. The arrow function expression is more useful where anonymous functions are needed, and it cannot be used as a constructor.
//ES5 Version
var getCurrentDate = function (){
return new Date();
}
//ES6 Version
const getCurrentDate = () => new Date();
Copy the code
In this case, the ES5 version has the function(){} declaration and the return keyword, which are needed to create the function and return value, respectively. In the arrow function version, we only need the () parentheses, not the return statement, because if we only have one expression or value to return, the arrow function will have an implicit return.
//ES5 Version function greet(name) { return 'Hello ' + name + '! '; } //ES6 Version const greet = (name) => `Hello ${name}`; const greet2 = name => `Hello ${name}`;Copy the code
We can also use the same arguments in arrow functions as function expressions and function declarations. If we have an argument in an arrow function, we can omit the parentheses.
const getArgs = () => arguments const getArgs2 = (... rest) => restCopy the code
Arrow functions cannot access arguments objects. So calling the first getArgs function throws an error. Instead, we can use rest arguments to get all the arguments passed in the arrow function.
const data = { result: 0, nums: [1, 2, 3, 4, 5], computeResult() {// Here "this" refers to "data" object const addAll = () => {return this.nums.reduce((total, cur) => total + cur, 0) }; this.result = addAll(); }};Copy the code
Arrow functions do not have their own this value. It captures the this value of the lexical scope function. In this example, the addAll function copies the this value from computeResult, which is the Window object if we declare the arrow function in the global scope.
What is a class?
Classes are a new way of writing constructors in JS. It is syntactic sugar that uses constructors, but still stereotypes and prototype-based inheritance are used underneath.
//ES5 Version function Person(firstName, lastName, age, address){ this.firstName = firstName; this.lastName = lastName; this.age = age; this.address = address; } Person.self = function(){ return this; } Person.prototype.toString = function(){ return "[object Person]"; } Person.prototype.getFullName = function (){ return this.firstName + " " + this.lastName; } //ES6 Version class Person { constructor(firstName, lastName, age, address){ this.lastName = lastName; this.firstName = firstName; this.age = age; this.address = address; } static self() { return this; } toString(){ return "[object Person]"; } getFullName(){ return `${this.firstName} ${this.lastName}`; }}Copy the code
Override the method and inherit from another class.
//ES5 Version Employee.prototype = Object.create(Person.prototype); function Employee(firstName, lastName, age, address, jobTitle, yearStarted) { Person.call(this, firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; } Employee.prototype.describe = function () { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; } Employee.prototype.toString = function () { return "[object Employee]"; } //ES6 Version class Employee extends Person { //Inherits from "Person" class constructor(firstName, lastName, age, address, jobTitle, yearStarted) { super(firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; } describe() { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; } toString() { // Overriding the "toString" method of "Person" return "[object Employee]"; }}Copy the code
So how do we know it’s using a prototype internally?
class Something {
}
function AnotherSomething(){
}
const as = new AnotherSomething();
const s = new Something();
console.log(typeof Something); // "function"
console.log(typeof AnotherSomething); // "function"
console.log(as.toString()); // "[object Object]"
console.log(as.toString()); // "[object Object]"
console.log(as.toString === Object.prototype.toString); // true
console.log(s.toString === Object.prototype.toString); // true
Copy the code
What is a template string?
Template strings are a new way to create strings in JS. We can string templates by using backquotes.
//ES5 Version
var greet = 'Hi I\'m Mark';
//ES6 Version
let greet = `Hi I'm Mark`;
Copy the code
In ES5 we need to use some escape characters to achieve multi-line effects, but in template strings we don’t need to bother as much:
//ES5 Version
var lastWords = '\n'
+ ' I \n'
+ ' Am \n'
+ 'Iron Man \n';
//ES6 Version
let lastWords = `
I
Am
Iron Man
`;
Copy the code
In the ES5 version, we need to add \n to add a new line to the string. In template strings, we don’t need to do this.
//ES5 Version function greet(name) { return 'Hello ' + name + '! '; } //ES6 Version function greet(name) { return `Hello ${name} ! `; }Copy the code
In the ES5 version, if you need to add an expression or value to a string, you use the + operator. In the template string S, we can embed an expression with ${expr}, which makes it cleaner than the ES5 version.
What is object deconstruction?
Object destruction is a new, more concise way to get or extract values from objects or arrays. Suppose we have the following objects:
const employee = {
firstName: "Marko",
lastName: "Polo",
position: "Software Developer",
yearHired: 2017
};
Copy the code
To get a property from an object, the early method was to create a variable with the same name as the property of the object. This approach is cumbersome because we create a new variable for each attribute. Let’s say we have a large object that has a lot of properties and methods, and it’s cumbersome to extract the properties this way.
var firstName = employee.firstName;
var lastName = employee.lastName;
var position = employee.position;
var yearHired = employee.yearHired;
Copy the code
The syntax is much more concise with deconstruction:
{ firstName, lastName, position, yearHired } = employee;
Copy the code
We can also alias attributes:
let { firstName: fName, lastName: lName, position, yearHired } = employee;
Copy the code
Of course, if the property value is undefined, we can also specify the default value:
let { firstName = "Mark", lastName: lName, position, yearHired } = employee;
Copy the code
What is the ES6 module?
Modules allow us to split the code base into multiple files for greater maintainability and avoid putting all the code in one large file. Before ES6 supported modules, there were two popular modules.
- CommonJS-Node.js
- AMD (Asynchronous Module definition) – Browser
Basically, the way to use a module is simple, with import used to get features or features or values from another file, and export used to expose features or features or values from a file.
export
Use the ES5 (CommonJS)
// ES5 CommonJS - helpers.js exports. IsNull = function (val) {return val === null; } exports.isUndefined = function (val) { return val === undefined; } exports.isNullOrUndefined = function (val) { return exports.isNull(val) || exports.isUndefined(val); }Copy the code
Use the ES6 module
// use ES6 modules-helpers. js export function isNull(val){return val === null; } export function isUndefined(val) { return val === undefined; } export function isNullOrUndefined(val) { return isNull(val) || isUndefined(val); }Copy the code
Import the function in another file
// ES5 (CommonJS) -index.js const helpers = require('./helpers.js'); // helpers is an object const isNull = helpers.isNull; const isUndefined = helpers.isUndefined; const isNullOrUndefined = helpers.isNullOrUndefined; // or if your environment supports Destructuring const { isNull, isUndefined, isNullOrUndefined } = require('./helpers.js'); ------------------------------------------------------- // ES6 Modules - index.js import * as helpers from './helpers.js'; // helpers is an object // or import { isNull, isUndefined, isNullOrUndefined as isValid } from './helpers.js'; // using "as" for renaming named exportsCopy the code
Export individual functions in a file or default export
Use the ES5 (CommonJS)
Class Helpers {static isNull(val) {return val === null; } static isUndefined(val) { return val === undefined; } static isNullOrUndefined(val) { return this.isNull(val) || this.isUndefined(val); } } module.exports = Helpers;Copy the code
Use the ES6 Modules
Js class helpers {static isNull(val) {return val === null; } static isUndefined(val) { return val === undefined; } static isNullOrUndefined(val) { return this.isNull(val) || this.isUndefined(val); } } export default HelpersCopy the code
Import a single function from another file
Use the ES5 (CommonJS)
// ES5 (CommonJS) -index.js const Helpers = require('./helpers.js'); console.log(Helpers.isNull(null));Copy the code
Use the ES6 Modules
import Helpers from '.helpers.js'
console.log(Helpers.isNull(null));
Copy the code
What is a ‘Set’ object and how does it work?
The Set object allows you to store a unique value of any type, either a primitive value or an object reference.
We can use the Set constructor to create a Set instance.
const set1 = new Set();
const set2 = new Set(["a","b","c","d","d","e"]);
Copy the code
We can use the add method to add a new value to the Set instance. Since the add method returns a Set object, we can use Add again in chained fashion. If a value already exists in a Set object, it is no longer added.
set2.add("f"); set2.add("g").add("h").add("i").add("j").add("k").add("k"); // The latter "k" will not be added to the set object because it already existsCopy the code
We can use the HAS method to check for the presence of a specific value in a Set instance.
set2.has("a") // true
set2.has("z") // true
Copy the code
We can use the size attribute to get the length of the Set instance.
set2.size // returns 10
Copy the code
You can use the clear method to delete data from a Set.
set2.clear();
Copy the code
We can use the Set object to remove duplicate elements from an array.
const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5]; const uniqueNums = [...new Set(numbers)]; / /,2,3,4,5,6,7,8 [1]Copy the code
What is a callback function?
A callback is an executable piece of code that is passed to other code as an argument to call it if needed.
In JavaScript, functions are also objects, and objects can be passed as arguments to functions, so functions can be passed as arguments to another function, called a callback function.
const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener('click', function clickCallback(e) {
// do something useless
});
Copy the code
In this case, we wait for the click event in the element with id btnAdd, and if it is clicked, the clickCallback function is executed. Callbacks add functionality to some data or event.
The reduce, filter, and map methods in the array require a callback as a parameter. A good analogy for a callback is when you call someone and if they don’t answer, you leave a message and you expect them to call back. The action of calling someone or leaving a message is the event or data, and the callback is the action you want to happen later.
What is Promise?
Promises are a solution to asynchronous programming: syntactically, promises are an object from which to retrieve messages for asynchronous operations; In its original sense, it is a promise that will give you results over time. Promise has three states: pending, fulfiled, and Rejected. Once the state has changed, it will never change. Once a Promise instance is created, it executes immediately.
fs.readFile('somefile.txt', function (e, data) {
if (e) {
console.log(e);
}
console.log(data);
});
Copy the code
There is a problem with this method if we have another asynchronous operation inside the callback. We would have a messy and unreadable code. This code is called “callback hell” **.
//your code here fs.readdir('directory', function (e, data) {//your code here fs.readdir('directory', function (e, data)) {// Your code here fs.readdir('directory', function (e, data)) files) { //your code here fs.mkdir('directory', function (e) { //your code here }) }) })Copy the code
If we use promise in this code, it will be easier to read, understand, and maintain.
promReadFile('file/path')
.then(data => {
return promReaddir('directory');
})
.then(data => {
return promMkdir('directory');
})
.catch(e => {
console.log(e);
})
Copy the code
Promises come in three different states:
- Pending: Initial state, the state preceding the completed or failed state
- This is a pity: The operation is completed successfully
- Rejected: The operation fails
A Promise object with a pending state triggers the fulfilled/ Rejected state, and parameter/failure information can be passed in its state processing method. When the operation completes successfully, the then method of the Promise object is called; Otherwise a catch is triggered. Such as:
Const myFirstPromise = new Promise((resolve, reject) => {setTimeout(function(){resolve(" success! ); }, 250); }); myFirstPromise.then((data) => { console.log("Yay! " + data); }).catch((e) => {... });Copy the code
What is’ async/await ‘and how does it work?
Async /await is a new way of writing asynchronous or non-blocking code in JS. It is built on Promises to make asynchronous code readable and concise.
Async /await is a new way of writing asynchronous or non-blocking code in JS. It was built on Promises. It was much more readable and concise than Promises and callbacks. However, before using this feature, we have to learn the basics of Promises because, as I said before, it is built on Promises, which means Promises are still used behind the scenes.
The use of Promise
function callApi() {
return fetch("url/to/api/endpoint")
.then(resp => resp.json())
.then(data => {
//do something with "data"
}).catch(err => {
//do something with "err"
});
}
Copy the code
Use the async/await
In async/await, we use tru/catch syntax to catch exceptions.
async function callApi() {
try {
const resp = await fetch("url/to/api/endpoint");
const data = await resp.json();
//do something with "data"
} catch (e) {
//do something with "err"
}
}
Copy the code
Note: Using the async key declaration function implicitly returns a Promise.
const giveMeOne = async () => 1;
giveMeOne()
.then((num) => {
console.log(num); // logs 1
});
Copy the code
Note: The await keyword can only be used in async function. Using the await keyword in any function that is not async function throws an error. The await keyword waits for the expression on the right (perhaps a Promise) to return before executing the next line of code.
const giveMeOne = async () => 1; function getOne() { try { const num = await giveMeOne(); console.log(num); } catch (e) { console.log(e); } } // Uncaught SyntaxError: await is only valid in async function async function getTwo() { try { const num1 = await giveMeOne(); Const num2 = await giveMeOne(); return num1 + num2; } catch (e) { console.log(e); } } await getTwo(); / / 2Copy the code
What is the difference between the spread operator and the Rest operator?
The spread operator is three points (…) , you can convert an array to a comma-separated sequence of arguments. Say of easy to understand point, a bit like changing bone sponge palm, a big element to break apart into a separate small element.
The remainder operator also uses three dots (…). It looks the same as the expansion operator, but is used to deconstruct arrays and objects. In some ways, a residual element is the opposite of an expanded element, which “expands” the array into multiple elements, and a residual element collects multiple elements and “compresses” them into a single element.
function add(a, b) { return a + b; }; const nums = [5, 6]; const sum = add(... nums); console.log(sum);Copy the code
In this case, we use the expansion operator when we call the add function to expand the NUMS array. So the value of parameter A is 5, the value of parameter B is 6, so sum is 11.
function add(... rest) { return rest.reduce((total,current) => total + current); }; console.log(add(1, 2)); // 3 console.log(add(1, 2, 3, 4, 5)); / / 15Copy the code
In this case, we have an Add function that takes any number of arguments, adds them all up, and returns the total.
const [first, ...others] = [1, 2, 3, 4, 5]; console.log(first); // 1 console.log(others); / / 5-tetrafluorobenzoic [2]Copy the code
Here, we use the residual operator to extract all the remaining array values and place them in an array other than the first item.
What are the default parameters?
Default parameters are a new way to define default variables in JS and are available in ES6 or ECMAScript 2015 versions.
//ES5 Version
function add(a,b){
a = a || 0;
b = b || 0;
return a + b;
}
//ES6 Version
function add(a = 0, b = 0){
return a + b;
}
add(1); // returns 1
Copy the code
We can also use deconstruction in the default parameters.
function getFirst([first, ...rest] = [0, 1]) { return first; } getFirst(); / / 0 getFirst (10, 30 []); // 10 function getArr({ nums } = { nums: [1, 2, 3, 4] }){ return nums; } getArr(); // [1, 2, 3, 4] getArr({nums:[5,4,3, 1]}); / /,4,3,2,1 [5]Copy the code
We can also use the parameters defined first to define the parameters after them.
function doSomethingWithValue(value = "Hello World", callback = () => { console.log(value) }) {
callback();
}
doSomethingWithValue(); //"Hello World"
Copy the code
What is a Wrapper object?
Now let’s review the JS data types. JS data types are divided into two broad categories, basic types and reference types.
Basic types: Undefined, Null, Number, Boolean, String, Symbol, BigInt
Reference types: Object,Array,Date,RegExp, etc.
Where reference types have methods and attributes, primitive types don’t, but we often see code like this:
let name = "marko";
console.log(typeof name); // "string"
console.log(name.toUpperCase()); // "MARKO"
Copy the code
The name type is string, which is a primitive type, so it has no properties or methods, but in this case, we call a toUpperCase() method, which does not throw an error and returns the variable value of the object.
The reason is that values of primitive types are temporarily cast or cast to objects, so the name variable behaves like an object. Each basic type except null and undefined has its own wrapper object. That is: String, Number, Boolean, Symbol and BigInt. In this case, name.toupperCase () looks like this behind the scenes:
console.log(new String(name).toUpperCase()); // "MARKO"
Copy the code
The newly created object is discarded immediately after accessing the property or calling the method.
What is the difference between implicit and explicit conversions?
An implicit cast is a way to convert a value to another type, and the process is done automatically without us having to do it manually.
Suppose we have an example below.
console.log(1 + '6'); // 16 console.log(false + true); // 1 console.log(6 * '2'); / / 12Copy the code
The first console.log statement results in 16. In other languages, this throws a compile-time error, but in JS, 1 is converted to a string and then concatenated with the + operator. We didn’t do anything, it was done automatically by JS.
The second console.log statement results in 1, JS converts false to Boolean value 0, and true is 1, so the result is 1.
The third console.log statement results in 12, which converts ‘2’ to a number and then multiplies it by 6 * 2, resulting in 12.
Explicit coercion is a way to convert a value to another type, which we need to do manually.
console.log(1 + parseInt('6'));
Copy the code
In this case, we use the parseInt function to convert ‘6’ to number, and then use the + operator to add 1 and 6.
What is NaN? And how do I check if the value is NaN?
NaN means ** “non-number” ** is a value in JS that is the result of an operation that converts or executes a number to a non-number value, so the result is NaN.
let a;
console.log(parseInt('abc')); // NaN
console.log(parseInt(null)); // NaN
console.log(parseInt(undefined)); // NaN
console.log(parseInt(++a)); // NaN
console.log(parseInt({} * 10)); // NaN
console.log(parseInt('abc' - 2)); // NaN
console.log(parseInt(0 / 0)); // NaN
console.log(parseInt('10a' * 10)); // NaN
Copy the code
JS has a built-in isNaN method that tests whether a value is an isNaN value, but this function has a strange behavior.
console.log(isNaN()); // true
console.log(isNaN(undefined)); // true
console.log(isNaN({})); // true
console.log(isNaN(String('a'))); // true
console.log(isNaN(() => { })); // true
Copy the code
All of these console.log statements return true, even if we passed a value other than NaN.
In ES6, it is recommended to use the number. isNaN method, because it does check for the value (if it is indeed NaN), or we can have our own helper function check for this problem, because NaN is the only value in JS that is not equal to itself.
function checkIfNaN(value) { return value ! == value; }Copy the code
How do I determine if a value is an array?
We can use the array. isArray method to check if the value is an Array. It returns true if the argument passed to it is an array, false otherwise.
console.log(Array.isArray(5)); // false
console.log(Array.isArray("")); // false
console.log(Array.isArray()); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray({ length: 5 })); // false
console.log(Array.isArray([])); // true
Copy the code
If your environment does not support this approach, you can implement it using Polyfill.
function isArray(value){
return Object.prototype.toString.call(value) === "[object Array]"
}
Copy the code
Of course, you can use the traditional method:
Let a = [] if (a instanceof Array) {console.log(' is Array ')} else {console.log(' is Array ')}Copy the code
How do I check if a number is even without using the % modulo operator?
We can use the bitwise & operator for this problem, which operates on its operand as a binary value, and then performs the and operation.
function isEven(num) {
if (num & 1) {
return false
} else {
return true
}
}
Copy the code
0 binary number is 000. 1 Binary number is 001. 2 Binary number is 010. 3 Binary number is 011
And so on…
The rules of and operation are as follows:
a
b
a & b
0
0
0
0
1
0
1
1
1
Therefore, when we execute the expression console.log(5&1), the result is 1. First, the & operator converts both numbers to binary, so 5 becomes 101 and 1 becomes 001.
It then compares each bit (0 and 1) using the bitwise operator. 101&001, as you can see from the table, if a &b is 1, so 5&1 is 1.
101 & 001
101
001
001
- First let’s compare the leftmost one
1& 0
As a result,0
. - And then we compare the middle one
0& 0
As a result,0
. - And then we compare the last
1& 1
As a result,1
. - Finally, you get a binary number
001
, the corresponding decimal number, i.e1
. And from that we can also figure outconsole.log(4 & 1)
The results for0
. know4
The last digit of PI is PI0
And the0 and 1
It will be0
. If this is difficult for you to understand, we can use recursive functions to solve the problem. - function isEven(num) { if (num < 0 || num === 1) return false; if (num == 0) return true; return isEven(num – 2); }
How do I check if an attribute exists in an object?
There are three ways to check for the presence of attributes in an object.
The first uses in to manipulate the symbol:
const o = {
"prop" : "bwahahah",
"prop2" : "hweasa"
};
console.log("prop" in o); // true
console.log("prop1" in o); // false
Copy the code
The second method uses the hasOwnProperty method. The hasOwnProperty() method returns a Boolean value indicating whether the object has the specified property in its own properties (that is, whether it has the specified key).
console.log(o.hasOwnProperty("prop2")); // true
console.log(o.hasOwnProperty("prop1")); // false
Copy the code
The third uses the parenthesis symbol obj[“prop”]. It returns the value of the property if it exists, undefined otherwise.
console.log(o["prop"]); // "bwahahah"
console.log(o["prop1"]); // undefined
Copy the code
How do I create objects in JS?
Use object literals:
Const o = {name: "greeting ", greeting() {return 'Hi, I'm ${this.name}'; }}; o.greeting(); // "Hi, I'm a front-end smarty"Copy the code
Using constructors:
function Person(name) { this.name = name; } Person. The prototype. The greeting = function () {return ` Hi, I am a ${this. The name} `; } const mark = new Person(" new Person "); mark.greeting(); // "Hi, I'm a front-end smarty"Copy the code
Use the object.create method:
Const n = {greeting() {return 'Hi, I'm ${this.name}'; }}; const o = Object.create(n); O.name = "front-end smarts ";Copy the code
What is the difference between the object.seal and object.freeze methods?
Object.freeze()
The object.freeze () method freezes an Object. A frozen object can no longer be modified. If you freeze an object, you cannot add new attributes to the object, delete existing attributes, modify the enumerability, configurability, writability of existing attributes of the object, or modify the value of existing attributes. In addition, the stereotype of an object cannot be modified after it is frozen. Freeze () returns the same object as the argument passed in.
Object.seal()
The object.seal () method seals an Object, preventing the addition of new properties and marking all existing properties as unconfigurable. The value of the current property can be changed as soon as it is writable.Copy the code
Similarities of methods:
- ES5 added.
- Objects cannot be extended, that is, new properties or methods cannot be added.
- Existing attributes of an object cannot be deleted.
- Object properties cannot be reconfigured.
Differences of methods:
Object.seal
Method that can modify property values if the property is writable.* Object.freeze
Properties of frozen objects generated by the method are not writable, that is, their values cannot be changed.