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.create
、Object.keys
、Object.values
、Object.entries
、Object.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
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');
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。