Here are 20 big factory noodle tests waiting for you to check

  Front end, html5, javascript, node.js, Programmer

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?

newThe implementation principle of:

  1. Creates an empty object to which this in the constructor points
  2. This new object is connected by [[prototype]]
  3. Executes constructor methods, attributes, and methods are added to the object referenced by this
  4. 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 itnewBinding

If it isnewBinding, 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 isundefinedOr ..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 inObject.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:

  1. Object cannot be copied when its attribute value is a function.
  2. Attributes on prototype chain cannot be copied
  3. Data of type Date cannot be processed correctly
  4. RegExp cannot be processed
  5. Symbol is ignored
  6. Ignoring undefined

2. implement a deepClone function

  1. If it is a basic data type, directly return
  2. If it isRegExpOr ..DateType, returns the corresponding type
  3. If it is a complex data type, recursion.
  4. 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.thisAnd execute the function immediately. The difference lies in the different ways of parameter transmission.

  • func.call(thisArg, arg1, arg2, ...): The first parameter isthisPointed to the object, other parameters are passed in sequence.
  • func.apply(thisArg, [argsArray]): The first parameter isthisThe 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, descriptioncallIt is a method on a function prototype, and all instances can be called. That is:Function.prototype.call.

  • IncallGets the call from thecall()Function
  • If the first parameter is not passed in, the default point iswindow / global(Non-strict Mode)
  • afferentcallThe first parameter of is the object this points to. According to the implicit binding rule, we know thatobj.foo(),foo()hit the targetthispoint 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 bindcallConsistent, 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?

  1. 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 == 3The 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 JSobjectRecall 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

    1. Non-Date type objects,hintYesdefault, the call order is:valueOf>>>toString, i.e.valueOfThe return is not the basic data type, and the call will continue.valueOfIftoStringIf the returned data type is not the basic data type, an error is thrown.
    2. IfhintYesstring(hint of Date object defaults to string), and the calling order is:toString>>>valueOf, i.e.toStringThe return is not the basic data type, and the call will continue.valueOfIfvalueOfIf the returned data type is not the basic data type, an error is thrown.
    3. IfhintYesnumber, call order is:valueOf>>>toString
//部署 [Symbol.toPrimitive] / valueOf/ toString 皆可
//一次返回1,2,3 即可。
let a = {
    [Symbol.toPrimitive]: (function(hint) {
            let i = 1;
            //闭包的特性之一:i 不会被回收
            return function() {
                return i++;
            }
    })()
}
  1. Using Proxy/Object.definedProperty
let i = 1;
let a = new Proxy({}, {
    i: 1,
    get: function () {
        return () => this.i++;
    }
});
  1. Array oftoStringThe interface calls the of the array by defaultjoinMethods, tojoinMethod
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 elementdisplayProperty 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.

BFC layout rules

  • In BFC, the boxes are arranged vertically in turn.
  • In BFC, the vertical distance between the two boxes is determined bymarginAttribute 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

  1. Prevent margin from Overlapping (for two adjacent Box within the same BFCmarginOverlap will occur, triggering the generation of two BFC, i.e. no overlap)
  2. 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)
  3. 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>

deferAndasyncThe difference lies in:

  • deferWhen 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;
  • asyncOnce the download is complete, the rendering engine will stop rendering and continue rendering after executing this script.
  • If there are multipledeferScripts are loaded in the order in which they appear on the page
  • MultipleasyncScripts cannot guarantee the loading order

Dynamic creationscriptLabel

Dynamically createdscript, settingssrcThe 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:

  1. 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.
  2. 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:

  1. You can pass parameters to superclasses
  2. The problem that the reference type value contained in the prototype is shared by all instances is solved

Disadvantages:

  1. 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 onpersonA new object–person2, the new object not only haspersonAll 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: AddconstructorAttribute
  • Step 3: Assign the newly created object to the prototype of the subtype

At this point, we can call theinheritPrototypeTo 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.prototypeThe 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 和 盒模型 将元素移出可视区范围
  1. Set upposoitionForabsoluteOrfixedBy setting thetopleftEquivalent, move it out of the visible area.
position:absolute;
left: -99999px;
  1. Set uppositionForrelativeBy setting thetopleftEquivalent, move it out of the visible area.
position: relative;
left: -99999px;
height: 0
  1. Set the margin value and move it out of the visible area (visible area placeholder).
margin-left: -99999px;
height: 0;
2.利用 transfrom
  1. Zoom
transform: scale(0);
height: 0;
  1. mobiletranslateX,translateY
transform: translateX(-99999px);
height: 0
  1. Rotationrotate
transform: rotateY(90deg);
3.设置其大小为0
  1. Width and height are 0 and font size is 0:
height: 0;
width: 0;
font-size: 0;
  1. 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:

  1. Create a variable object: First initialize the arguments of the function, promote the function declaration and variable declaration.
  2. Create Scope Chain: In the creation phase of the runtime context, scope chain is created after the variable object.
  3. 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. (withAndevalThe 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

  1. When the event is triggered for the first time,timerYesnull, callinglater()IfimmediateFortrueThen call immediatelyfunc.apply(this, params); IfimmediateForfalse, thenwaitAfter that, call thefunc.apply(this, params)
  2. When the event is triggered for the second time, iftimerHas been reset tonull(i.e.setTimeoutThe countdown to the end of), then the process is the same as the first trigger, iftimerNot 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;
};

immediateTrue indicates that the function is called at the beginning of each wait delay.immediateFalse indicates that the function is called at the end of each wait delay.

Anti-shake application scenario

  1. 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.
  2. Form validation
  3. Button submit event.
  4. 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

  1. Button click event
  2. Drag event
  3. onScoll
  4. 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.

闭包的作用
  1. Can access the lexical scope of the function definition (prevent it from being recycled).
  2. Privatization variable
function base() {
    let x = 10; //私有变量
    return {
        getX: function() {
            return x;
        }
    }
}
let obj = base();
console.log(obj.getX()); //10
  1. 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
  1. 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 initerableAll within the parameterpromiseAllfulfilledOr the parameter does not containpromise, the state changes tofulfilled; If one of the parameterspromiseThere is one failurerejectedThis instance callback failed because of the first failurepromiseReturns 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 becomefulfilledIn 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 becomesrejectedThe 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.allMeetingSynchronizationA that returns a completed statepromise
  • If the parameter passed in does not contain any promise,Promise.allMeetingAsynchronousA that returns a completed statepromise
  • In other cases,Promise.allReturn onePendingState ofpromise.

The status of promise returned by Promise.all

  • If promise in the passed-in parameters all become complete,Promise.allReturnedpromiseBecome completed asynchronously.
  • If one of the parameters passed inpromiseFailure,Promise.allThe result of the failure is asynchronously given to the callback function of the failed state, regardless of the others.promiseIs it complete
  • In any case,Promise.allReturnedpromiseThe 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 instancesflatMethod, used to “flatten” nested arrays into one-dimensional arrays. This method returns a new array and has no effect on the original array.

flatThe default is to “flatten” only one layer. If you want to “flatten” multi-layer nested arrays, you need to giveflatPass 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) - 1So we can define it this wayflattenDeepFunction

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 typesSet

SetIt 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: UseindexOf

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: Useincludes

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: Usereduce

function uniq(arry) {
    return arry.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []);
}

Method 5: UseMap

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 defaultIteratorThe interface is deployed in the of the data structureSymbol.iteratorAttribute, in other words, a data structure can be considered as long as it hasSymbol.iteratorProperties (Symbol.iteratorThe method corresponds to a traverser generation function and returns a traverser object), then it can be considered iterated.

Characteristics of Iterative Objects

  • HaveSymbol.iteratorAttributes,Symbol.iterator()Returns a traverser object
  • Can be usedfor ... ofCycle through
  • By beingArray.fromConvert 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 toIteratorThe 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>TaggedsrcAttributes are not constrained by homologous policies, and scripts on any server can be obtained and executed.jsonpBy insertionscriptTag to achieve cross-domain, parameters can only be passed throughurlIncoming, only supportedgetRequest.

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:

clipboard.png