6
头图

Block-level scope (execution result question)

block scope
Ruan Yifeng block-level scope

 var a = 1999;
{
    console.log(a); // function a(){}
    a = 2020;
    function a() {}
    a = 2021;
}
console.log(a); // 2020

My understanding: (The principle may be wrong, but it is easy to understand. The wrong point is that functions cannot be declared at the block level. The browser will have its own support behavior, similar to the function expression declaration - refer to Ruan Yifeng. The declaration should not be declared as a function way, in the way of a function expression.)
In the block level, the compilation process, function declaration variable promotion, and execution process have no effect. Hence function a(){}
Outside the block level, the compilation process, with a outside, has no effect. When executing the process, start the search. Since the search order of a is from the lexical environment ({}) to the variable environment (var), the closest one is found, so it is 2020 (note that this is the execution phase, the function a(){} Variable hoisting is the compile phase)

ps. Functions will be promoted preferentially compared to variables. (My understanding: this means that the function replaces the variable hoisting)

Event bubbling, event capture, event delegation (event delegation)

Event bubbling: event capture: event proxy: use event bubbling to bind events to parent elements

target.addEventListener(type, listener, useCapture); , when useCapture is false, it is event bubbling, the default is false.

Object

Common method:

  • Object.defineProperty Defined description: { value, writable, configurable, emunable }, or { set, get, configurable, emunable }
  • Object.createObject.keysObject.valuesObject.entriesObject.toString
  • Object.preventExtensions Organization extension object

Scope, scope chain and context

Scope refers to the space in which variables are declared when a function is defined.
The scope chain refers to the process of variable lookup, from the current context, to the parent layer by layer, until the global.

When the function is declared, there will be a scope attribute that contains all the parent's variables. At this time, the VO object, including internal functions, variables, and formal parameters, is stored in the context.
When the function is executed, the AO object, including internal functions, variables, formal parameters, and internal this, is mounted on the scope chain.

Introduction to scope, scope chain and execution context stack

Prototype chain

To be added

Promises and async

Common asynchronous requests:

Native

 var request = new HttpXMLRequest()
request.open('GET', url);
request.responseType = 'json'
request.onload = function(){}
request.send()

Implement Promises
To be added

 // Promise

// Promise.prototype.then

// Promise.prototype.all

// Promise.prototype.resolve

// Promise.prototype.race

event loop and event queue

The event loop consists of:

  • Event queue (unit is a message, the message is associated with a callback function, and the callback function will be called after being popped from the message queue to form an execution frame)
  • Execution stack (unit is frame, including variables and parameters in the function)
  • Heap (holds the object structure)

Synchronous and asynchronous tasks

window.requestAnimationFrame() is neither a macro task nor a micro task, but is executed the next time the browser redraws

Closure

Two main features:

  • Prevent external function's reference to internal variable by function
  • Functions can use external variables

refer to

this in the closure
Since the closure is executed in memory, this usually points to the global, which can be changed by call.

The role of closures

  • By executing the function immediately, it simulates the block-level scope and reduces the declaration of variables to the global scope. In addition, since the immediate execution function has no external reference after execution, the memory will be released immediately.
  • When using var declaration, i can be accurately obtained when traversing the function with immediate execution
  • Implement object-oriented programming (not via the new construct)
 function Person(){
  var name = 'default';
  return {
    getName : function(){
      return name;
    },
    setName : function(newName){
      name = newName;
    }
  }
};
var p1 = Person();
console.log(p1.getName()); // default
p1.setName('wang');
console.log(p1.getName()); // wang

The problem with closures

  • Referencing the dom in a closure results in a circular reference that cannot be GC (reference counting)
 // IE9 之前甚至无法销毁 dom
function closure(){
  var element = document.getElementById(ID);
  element.onclick = function(){
    console.log(element.id);
  }
  // 销毁 element
  // element = null
}
  • this points to
  • When a closure returns a local scope variable, the memory is not freed immediately

macrotasks and microtasks

Common Asynchronous Exam Questions

es5/es6/es7/es8

To be added

super in class

super can be used both as a function and as an object.
When a function is used, it is equivalent to the constructor of the parent class and can only be used in the constructor of the subclass, and this points to the instance of the subclass.

 class A {
  constructor() {
    this.show();
  }
  show(){
    console.log('A 实例');
  }
}
class B extends A {
  constructor() {
    super();
  }
  show(){
    console.log('B 实例');
  }
}
new B() // B 实例

When the object is used in general functions, super is equivalent to the prototype object of the parent class, and this points to the subclass instance.

 class A {
  constructor() {  
    this.x = 'A';
  }
  say() {
    console.log(this.x)
  }
}
class B extends A {
  constructor() {
    super();
    this.x = 'B'
  }
}
let b = new B();
console.log(b.say()) // B
ps. Pay attention to this reminder
 class A {
  constructor() {  // 在构造函数上定义的属性和方法相当于定义在父类实例上的,而不是原型对象上
    this.p = 2;
  }
}
class B extends A {
  get m() {
    return super.p;
  }
}
let b = new B();
console.log(b.m) // undefined

// 引申题
function A(x) {
    this.p = x
}
A.prototype.p = 2
// 此时的 p 通过构造函数已经声明
new A().p // undefined

super in the static method this points to the parent class

common code

Anti-shake and throttling

Anti-shake means that it is triggered after accumulating over a period of time. For example, when entering text in an input box, monitor onChange.

 function debounce(fn, delay) {
    let timer
    return function () {
        const self = this;
        const args = arguments;
        if (timer) {
            clearTimeout(timer);
        }

        timer = setTimeout(function(){
            fn.apply(self, args);
        }, delay)
    }
}

let log = debounce(function(){ console.log('!')}, 5000)

window.addEventListener('resize',log)

Throttling means that multiple repeated triggers are executed only once over a period of time, such as repeated clicks.

 function throttle(fn, delay) {

    let timer
    
    return function () {
        const self = this;
        const args = arguments;
        if (timer) {
            return;
        }

        timer = setTimeout(function() {
            self.apply(fn, args)
            timer = null;
        }, delay)
    }
}

let log = throttle(function(){ console.log('!')}, 3000)

window.addEventListener('click',log)

Reasons for this difference:
Throttling is fixed when the first execution is arg, that is to say, if throttling is used in the onChange scene of the input box, the value will be the first input number.
Anti-shake, through continuous clearTimeout, to update the function to be executed, until it is not triggered, wait for the delay to execute, the function of the delay is that if it is triggered again during this period, it will clearTimeout again

handwritten new

 // Object.create 会更新 __proto__,也就是 [[Prototype]],维持原形链
function create (proto) {
    if (typeof proto !== 'object' && typeof proto !== 'function' ) {
        throw new TypeError("原型只能是对象")
    }
    if (proto === null) {
        throw new TypeError("不能为空")
    }

        // function F() {}
        //F.prototype = proto;
        // return new F();
    proto.constructor.prototype = proto
    return new proto.constructor()
}

function newOperator(ctor) {
    if (typeof ctor !== 'function') {
        throw '构造函数必须是方法'
    }

    newOperator.target = ctor;

    // es6 可以直接使用 Object.create
    // const instance = Object.create(ctor.prototype)
    const instance = create(ctor.prototype)
    const args = [].slice.call(arguments, 1)
    // 绑定 this,并执行构造函数
    const r = ctor.apply(instance, args);
    // 如果构造函数有返回,则返回构造函数
    if (r) {
        return r;
    }

    // 实例
    return instance;
}

function Person (name) {
    this.name = name
}


const w = newOperator(Person, "zs")

console.log(w)

handwritten bind

 function bind(fn, obj) {
    const args = [].slice.call(arguments, 1);
    const selef = this;
    return function bound() {
        return fn.call(obj, [].slice.call(arguments, 1).concat(args))
    }
}

const h = {
    name: 'zs',
}

function say() {
    console.log(this.name)
}

const bound = bind(say, h)
bound()

Object.is Polyfill

 if (!Object.is) {
  Object.defineProperty(Object, "is", {
    value: function (x, y) {
        if (x === y) {
            // 1. 如果 x === y,且均不为0时
            // 2. 如果 x,y 均为 0 ,判断符号是否相等
            return x !== 0 || 1 / x === 1 / y; 
        } else {
            // NaN 与自己比较。 包含:Number.NaN, 0/0, NaN
            return x != x && y != y;
        }
    }
  })
}

How to implement Array.reduce()

To be added

curry and compose

To be added

Object.assign()

To be added

Implement string repeat

 // 原生repeat 'ni'.repeat(3); 
// 'ninini' 
// 实现一 
String.prototype.repeatString1 = function (n) { 
    return Array(n + 1).join(this); 
} 
console.log('ni'.repeatString1(3)); 
// 实现二 
String.prototype.repeatString2 = function (n) { 
    return Array(n).fill(this).join('');
}
console.log('ni'.repeatString2(3));

js template engine

 Function('let a = 1');

other

other


donggg
203 声望584 粉丝

> github