This year, major companies have reduced HC and even adopted “layoff” measures. Under such a big environment, it is necessary to make more efforts to get a better job.
This article selected 20 to large factory interview questions, when reading, we suggest not to look at my answer first, but to think about it first. Although, all the answers in this article were given only after I read all kinds of materials, thought and verified them. However, due to limited level, my answer is not necessarily the best. If you have a better answer, please leave me a message.
This article is a long one. I hope my friends can stick to it. If you want to join the communication group, you can add me as a good friend through the public number at the end of the article.
More quality articles to stamp on: https://github.com/YvetteLau/ …
1. What is the implementation principle of New?
new
The implementation principle of:
- Creates an empty object to which this in the constructor points
- This new object is connected by [[prototype]]
- Executes constructor methods, attributes, and methods are added to the object referenced by this
- If no other object is returned in the constructor, this is the new object created for this; otherwise, the object returned in the constructor is returned.
function _new() {
let target = {}; //创建的新对象
//第一个参数是构造函数
let [constructor, ...args] = [...arguments];
//执行[[原型]]连接;target 是 constructor 的实例
target.__proto__ = constructor.prototype;
//执行构造函数,将属性或方法添加到创建的空对象上
let result = constructor.apply(target, args);
if (result && (typeof (result) == "object" || typeof (result) == "function")) {
//如果构造函数执行的结构返回的是一个对象,那么返回这个对象
return result;
}
//如果构造函数返回的不是一个对象,返回创建的新对象
return target;
}
How to correctly judge the direction of this?
If you use one sentence to explain the direction of this, that is, whoever calls it, this points to whom.
However, through this sentence alone, we often cannot accurately judge the direction of this. Therefore, we need to use some rules to help ourselves:
The direction of this can be judged in the following order:
This in the Global Environment
Browser environment: whether in strict mode or not, this points to global objects in the global execution environment (outside any function body)window
;
Node Environment: this is an empty object in the global execution environment (outside any function body) regardless of whether it is in strict mode or not.{}
;
Is itnew
Binding
If it isnew
Binding, and no function or object is returned in the constructor, this points to this new object. As follows:
The constructor return value is not function or object.
new Super()
This object is returned.
function Super(age) {
this.age = age;
}
let instance = new Super('26');
console.log(instance.age); //26
The return value of the constructor is function or object.
new Super()
However, the returned object is Super.
function Super(age) {
this.age = age;
let obj = {a: '2'};
return obj;
}
let instance = new Super('hello');
console.log(instance);//{ a: '2' }
console.log(instance.age); //undefined
Whether the function is called through call,apply, or bind binding is used; if so, this binds the specified object [boils down to explicit binding].
function info(){
console.log(this.age);
}
var person = {
age: 20,
info
}
var age = 28;
var info = person.info;
info.call(person); //20
info.apply(person); //20
info.bind(person)(); //20
Here also need to pay attention to aSpecialCase, if the first parameter value passed in by call,apply, or bind isundefined
Or ..null
, the value of this in strict mode is the passed-in value null /undefined. In non-strict mode, this refers to the global object (the node environment is global and the browser environment is window) as the default binding rule applied in practice.
function info(){
//node环境中:非严格模式 global,严格模式为null
//浏览器环境中:非严格模式 window,严格模式为null
console.log(this);
console.log(this.age);
}
var person = {
age: 20,
info
}
var age = 28;
var info = person.info;
//严格模式抛出错误;
//非严格模式,node下输出undefined(因为全局的age不会挂在 global 上)
//非严格模式。浏览器环境下输出 28(因为全局的age会挂在 window 上)
info.call(null);
Implicit binding, the function call is triggered on an object, that is, there is a context object at the call location. Typical implicit calls are:xxx.fn()
function info(){
console.log(this.age);
}
var person = {
age: 20,
info
}
var age = 28;
person.info(); //20;执行的是隐式绑定
The default binding, which is used when other binding rules cannot be applied, is usually an independent function call.
Non-strict mode: node environment, execute global object global, browser environment, execute global object window.
Strict mode: execute undefined
function info(){
console.log(this.age);
}
var age = 28;
//严格模式;抛错
//非严格模式,node下输出 undefined(因为全局的age不会挂在 global 上)
//非严格模式。浏览器环境下输出 28(因为全局的age会挂在 window 上)
//严格模式抛出,因为 this 此时是 undefined
info();
In case of arrow function:
The arrow function does not have its own this, which inherits this bound by the outer context.
let obj = {
age: 20,
info: function() {
return () => {
console.log(this.age); //this继承的是外层上下文绑定的this
}
}
}
let person = {age: 28};
let info = obj.info();
info(); //20
let info2 = obj.info.call(person);
info2(); //28
3. What is the difference between deep copy and shallow copy? Realize a deep copy
Deep copy and shallow copy are for complex data types. Shallow copy only copies one layer, while deep copy is a layer-by-layer copy.
Deep copy
Deep copy copies variable values. For variables of non-basic type, it will be copied after recursion to variables of basic type. The object after the deep copy is completely isolated from the original object and does not affect each other, and the modification of one object does not affect the other.
Shallow copy
Shallow copy copies each attribute of an object in turn. However, when the attribute value of an object is a reference type, what is actually copied is its reference. When the value pointed to by the reference changes, it will also change accordingly.
Can be usedfor in
、Object.assign
, extension operator...
、Array.prototype.slice()
、Array.prototype.concat()
For example:
let obj = {
name: 'Yvette',
age: 18,
hobbies: ['reading', 'photography']
}
let obj2 = Object.assign({}, obj);
let obj3 = {...obj};
obj.name = 'Jack';
obj.hobbies.push('coding');
console.log(obj);//{ name: 'Jack', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj2);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj3);//{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
It can be seen that the shallow copy only copies the attribute of the first layer. When the attribute value of the first layer is the basic data type, the new object and the original object do not affect each other. However, if the attribute value of the first layer is the complex data type, the attribute value of the new object and the original object point to the same memory address.
Deep copy implementation
1. The simplest implementation of deep copy is:
JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj))
Is the simplest implementation, but there are some drawbacks:
- Object cannot be copied when its attribute value is a function.
- Attributes on prototype chain cannot be copied
- Data of type Date cannot be processed correctly
- RegExp cannot be processed
- Symbol is ignored
- Ignoring undefined
2. implement a deepClone function
- If it is a basic data type, directly return
- If it is
RegExp
Or ..Date
Type, returns the corresponding type - If it is a complex data type, recursion.
- Consider the problem of circular references
function deepClone(obj, hash = new WeakMap()) { //递归拷贝
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (obj === null || typeof obj !== 'object') {
//如果不是复杂数据类型,直接返回
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
let t = new obj.constructor();
hash.set(obj, t);
for (let key in obj) {
//递归
if (obj.hasOwnProperty(key)) {//是否是自身的属性
t[key] = deepClone(obj[key], hash);
}
}
return t;
}
4. What is the implementation principle of CALL/APPLY?
Call and apply have the same function and are both changes.this
And execute the function immediately. The difference lies in the different ways of parameter transmission.
-
func.call(thisArg, arg1, arg2, ...)
: The first parameter isthis
Pointed to the object, other parameters are passed in sequence. -
func.apply(thisArg, [argsArray])
: The first parameter isthis
The second parameter is an array or class array.
Let’s think about how to simulate the implementation.call
?
First of all, we know that functions can be calledcall
, descriptioncall
It is a method on a function prototype, and all instances can be called. That is:Function.prototype.call
.
- In
call
Gets the call from thecall()
Function - If the first parameter is not passed in, the default point is
window / global
(Non-strict Mode) - afferent
call
The first parameter of is the object this points to. According to the implicit binding rule, we know thatobj.foo()
,foo()
hit the targetthis
point toobj
; So we can call the function like thisthisArgs.func(...args)
- Returns the execution result
Function.prototype.call = function() {
let [thisArg, ...args] = [...arguments];
if (!thisArg) {
//context为null或者是undefined
thisArg = typeof window === 'undefined' ? global : window;
}
//this的指向的是当前函数 func (func.call)
thisArg.func = this;
//执行函数
let result = thisArg.func(...args);
delete thisArg.func; //thisArg上并没有 func 属性,因此需要移除
return result;
}
The realization thought and method of bindcall
Consistent, only slightly different parameter processing. As follows:
Function.prototype.apply = function(thisArg, rest) {
let result; //函数返回结果
if (!thisArg) {
//context为null或者是undefined
thisArg = typeof window === 'undefined' ? global : window;
}
//this的指向的是当前函数 func (func.call)
thisArg.func = this;
if(!rest) {
//第二个参数为 null / undefined
result = thisArg.func();
}else {
result = thisArg.func(...rest);
}
delete thisArg.func; //thisArg上并没有 func 属性,因此需要移除
return result;
}
5. Realization of Coritization Function
Before we begin, we first need to make clear the concept of function kriging.
Corellization of functions is a technique that transforms a function that accepts multiple parameters into a function that accepts a single parameter (the first parameter of the original function), and returns a new function that accepts the remaining parameters and returns the result.
const curry = (fn, ...args) =>
args.length < fn.length
//参数长度不足时,重新柯里化该函数,等待接受新参数
? (...arguments) => curry(fn, ...args, ...arguments)
//参数长度满足时,执行函数
: fn(...args);
function sumFn(a, b, c) {
return a + b + c;
}
var sum = curry(sumFn);
console.log(sum(2)(3)(5));//10
console.log(sum(2, 3, 5));//10
console.log(sum(2)(3, 5));//10
console.log(sum(2, 3)(5));//10
The Main Functions of Curriculation of Functions;
- Parameter reuse
- Return in advance–returns a new function that accepts the remaining parameters and returns the result
- Delayed execution–returns a new function and waits for execution
6. How to make the value of (a == 1 && a == 2 && a == 3) true?
- Using implicit type conversion
==
When the left and right data types of operators are inconsistent, implicit conversion will be performed first.
a == 1 && a == 2 && a == 3
The value of means that it cannot be a basic data type. Because if a is null or undefined bool type, it is impossible to return true.
Therefore, it can be inferred that A is a complex data type, and only complex data types in JSobject
Recall what method will be called when Object is converted to the original type?
- If deployed
[Symbol.toPrimitive]
Interface, then call this interface, if the return is not the basic data type, throw an error. -
If not deployed
[Symbol.toPrimitive]
Interface, then according to the type to be converted, first call thevalueOf
/toString
- Non-Date type objects,
hint
Yesdefault
, the call order is:valueOf
>>>toString
, i.e.valueOf
The return is not the basic data type, and the call will continue.valueOf
IftoString
If the returned data type is not the basic data type, an error is thrown. - If
hint
Yesstring
(hint of Date object defaults to string), and the calling order is:toString
>>>valueOf
, i.e.toString
The return is not the basic data type, and the call will continue.valueOf
IfvalueOf
If the returned data type is not the basic data type, an error is thrown. - If
hint
Yesnumber
, call order is:valueOf
>>>toString
- Non-Date type objects,
//部署 [Symbol.toPrimitive] / valueOf/ toString 皆可
//一次返回1,2,3 即可。
let a = {
[Symbol.toPrimitive]: (function(hint) {
let i = 1;
//闭包的特性之一:i 不会被回收
return function() {
return i++;
}
})()
}
- Using Proxy/Object.definedProperty
let i = 1;
let a = new Proxy({}, {
i: 1,
get: function () {
return () => this.i++;
}
});
- Array of
toString
The interface calls the of the array by defaultjoin
Methods, tojoin
Method
let a = [1, 2, 3];
a.join = a.shift;
7. What is BFC? What are the layout rules of BFC? How to create BFC?
Box is the object and basic unit of CSS layout, and the page is made up of several boxes.
The type and of the elementdisplay
Property determines the type of this Box. Different types of boxes participate in different Formatting Context.
Formatting Context
Formatting Context is a rendering area of a page and has a set of rendering rules that determine how its child elements will be located and their relationships and interactions with other elements.
Formatting Context includes BFC (Block formatting context), IFC (Inline formatting context), FFC (Flex formatting context) and GFC (Grid formatting context). FFC and GFC are added to CC3.
- In BFC, the boxes are arranged vertically in turn.
- In BFC, the vertical distance between the two boxes is determined by
margin
Attribute determination. Margins of two adjacent boxes belonging to the same BFC will overlap [large margins will be used after merging the margins conforming to the merging principle] - In BFC, the left outer edge of each box contacts the left edge of the inner box (for right-to-left formats, the right edge contacts). Even in the presence of floating. Unless a new BFC is created.
- The BFC area does not overlap with the float box.
- BFC is an isolated and independent container on the page. The sub-elements inside the container will not affect the elements outside. And vice versa.
- When calculating the height of BFC, floating elements also participate in the calculation.
How to create BFC
- Root element
- Floating element (float attribute is not none)
- Position is absolute or fixed.
- Overflow is not a visible block element
- Display is inline-block, table-cell, table-capture.
Application of BFC
- Prevent margin from Overlapping (for two adjacent Box within the same BFC
margin
Overlap will occur, triggering the generation of two BFC, i.e. no overlap) - Clear the internal float (create a new BFC, because according to BFC rules, when calculating the height of BFC, floating elements also participate in the calculation)
- Adaptive multi-column layout (BFC area does not overlap with float box. Therefore, generation of a new BFC) can be triggered
8. What are the ways to load JS scripts asynchronously?
<script>
Added to labelasync
(html5) ordefer
(html4) attribute, the script will be loaded asynchronously.
<script src="../XXX.js" defer></script>
defer
Andasync
The difference lies in:
-
defer
When the normal rendering of the whole page in memory is finished (DOM structure is fully generated and other scripts are executed), it is executed before window.onload; -
async
Once the download is complete, the rendering engine will stop rendering and continue rendering after executing this script. - If there are multiple
defer
Scripts are loaded in the order in which they appear on the page - Multiple
async
Scripts cannot guarantee the loading order
Dynamic creation
script
Label
Dynamically createdscript
, settingssrc
The JS file will not start downloading until it is added to the document.
let script = document.createElement('script');
script.src = 'XXX.js';
// 添加到html文件中才会开始下载
document.body.append(script);
XHR asynchronous loading JS
let xhr = new XMLHttpRequest();
xhr.open("get", "js/xxx.js",true);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
eval(xhr.responseText);
}
}
9. How many ways can ES5 implement inheritance? What are the advantages and disadvantages respectively?
ES5 can be inherited in 6 ways, namely:
1. 原型链继承
The basic idea of prototype chain inheritance is to use prototypes to let one reference type inherit the attributes and methods of another reference type.
function SuperType() {
this.name = 'Yvette';
this.colors = ['pink', 'blue', 'green'];
}
SuperType.prototype.getName = function () {
return this.name;
}
function SubType() {
this.age = 22;
}
SubType.prototype = new SuperType();
SubType.prototype.getAge = function() {
return this.age;
}
SubType.prototype.constructor = SubType;
let instance1 = new SubType();
instance1.colors.push('yellow');
console.log(instance1.getName()); //'Yvette'
console.log(instance1.colors);//[ 'pink', 'blue', 'green', 'yellow' ]
let instance2 = new SubType();
console.log(instance2.colors);//[ 'pink', 'blue', 'green', 'yellow' ]
Disadvantages:
- When inheritance is realized through a prototype, the prototype becomes an instance of another type, the original instance attribute becomes the current prototype attribute, and the reference type attribute of the prototype is shared by all instances.
- When creating instances of subtypes, there is no way to pass parameters to supertype constructors without affecting all object instances.
2. 借用构造函数
Borrowing constructorTechnology, its basic idea is:
Call the supertype constructor in the subtype constructor.
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
function SubType(name) {
SuperType.call(this, name);
}
let instance1 = new SubType('Yvette');
instance1.colors.push('yellow');
console.log(instance1.colors);//['pink', 'blue', 'green', yellow]
let instance2 = new SubType('Jack');
console.log(instance2.colors); //['pink', 'blue', 'green']
Advantages:
- You can pass parameters to superclasses
- The problem that the reference type value contained in the prototype is shared by all instances is solved
Disadvantages:
- Methods are defined in constructors, function reuse is impossible, and methods defined in supertype prototypes are invisible to subtypes.
3. 组合继承(原型链 + 借用构造函数)
Combination inheritance refers to an inheritance mode that combines prototype chain and borrowing constructor technology together to give full play to the advantages of both. Basic ideas:
The prototype chain is used to inherit the prototype attributes and methods, and the constructor is used to inherit the instance attributes. The method is defined on the prototype to realize function reuse, and each instance has its own attributes.
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
}
function SuberType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SuberType.prototype = new SuperType();
SuberType.prototype.constructor = SuberType;
SuberType.prototype.sayAge = function () {
console.log(this.age);
}
let instance1 = new SuberType('Yvette', 20);
instance1.colors.push('yellow');
console.log(instance1.colors); //[ 'pink', 'blue', 'green', 'yellow' ]
instance1.sayName(); //Yvette
let instance2 = new SuberType('Jack', 22);
console.log(instance2.colors); //[ 'pink', 'blue', 'green' ]
instance2.sayName();//Jack
Disadvantages:
- In any case, the supertype constructor is called twice: once when the subtype prototype is created, and once inside the subtype constructor.
Advantages:
- You can pass parameters to superclasses
- Each instance has its own attributes
- Function reuse is realized
4. 原型式继承
The Basic Idea of Prototype Inheritance;
Prototypes allow you to create new objects based on existing objects without creating custom types.
function object(o) {
function F() { }
F.prototype = o;
return new F();
}
Inobject()
Inside the function, a temporary constructor is first passed through, then the passed-in object is taken as the prototype of the constructor, and finally a new instance of the temporary type is returned. In essence,object()
A shallow copy was performed on the incoming object.
ECMAScript5 by addingObject.create()
The method standardizes prototype inheritance. This method receives two parameters: an object used as the prototype of the new object and (optionally) an object defining additional attributes for the new object (which can override the same name attribute on the prototype object). If a parameter is passed in,Object.create()
Andobject()
The method behaves the same.
var person = {
name: 'Yvette',
hobbies: ['reading', 'photography']
}
var person1 = Object.create(person);
person1.name = 'Jack';
person1.hobbies.push('coding');
var person2 = Object.create(person);
person2.name = 'Echo';
person2.hobbies.push('running');
console.log(person.hobbies);//[ 'reading', 'photography', 'coding', 'running' ]
console.log(person1.hobbies);//[ 'reading', 'photography', 'coding', 'running' ]
Prototype inheritance is competent when it is not necessary to create constructors and only to keep one object similar to another.
Disadvantages:
As with prototype chain implementation inheritance, attributes containing reference type values are shared by all instances.
5. 寄生式继承
Parasitic inheritance is closely related to prototype inheritance. The idea of parasitic inheritance is similar to that of parasitic constructors and factory patterns, that is, to create a function that is only used to encapsulate the inheritance process. The function has internally enhanced the object in some way, and finally returns the object as if it did all the work.
function createAnother(original) {
var clone = object(original);//通过调用函数创建一个新对象
clone.sayHi = function () {//以某种方式增强这个对象
console.log('hi');
};
return clone;//返回这个对象
}
var person = {
name: 'Yvette',
hobbies: ['reading', 'photography']
};
var person2 = createAnother(person);
person2.sayHi(); //hi
Based onperson
A new object–person2
, the new object not only hasperson
All properties and methods of, but also their ownsayHi()
Methods. Parasitic inheritance is also a useful pattern when considering objects rather than custom types and constructors.
Disadvantages:
- Using parasitic inheritance to add functions to objects is inefficient because it cannot reuse functions.
- As with prototype chain implementation inheritance, attributes containing reference type values are shared by all instances.
6. 寄生组合式继承
The so-called parasitic combinatorial inheritance is to inherit the attribute by borrowing the constructor and the method by blending the prototype chain. The basic idea is:
It is not necessary to call the super-type constructor in order to specify the prototype of the sub-type. What we need is only a copy of the super-type prototype. Essentially, we use parasitic inheritance to inherit the prototype of the super-type, and then assign the result to the prototype of the sub-type. The basic pattern of parasitic combinatorial inheritance is as follows:
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType;//增强对象
subType.prototype = prototype;//指定对象
}
- Step 1: Create a copy of the supertype prototype
- Step 2: Add
constructor
Attribute - Step 3: Assign the newly created object to the prototype of the subtype
At this point, we can call theinheritPrototype
To replace a statement that assigns a value to a subtype prototype:
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
//...code
function SuberType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SuberType.prototype = new SuperType();
inheritPrototype(SuberType, SuperType);
//...code
Advantages:
The super class constructor is called only once, which is more efficient. AvoidSuberType.prototype
The above create unnecessary and redundant attributes, while the prototype chain can remain unchanged.
Therefore, parasitic combination inheritance is the most rational inheritance paradigm for reference types.
10. What are the ways to hide an element in a page?
Hidden type
The screen is not the only output mechanism, for example, invisible elements (hidden elements) on the screen, some of which can still be read by the screen reading software (because the screen reading software depends on the accessibility tree to elaborate). In order to eliminate the ambiguity between them, we classify them into three categories:
- Completely Hidden: Elements disappear from the rendering tree and do not occupy space.
- Visual Hiding: Not visible on the screen, occupying space.
- Semantic Hiding: The screen reading software is unreadable, but normally occupies empty space.
Completely hidden
1.display
属性
display: none;
2.hidden 属性
HTML5 adds attributes equivalent todisplay: none
<div hidden>
</div>
Visual concealment
1.利用 position
和 盒模型 将元素移出可视区范围
- Set up
posoition
Forabsolute
Orfixed
By setting thetop
、left
Equivalent, move it out of the visible area.
position:absolute;
left: -99999px;
- Set up
position
Forrelative
By setting thetop
、left
Equivalent, move it out of the visible area.
position: relative;
left: -99999px;
height: 0
- Set the margin value and move it out of the visible area (visible area placeholder).
margin-left: -99999px;
height: 0;
2.利用 transfrom
- Zoom
transform: scale(0);
height: 0;
- mobile
translateX
,translateY
transform: translateX(-99999px);
height: 0
- Rotation
rotate
transform: rotateY(90deg);
3.设置其大小为0
- Width and height are 0 and font size is 0:
height: 0;
width: 0;
font-size: 0;
- Width and height are 0, beyond hiding:
height: 0;
width: 0;
overflow: hidden;
4.设置透明度为0
opacity: 0;
5.visibility
属性
visibility: hidden;
6.层级覆盖,z-index
属性
position: relative;
z-index: -999;
Set a higher level element to cover this element.
7.clip-path 裁剪
clip-path: polygon(0 0, 0 0, 0 0, 0 0);
Semantic concealment
aria-hidden 属性
The screen reading software is unreadable, occupying space and visible.
<div aria-hidden="true">
</div>
What are the differences between let, const and var?
Declaration method | Variable promotion | Temporary dead zone | Repeat declaration | Block scope is valid | Initial value | Reassign |
---|---|---|---|---|---|---|
var | Meeting | nothingness | Allow | No | Not required | Allow |
let | will not | exist | Not allowed | Yes | Not required | Allow |
const | will not | exist | Not allowed | Yes | Must | Not allowed |
Variables defined by 1.let/const will not be promoted, while variables defined by var will be promoted.
2. In the same scope, let and const are not allowed to repeat declarations, and var is allowed to repeat declarations.
3.const must set the initial value when declaring variables
4.const declares a read-only constant that cannot be changed.
One very important point here is that in JS, for complex data types, the address of heap memory is stored in the stack. The address in the stack is unchanged, but the value in the stack can be changed. Is there any equivalent const pointer/pointer constant ~
const a = 20;
const b = {
age: 18,
star: 500
}
As shown in the following figure, what remains unchanged is 20 stored in A and 0x0012ff21 stored in B of the stack memory. While {age: 18, star: 200} is variable.
12. Tell me about your understanding of JS execution context stack and scope chain?
Before we begin to explain JS context stack and scope, let’s first explain the concepts of JS context and scope.
JS execution context
The execution context is the abstract concept of the environment in which the current JavaScript code is parsed and executed. Any code running in JavaScript runs in the execution context.
The execution context types are:
- Global execution context
- Function execution context
During the context creation process, the following things need to be done:
- Create a variable object: First initialize the arguments of the function, promote the function declaration and variable declaration.
- Create Scope Chain: In the creation phase of the runtime context, scope chain is created after the variable object.
- Determine the value of this, namely ResolveThisBinding
action scope
action scopeResponsible for collecting and maintaining a series of queries consisting of all declared identifiers (variables), and implementing a very strict set of rules to determine the access rights of the currently executing code to these identifiers. -excerpted from “JavaScript you don’t know” (volume 1)
Scope has two working models: lexical scope and dynamic scope. JS usesLexical scopeWorking model, lexical scope means that scope is determined by the position of variables and function declarations when writing code. (with
Andeval
The lexical scope can be modified, but it is not recommended, which is not specifically explained)
Scope is divided into:
- Global scope
- Function scope
- Block scope
JS Execution Context Stack (hereinafter referred to as Execution Stack)
The execution stack, also called the call stack, hasLIFO(Last In, First Out) structure that stores all execution contexts created during code execution.
The rules are as follows:
- When JavaScript code is first run, a global execution context will be created and Pushed to the current execution stack. Whenever a function call occurs, the engine will create a new function execution context for the function and push the top of the current execution stack.
- When the function at the top of the stack runs, its corresponding function execution context will Pop out of the execution stack, and the control of the context will move to the next execution context of the current execution stack.
To specify with a code:
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
Global Execution Context
(i.e. global execution context) is first put on the stack as follows:
Pseudo code:
//全局执行上下文首先入栈
ECStack.push(globalContext);
//执行fun1();
ECStack.push(<fun1> functionContext);
//fun1中又调用了fun2;
ECStack.push(<fun2> functionContext);
//fun2中又调用了fun3;
ECStack.push(<fun3> functionContext);
//fun3执行完毕
ECStack.pop();
//fun2执行完毕
ECStack.pop();
//fun1执行完毕
ECStack.pop();
//javascript继续顺序执行下面的代码,但ECStack底部始终有一个 全局上下文(globalContext);
scope chain
Scope chain is to search for a variable level by level from the current scope until the global scope is found or not, and then announce to give up. This layer-by-layer relationship is scope chain.
For example:
var a = 10;
function fn1() {
var b = 20;
console.log(fn2)
function fn2() {
a = 20
}
return fn2;
}
fn1()();
Fn2 scope chain = [fn2 Scope, fn1 Scope, Global Scope]
13. What is the function of the anti-shake function? Please implement an anti-shake function
The function of anti-shake function
The function of anti-shake function is to control the number of times the function is executed within a certain period of time. Anti-shake means that the function will only be executed once in n seconds. If it is triggered again in n seconds, thenagainCalculate the delay time.
For example:Xiao Si is losing weight recently, but she eats snacks very much. For this reason, it is agreed with his boyfriend that if he does not eat snacks for 10 days, he can buy a bag (don’t ask why it is a bag, becauseCure)。 However, if you eat a snack in the middle, you have to recalculate the time until Xiao Si insists on not eating snacks for 10 days before buying a bag. So, Xiao Si, who can’t keep his mouth shut, didn’t have a chance to buy a bag (sad story) … this is it.Anti shake.
Realization of Anti-shake Function
- When the event is triggered for the first time,
timer
Yesnull
, callinglater()
Ifimmediate
Fortrue
Then call immediatelyfunc.apply(this, params)
; Ifimmediate
Forfalse
, thenwait
After that, call thefunc.apply(this, params)
- When the event is triggered for the second time, if
timer
Has been reset tonull
(i.e.setTimeout
The countdown to the end of), then the process is the same as the first trigger, iftimer
Not fornull
(i.e. the countdown to setTimeout has not ended), then clear the timer and start counting again.
function debounce(func, wait, immediate = true) {
let timeout, result;
// 延迟执行函数
const later = (context, args) => setTimeout(() => {
timeout = null;// 倒计时结束
if (!immediate) {
//执行回调
result = func.apply(context, args);
context = args = null;
}
}, wait);
let debounced = function (...params) {
if (!timeout) {
timeout = later(this, params);
if (immediate) {
//立即执行
result = func.apply(this, params);
}
} else {
clearTimeout(timeout);
//函数在每个等待时延的结束被调用
timeout = later(this, params);
}
return result;
}
//提供在外部清空定时器的方法
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
};
return debounced;
};
immediate
True indicates that the function is called at the beginning of each wait delay.immediate
False indicates that the function is called at the end of each wait delay.
Anti-shake application scenario
- Search box input query, if the user has been in the input, there is no need to constantly call to request the server interface, when the user stops input, call again, set a suitable time interval, effectively reduce the pressure on the server.
- Form validation
- Button submit event.
- Browser window scaling, resize events (such as recalculating the layout after the window stops changing size), etc.
14. What is the function of throttling function? Please implement a throttling function for any application scenarios
Function of throttling function
The throttling function is used to specify a unit time, in which the function can only be triggered once at most. If the function is triggered multiple times in this unit time, it can only be effective once.
Implementation of throttling function
function throttle(func, wait, options = {}) {
var timeout, context, args, result;
var previous = 0;
var later = function () {
previous = options.leading === false ? 0 : (Date.now() || new Date().getTime());
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function () {
var now = Date.now() || new Date().getTime();
if (!previous && options.leading === false) previous = now;
//remaining 为距离下次执行 func 的时间
//remaining > wait,表示客户端系统时间被调整过
var remaining = wait - (now - previous);
context = this;
args = arguments;
//remaining 小于等于0,表示事件触发的间隔时间大于设置的 wait
if (remaining <= 0 || remaining > wait) {
if (timeout) {
//清空定时器
clearTimeout(timeout);
timeout = null;
}
//重置 previous
previous = now;
//执行函数
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function () {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}
Disable first execution, delivery{leading: false}
; To disable the last execution, pass{trailing: false}
Application Scenarios of Throttling
- Button click event
- Drag event
- onScoll
- Calculate the mouse movement distance (mousemove)
15. What is closure? What is the function of closures?
闭包的定义
JavaScript Advanced Programming:
Closures are functions that have access to variables in the scope of another function
JavaScript Authority Guide:
From a technical point of view, all JavaScript functions are closures: they are objects and they are all related to scope chain.
JavaScript you don’t know
Closures are generated when a function can remember and access its lexical scope, even if the function is executed outside the current lexical scope.
创建一个闭包
function foo() {
var a = 2;
return function fn() {
console.log(a);
}
}
let func = foo();
func(); //输出2
Closures allow functions to continue to access the lexical scope at the time of definition. Thanks to fn, the scope inside foo will not be destroyed after foo () is executed.
闭包的作用
- Can access the lexical scope of the function definition (prevent it from being recycled).
- Privatization variable
function base() {
let x = 10; //私有变量
return {
getX: function() {
return x;
}
}
}
let obj = base();
console.log(obj.getX()); //10
- Simulate block-level scope
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(j){
return function () {
console.log(j);
}
})(i);
}
a[6](); // 6
- Create module
function coolModule() {
let name = 'Yvette';
let age = 20;
function sayName() {
console.log(name);
}
function sayAge() {
console.log(age);
}
return {
sayName,
sayAge
}
}
let info = coolModule();
info.sayName(); //'Yvette'
Module mode has two prerequisites (from JavaScript you don’t know)
- There must be an external enclosing function that must be called at least once (each call creates a new module instance)
- Closed functions must return at leastOneInternal functions, so that internal functions can form closures in private scopes and can access or modify private states.
16. implement Promise.all method
Before implementing the Promise.all method, we must first know the functions and characteristics of Promise.all, because we can write the implementation further only when the functions and characteristics of Promise.all are clear.
Promise.all function
Promise.all(iterable)
Returns a new Promise instance. This instance is found initerable
All within the parameterpromise
Allfulfilled
Or the parameter does not containpromise
, the state changes tofulfilled
; If one of the parameterspromise
There is one failurerejected
This instance callback failed because of the first failurepromise
Returns the result of the.
let p = Promise.all([p1, p2, p3]);
The state of P is determined by P1, P2 and P3 and is divided into the following: There are two situations:
(1) Only p1, p2 and p3 becomefulfilled
, the state of p will becomefulfilled
In this case, the return values of p1, p2 and p3 form an array and are passed to the callback function of p.
(2) As long as one of p1, p2, p3 isrejected
, the state of p becomesrejected
The return value of the first reject instance is passed to the callback function of p.
Features of Promise.all
The return value of Promise.all is a promise instance
- If the passed-in parameter is an empty iterated object,
Promise.all
MeetingSynchronizationA that returns a completed statepromise
- If the parameter passed in does not contain any promise,
Promise.all
MeetingAsynchronousA that returns a completed statepromise
- In other cases,
Promise.all
Return onePendingState ofpromise
.
The status of promise returned by Promise.all
- If promise in the passed-in parameters all become complete,
Promise.all
Returnedpromise
Become completed asynchronously. - If one of the parameters passed in
promise
Failure,Promise.all
The result of the failure is asynchronously given to the callback function of the failed state, regardless of the others.promise
Is it complete - In any case,
Promise.all
Returnedpromise
The result of the completion status of is an array
Promise.all implementation
Promise.all = function (promises) {
//promises 是可迭代对象,省略参数合法性检查
return new Promise((resolve, reject) => {
//Array.from 将可迭代对象转换成数组
promises = Array.from(promises);
if (promises.length === 0) {
resolve([]);
} else {
let result = [];
let index = 0;
for (let i = 0; i < promises.length; i++ ) {
//考虑到 i 可能是 thenable 对象也可能是普通值
Promise.resolve(promises[i]).then(data => {
result[i] = data;
if (++index === promises.length) {
//所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态
resolve(result);
}
}, err => {
reject(err);
return;
});
}
}
});
}
17. Please implement a Flattened Deep function to flatten nested arrays
For example:
flattenDeep([1, [2, [3, [4]], 5]]); //[1, 2, 3, 4, 5]
Using Array.prototype.flat
ES6 added to array instancesflat
Method, used to “flatten” nested arrays into one-dimensional arrays. This method returns a new array and has no effect on the original array.
flat
The default is to “flatten” only one layer. If you want to “flatten” multi-layer nested arrays, you need to giveflat
Pass an integer indicating the number of layers you want to flatten.
function flattenDeep(arr, deepLength) {
return arr.flat(deepLength);
}
console.log(flattenDeep([1, [2, [3, [4]], 5]], 3));
When the passed integer is greater than the number of nested layers of the array, the array will be flattened into a one-dimensional array, and the maximum number JS can represent isMath.pow(2, 53) - 1
So we can define it this wayflattenDeep
Function
function flattenDeep(arr) {
//当然,大多时候我们并不会有这么多层级的嵌套
return arr.flat(Math.pow(2,53) - 1);
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));
Leveraging reduce and concat
function flattenDeep(arr){
return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));
Using stack to Infinitely Anti-nest Multi-level Nested Arrays
function flattenDeep(input) {
const stack = [...input];
const res = [];
while (stack.length) {
// 使用 pop 从 stack 中取出并移除值
const next = stack.pop();
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入 original input
stack.push(...next);
} else {
res.push(next);
}
}
// 使用 reverse 恢复原数组的顺序
return res.reverse();
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));
18. Please implement a uniq function to realize array de-duplication
For example:
uniq([1, 2, 3, 5, 3, 2]);//[1, 2, 3, 5]
Method 1: Use ES6 to add new data types
Set
Set
It is similar to an array, but the values of members are unique and there are no duplicate values.
function uniq(arry) {
return [...new Set(arry)];
}
Method 2: Use
indexOf
function uniq(arry) {
var result = [];
for (var i = 0; i < arry.length; i++) {
if (result.indexOf(arry[i]) === -1) {
//如 result 中没有 arry[i],则添加到数组中
result.push(arry[i])
}
}
return result;
}
Method 3: Use
includes
function uniq(arry) {
var result = [];
for (var i = 0; i < arry.length; i++) {
if (!result.includes(arry[i])) {
//如 result 中没有 arry[i],则添加到数组中
result.push(arry[i])
}
}
return result;
}
Method 4: Use
reduce
function uniq(arry) {
return arry.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []);
}
Method 5: Use
Map
function uniq(arry) {
let map = new Map();
let result = new Array();
for (let i = 0; i < arry.length; i++) {
if (map.has(arry[i])) {
map.set(arry[i], true);
} else {
map.set(arry[i], false);
result.push(arry[i]);
}
}
return result;
}
19. What are the characteristics of iterated objects
ES6 stipulates that the defaultIterator
The interface is deployed in the of the data structureSymbol.iterator
Attribute, in other words, a data structure can be considered as long as it hasSymbol.iterator
Properties (Symbol.iterator
The method corresponds to a traverser generation function and returns a traverser object), then it can be considered iterated.
Characteristics of Iterative Objects
- Have
Symbol.iterator
Attributes,Symbol.iterator()
Returns a traverser object - Can be used
for ... of
Cycle through - By being
Array.from
Convert to array
let arry = [1, 2, 3, 4];
let iter = arry[Symbol.iterator]();
console.log(iter.next()); //{ value: 1, done: false }
console.log(iter.next()); //{ value: 2, done: false }
console.log(iter.next()); //{ value: 3, done: false }
Native toIterator
The data structure of the interface:
- Array
- Map
- Set
- String
- TypedArray
- Arguments object for function
- NodeList object
20. What is the principle of JSONP?
Although browsers have homologous policies, however<script>
Taggedsrc
Attributes are not constrained by homologous policies, and scripts on any server can be obtained and executed.jsonp
By insertionscript
Tag to achieve cross-domain, parameters can only be passed throughurl
Incoming, only supportedget
Request.
Implementation principle:
- Step1: Create callback Method
- Step2: Insert script Label
- Step3: The background receives the request, parses the callback method passed by the front end, returns the call of the method, and the data is passed into the method as a parameter
- Step4: The front end executes the method call returned by the service end
Jsonp source code implementation
function jsonp({url, params, callback}) {
return new Promise((resolve, reject) => {
//创建script标签
let script = document.createElement('script');
//将回调函数挂在 window 上
window[callback] = function(data) {
resolve(data);
//代码执行后,删除插入的script标签
document.body.removeChild(script);
}
//回调函数加在请求地址上
params = {...params, callback} //wb=b&callback=show
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
Use:
function show(data) {
console.log(data);
}
jsonp({
url: 'http://localhost:3000/show',
params: {
//code
},
callback: 'show'
}).then(data => {
console.log(data);
});
Node:
//express启动一个后台服务
let express = require('express');
let app = express();
app.get('/show', (req, res) => {
let {callback} = req.query; //获取传来的callback函数名,callback是key
res.send(`${callback}('Hello!')`);
});
app.listen(3000);
Reference articles:
[1] [JavaScript Advanced Programming Chapter 6]
[2]Step-By-Step] high-frequency interview questions in-depth analysis/weekly 01
[3]Step-By-Step] high-frequency interview questions in-depth analysis/weekly 02
[4]Step-By-Step] high-frequency interview questions in-depth analysis/weekly 03
[5]Step-By-Step] high-frequency interview questions in-depth analysis/weekly 04
Thank you for your friends’ willingness to spend precious time reading this article. If this article gives you some help or inspiration, please don’t be stingy with your praise and Star. Your affirmation is my greatest motivation to move forward.https://github.com/YvetteLau/ …
Recommend to pay attention to my public number: