[Step-By-Step] One-week Question Analysis/Weekly 02

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

This week’s interview questions list:

  • What is the function of the throttle function? Please implement a throttling function for any application scenarios
  • Tell me about your understanding of JS execution context stack and scope chain?
  • What is BFC? What are the layout rules of BFC? How to create BFC?
  • What are the differences between let, const and var?
  • What is the difference between deep copy and shallow copy? How to realize a deep copy?

6. What is the function of the throttle function? Please implement a throttling function for any application scenarios. (2019-05-27)

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.

For example: Xiaoming’s mother and Xiaoming have agreed that if Xiaoming gets full marks in the weekly examination, he can be taken to the amusement park that month, but he can only go once a month at most.

This is actually an example of cutting expenditure. In a month’s time, going to an amusement park can only be triggered once at most. Even during this period of time, Xiao Ming got full marks many times.

Throttling application scenario

1. button click event

2. Drag events

3.onScoll

4. Calculate the mouse movement distance (mousemove)

Implementation of throttling function

Implementation with timestamp

function throttle (func, delay) {
    var lastTime = 0;
    function throttled() {
        var context = this;
        var args = arguments;
        var nowTime = Date.now();
        if(nowTime > lastTime + delay) {
            func.apply(context, args);
            lastTime = nowTime;
        }
    }
    //节流函数最终返回的是一个函数
    return throttled; 
}

Implemented by Timer

function throttle(func, delay) {
    var timeout = null;
    function throttled() {
        var context = this;
        var args = arguments;
        if(!timeout) {
            timeout = setTimeout(()=>{
                func.apply(context, args);
                clearTimeout(timeout);
                timeout=null
            }, delay);
        }
    }
    return throttled;
}

Timestamp and timer methods do not consider the problem of the last execution. For example, if there is a button click event and the set interval is 1S, when clicking at 0.5S, 1.8S and 2.2S, only two clicks of 0.5S and 1.8S can trigger the function execution, while the last 2.2S will be ignored.

Combined implementation, allowing setting whether the first or last trigger function execution

function throttle (func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    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;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            // 判断是否设置了定时器和 trailing
            timeout = setTimeout(later, remaining);
        }
        return result;
    };

    throttled.cancel = function () {
        clearTimeout(timeout);
        previous = 0;
        timeout = context = args = null;
    };

    return throttled;
}

The use is simple:

btn.onclick = throttle(handle, 1000, {leading:true, trailing: true});

Click to view more

7. Tell me about your understanding of JS execution context stack and scope chain? (2019-05-28)

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
  • Eval function execution context (not recommended)

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]

8. What is BFC? What are the layout rules of BFC? How to create BFC? (2019-05-29)

What is BFC

BFC is the abbreviation of Block Formatting Context, i.e. blockformattingcontext. Let’s look at the description of BFC in the CSS2.1 specification.

Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with ‘overflow’ other than ‘visible’ (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

Floating, absolutely positioned elements, block containers that are not block-level boxes (such as inline-blocks, table-cells, and table-captions), andoverflowThe value of is notvisible(except that the value has been propagated to the viewport) Creates a new block format context for its contents.

Therefore, if we want to understand BFC in depth, we need to understand the following two concepts:

1.Box

2.Formatting Context

Box

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 relative.
  • Overflow is not a visible block element
  • Display is inline-block, table-cell, table-capture.

Application of BFC

1. Preventing margin from Overlapping

<style>
    .a{
        height: 100px;
        width: 100px;
        margin: 50px;
        background: pink;
    }
</style>
<body>
    <div class="a"></div>
    <div class="a"></div>
</body>

Two divs directmarginIt’s 50px, it happenedmarginThe overlap of.

According to the BFC rule, two adjacent boxes in the same BFCmarginThere will be overlap, so we can nest another layer of container outside the div and trigger the container to generate a BFC, thus<div class="a"></div>Will belong to two BFC, nature also won’t happen againmarginOverlap

<style>
    .a{
        height: 100px;
        width: 100px;
        margin: 50px;
        background: pink;
    }
    .container{
        overflow: auto; /*触发生成BFC*/
    }
</style>
<body>
    <div class="container">
        <div class="a"></div>
    </div>    
    <div class="a"></div>
</body>

2. Clear internal float

<style>
    .a{
        height: 100px;
        width: 100px;
        margin: 10px;
        background: pink;
        float: left;
    }
    .container{
        width: 120px;
        border: 2px solid black;
    }
</style>
<body>
    <div class="container">
        <div class="a"></div>
    </div>
</body>

The height of the container has not been expanded. If we want the height of the container to contain floating elements, we can create a new BFC, because according to BFC rules, floating elements also participate in the calculation when calculating the height of BFC.

<style>
    .a{
        height: 100px;
        width: 100px;
        margin: 10px;
        background: pink;
        float: left;
    }
    .container{
        width: 120px;
        display: inline-block;/*触发生成BFC*/
        border: 2px solid black; 
    }
</style>

3. Adaptive multi-column layout

<style>
    body{
        width: 500px;
    }
    .a{
        height: 150px;
        width: 100px;
        background: pink;
        float: left;
    }
    .b{
        height: 200px;
        background: blue;
    }
</style>
<body>
    <div class="a"></div>
    <div class="b"></div>
</body>   

According to the rules, the BFC area does not overlap with the float box. Therefore, a new BFC can be triggered as follows:

<style>
.b{
    height: 200px;
    overflow: hidden; /*触发生成BFC*/
    background: blue;
}
</style>

What are the differences between let, const and var? (2019-05-30)

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.

a = 10;
var a; //正常
a = 10;
let a; //ReferenceError

2. In the same scope, let and const are not allowed to repeat declarations, and var is allowed to repeat declarations.

let a = 10;
var a = 20;
//抛出异常:SyntaxError: Identifier 'a' has already been declared

3.cosnt must set the initial value when declaring variables

const a;//SyntaxError: Missing initializer in const declaration

4.const declares a read-only constant that cannot be changed.

Here is a very important point: complex data types, stored in the stack is the address of the heap memory, 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. Think about what method you should use if you want an object to be immutable.

Variables declared by 5.let/const are only valid in block-level scopes. However, variables declared by var can still be accessed outside the block-level scope.

{
    let a = 10;
    const b = 20;
    var c = 30;
}
console.log(a); //ReferenceError
console.log(b); //ReferenceError
console.log(c); //30

Before let/const, when I first learned JS, I was also troubled by the following question:

Expectations:A[0] () Output 0, a[1] () Output 1, a[2] () Output 2, ...

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    };
}
a[6](); // 10

Although I knew why later, in order to get the results I need, I still need the entire closure. I … what did I do wrong, and I have to do this to me …

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = (function(j){
        return function () {
            console.log(j);
        }
    })(i)
}
a[6](); // 6

With the let, finally don’t bother.

var a = [];
for (let i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    };
}
a[6](); // 6

Delighted, have ~

Beauty is beautiful, but you have to ask yourself why ~

var iWhy is the output 10, because I is valid in the global scope, equivalent to only one variable I, etca[6]()What is the value of this I? Please speak out loud.

Looking at the let again, we say that the variable declared by the let is valid only in the scope of block level. The variable I is declared by the let, and the current I is valid only in this round of cycles, so the I of each cycle is actually a new variable. Interested partners can view babel’s compiled code.

6. Variables declared by var in the top-level scope are hung on window (browser environment)

var a = 10;
console.log(window.a);//10

7.let/const has a temporary dead zone problem, i.e. variables declared by let/const are not available until they are defined. If used, an error will be thrown.

As long as the let command exists in the block-level scope, the variables it declares “bind” this area and are no longer affected by external influences.

var a = 10;
if (true) {
  a = 20; // ReferenceError
  let a;
}

Within the code block, the variable is not available until the let/const command is used to declare the variable, which means that typeof is no longer a 100% safe operation.

console.log(typeof b);//undefined

console.log(a); //ReferenceError
let a = 10;

10. What is the difference between deep copy and shallow copy? How to realize a deep copy? (2019-05-31)

Deep copy and shallow copy are for complex data types.

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. Let’s take a look at the usefor inRealize shallow copy.

let obj = {
    name: 'Yvette',
    age: 18,
    hobbies: ['reading', 'photography']
}
let newObj = {};
for(let key in obj){
    newObj[key] = obj[key]; 
    //这一步不需要多说吧,复杂数据类型栈中存的是对应的地址,因此赋值操作,相当于两个属性值指向同一个内存空间
}
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }
obj.age = 20;
obj.hobbies.pop();
console.log(newObj);
//{ name: 'Yvette', age: 18, hobbies: [ 'reading' ] }

Deep copy implementation

1. The simplest implementation of deep copy is:JSON.parse(JSON.stringify(obj))

let obj = {
    name: 'Yvette',
    age: 18,
    hobbies: ['reading', 'photography']
}
let newObj = JSON.parse(JSON.stringify(obj));//newObj和obj互不影响
obj.hobbies.push('coding');
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }

JSON.parse(JSON.stringify(obj))Is the simplest implementation, but there is one flaw:

1. When the attribute value of an object is a function, it cannot be copied.

let obj = {
    name: 'Yvette',
    age: 18,
    hobbies: ['reading', 'photography'],
    sayHi: function() {
        console.log(sayHi);
    }
}
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18, hobbies: [ 'reading', 'photography' ] }

2. Properties on prototype chain cannot be obtained

function Super() {

}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
    this.name = name;
    this.age = age;
}
Child.prototype = new Super();

let obj = new Child('Yvette', 18);
console.log(obj.location); //NanJing
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'Yvette', age: 18}
console.log(newObj.location);//undefined;原型链上的属性无法获取

3. Data of Date type cannot be processed correctly

4. RegExp cannot be processed

5. symbol will be ignored.

6. Ignoring undefined

let obj = {
    time: new Date(),
    reg: /\d{3}/,
    sym: Symbol(10),
    name: undefined
}

let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); //{ time: '2019-06-02T08:16:44.625Z', reg: {} }

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.
function deepClone(obj) { //递归拷贝
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(obj === null || typeof obj !== 'object') {
        //如果不是复杂数据类型,直接返回
        return obj;
    }
    /**
     * 如果obj是数组,那么 obj.constructor 是 [Function: Array]
     * 如果obj是对象,那么 obj.constructor 是 [Function: Object]
     */
    let t = new obj.constructor();
    for(let key in obj) {
        //如果 obj[key] 是复杂数据类型,递归
        if(obj.hasOwnProperty(key)){//是否是自身的属性
            t[key] = deepClone(obj[key]);
        }
    }
    return t;
}

Testing:

function Super() {

}
Super.prototype.location = 'NanJing';
function Child(name, age, hobbies) {
    this.name = name;
    this.age = age;
    this.hobbies = hobbies;
}
Child.prototype = new Super();

let obj = new Child('Yvette', 18, ['reading', 'photography']);
obj.sayHi = function () {
    console.log('hi');
}
console.log(obj.location); //NanJing
let newObj = deepClone(obj);
console.log(newObj);//
console.log(newObj.location);//NanJing 可以获取到原型链上的属性
newObj.sayHi();//hi 函数属性拷贝正常

Reference articles:

[1]https://www.ecma-internationa …

[2]Understanding Javascript Execution Context and Execution Stack

[3]https://css-tricks.com/deboun …

[4]https://github.com/mqyqingfen …

[5]https://www.cnblogs.com/coco1 …

[6]https://www.cnblogs.com/wangf …

[7]https://www.w3.org/TR/2011/RE …

[8]https://github.com/mqyqingfen …

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