js looks at the code and says the output

Table of contents

prototype

Function与Object

new fn()

prototype chain

constructor

function.length

Default parameters: the number of parameters before the first one with a default value

Remaining parameters: not included in length

Closure

in loop

Function factory: parameter passing

IIFE: anonymous closure

let: closure

forEach(): similar to let+for

setTimeout

IIFE:匿名闭包

setTimeout(functionRef, delay, param...)

this+closure

this

JS pre-parsing/compilation (variable promotion)

let

temporary dead zone

=Priority: right to left

Output sequence event loop

async, await event polling execution timing

async implicitly returns Promise, which will generate a microtask await xx; the following code will be executed during the microtask

process.nextTick in Node

process.nextTick execution order is earlier than microtask

string

str[i]=assignment

str.indexOf('',i):i

n=n++

Cache the original value, auto-increment, use the cached original value to perform operations

Parse from left to right, and form symbols if they can

原型

Function与Object

var F = function() {};

Object.prototype.a = function() {
  console.log('a');
};

Function.prototype.b = function() {
  console.log('b');
}

var f = new F();

f.a(); // a
f.b(); // f.b is not a function

F.a(); // a
F.b(); // b

new fn()

function A() {}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;

console.log(new A().a); //1
console.log(new B().a); //undefined(传入a为undefined)
console.log(new C(2).a);//2
console.log(new C().a); //1

原型链

123['toString']: Use square brackets to access properties on the number 123

The number itself has no toStringmethod, so search along the way to find the toString method. The length of the toString method is 1 __proto__.function Number()prototype

numObj.toString([radix])

console.log(123['toString'].length + 123) // 124
function fun(){
    this.a = 0
    this.b = function(){
        console.log("自己的b:",this.a)
    }
}

fun.prototype = {
    b: function(){
        this.a = 20
        console.log("原型链b:",this.a)
    },
    c: function (){
        this.a = 30
        console.log(this.a)
    }
}

var my_fun = new fun()

my_fun.b()    // 0
my_fun.c()    // 30
function Foo() {
    getName = function (){
        console.log(1)
    }
    return this
}

Foo.getName = function () {
    console.log(2)
}

Foo.prototype.getName = function(){
    console.log(3)
}

Foo.getName()//2

Foo().getName();//1

getName();//1:getName函数变量提升到全局

new Foo.getName()//2 Foo函数有对象有个getName(...2)属性方法
//先对 new Foo() 实例化再对 A.getName() 调用,
//对 new Foo() 实例化调用的 getName() 方法是原型 prototype 上的
new Foo().getName()//3  
// new new Foo().getName() => new B.getName(),
//先对 new Foo() 实例化再对 new B.getName() 实例化,
//new B.getName() 同时也在执行 B.getName() 方法输出的还是实例 B 上的方法也就是原型 prototype 的 getName
new new Foo().getName()//3

constructor

f1,f2中本没有 constructorprototype But the equivalent will be found  from the constructor  f1.prototype.constructor, f2and the prototype is redefined to point to the base class. object

找不到的,只会往上找,而非往下,所以原型上不存在n

function Fn(){
    var n = 10
    this.m = 20
    this.aa = function() {
        console.log(this.m)
    }
}

Fn.prototype.bb = function () {
    console.log("原型的this.n",this.n)
}

var f1 = new Fn

Fn.prototype = {
    aa: function(){
        console.log(this.m + 10)
    }
}

var f2 = new Fn

//注意区别修改原型Fn.prototype和修改原型的属性Fn.prototype.bb
console.log(f1.constructor)     // ==> function Fn(){...}
console.log(f2.constructor)     // ==> Object() { [native code] }

//原型中
f1.bb()    // n是 undefined
//自己有aa方法,就不去原型链上找了
f1.aa()    // 20
f2.aa()    // 20
//原型链上的aa方法中,原型没有m属性,undefined+10=NaN
f2.__proto__.aa()    // NaN
f2.bb()     //  Uncaught TypeError: f2.bb is not a function

function.length

默认参数:第一个具有默认值之前的参数个数

function fn1 (name) {}

function fn2 (name = '林三心') {}

function fn3 (name, age = 22) {}

function fn4 (name, age = 22, gender) {}

function fn5(name = '林三心', age, gender) { }

console.log(fn1.length) // 1
console.log(fn2.length) // 0
console.log(fn3.length) // 1
console.log(fn4.length) // 1
console.log(fn5.length) // 0

Remaining parameters: do not countlength

function fn1(name, ...args) {}

console.log(fn1.length) // 1

闭包

var ary = [1, 2, 3, 4]
function fn(i){
    return function(n){
        console.log(n+ (i++))
    }
}

var f = fn(10)
f(20)   // 30       (n+10)
f(20)   // 31       (n+11)

fn(20)(40)  // 60  
fn(30)(40)  // 70

// console.log(i)  //   Uncaught ReferenceError: i is not defined

循环中

Variables   are declared using and item have  function scope due to variable promotion . When   the callback is executed,  the value of is determined. Since the loop has completed executing long before the event is triggered , the variable object  (shared by the three closures) already points to  the last item .varonfocusitem.helpitem helpText


function setupHelp() {
  ...
  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function () {
      showHelp(item.help);
    };
  }
}

setupHelp();

Function factory: parameter passing

function makeHelpCallback(help) {
  return function () {
    showHelp(help);
  };
}

function setupHelp() {
...

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp();

IIFE: anonymous closure

function setupHelp() {
...

  for (var i = 0; i < helpText.length; i++) {
    (function () {
      var item = helpText[i];
      document.getElementById(item.id).onfocus = function () {
        showHelp(item.help);
      };
    })(); // 马上把当前循环项的 item 与事件回调相关联起来
  }
}

setupHelp();

let: closure

function setupHelp() {
...

  for (let i = 0; i < helpText.length; i++) {
    const item = helpText[i];
    document.getElementById(item.id).onfocus = () => {
      showHelp(item.help);
    };
  }
}

setupHelp();

forEach(): similar to let+for

function setupHelp() {
 ...

  helpText.forEach(function (text) {
    document.getElementById(text.id).onfocus = function () {
      showHelp(text.help);
    };
  });
}

setupHelp();

setTimeout

The var variable is promoted to global and can be declared repeatedly

for(var i=0;i<2;i++){
    setTimeout(()=>{console.log(i)},1000)//3,3
}
for(var i=0;i<3;i++){
    setTimeout(()=>{console.log(i)},1000)//3,3,3
}
console.log(i)//3

IIFE: anonymous closure

for (var i = 0; i < 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, 1000);
  })(i);
}
//或者
for(var i = 0;i < 5;i++)
{
    setTimeout((function(i){
        return () => console.log(i);
    })(i),1000)
}

setTimeout(functionRef, delay, param...)

// 利用setTimeout的第三个参数,第三个参数将作为setTimeout第一个参数的参数
for (var i = 0; i < 5; i++) {
  setTimeout(function fn(i) {
    console.log(i);
  }, 1000, i); // 第三个参数i,将作为fn的参数
}

this+closure

var num = 10    // 60; 65
var obj = {
    num: 20    
}
//自执行obj.fn= function(n){this.num+=n...}
obj.fn = (function (num){
    this.num = num * 3  // window.num=20*3
    num++    // 21 
    return function(n){
        this.num += n    // 60 + 5 = 65;20 + 10 =30
        num++   // 21 + 1 = 22;22 + 1 = 23 闭包引用num
        console.log(num)
    }
})(obj.num)

var fn = obj.fn 

fn(5)   // 22  this 指向 window

obj.fn(10)   // 23  this 指向 obj

console.log(num, obj.num)    // 65, 30

this

this.count=1
function func() {
  console.log(++this.count)//2
}

func.count = 0
func()

obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }

    return arrowFunc
  },

  _name: "obj",
}

obj.func()()//obj

func = obj.func
func()()//undefined

obj.func.bind({ _name: "newObj" })()()//newObj

obj.func.bind()()()//undefined

obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()//bindObj



JS pre-parsing/compilation (variable promotion)

//虽然按顺序创建作用域,不会报错a为声明
function foo() {
  console.log(a);
}

function bar() {
  var a="bar"
  foo(); 
}

bar(); //undefined
var a="window"
var a = 1;
function foo(a, b) {
  console.log(a); // 1
  a = 2;
  arguments[0] = 3;
  var a;
  console.log(a, this.a, b); // 3, 1, undefined
}
foo(a);

let

temporary dead zone

function test() {
  var foo = 33;
  if (foo) {// var foo 
    //foo+55是let 的 foo
    let foo = foo + 55; // ReferenceError
  }
}
test();

The identifier na is resolved to attribute a of the n object located in the instruction (let n) itself. Because the statement of n has not yet been executed, it is still in the temporary dead zone.

function go(n) {
  // n 在此处被定义
  console.log(n); // { a: [1, 2, 3] }

  for (let n of n.a) {
    //          ^ ReferenceError
    console.log(n);
  }
}

go({ a: [1, 2, 3] });

=Priority: right to left

= The priority is from right to left, so after the variable promotion stage b=undefined, c is assigned to undefined.

var b = {
    a,
    c: b
}
console.log(b.c);
//undefined

Output sequence event loop

//宏任务队列:[]
//微任务队列:[promise0]
Promise.resolve()
  .then(function() {
    console.log("promise0");
  })
  .then(function() {
    console.log("promise5");
  });
//定时的setTimeout(delay=0)=setImmediate:下个Event Loop执行
//宏任务队列:[timer1]
//微任务队列:[promise0]
setTimeout(() => {
  console.log("timer1");
  
  Promise.resolve().then(function() {
    console.log("promise2");
  });
  Promise.resolve().then(function() {
    console.log("promise4");
  });
}, 0);
//宏任务队列:[timer1,timer2]
//微任务队列:[promise0]
setTimeout(() => {
  console.log("timer2");
  Promise.resolve().then(function() {
    console.log("promise3");
  });
}, 0);
//宏任务队列:[timer1,timer2]
//微任务队列:[promise0,promise1]
Promise.resolve().then(function() {
  console.log("promise1");
});
//执行start
console.log("start");
//执行当前所有微任务队列:[promise0,promise1]
//执行promise0时将promise5放入了微任务队列:[promise1,promise5]
//接着执行微任务队列:输出promise1,promise5
//当微任务队列为空,开始执行宏任务队列[timer1,timer2]队首的timer1
//执行timer1时碰到了微任务promise2,放进微任务队列[promise2]
//宏任务timer1执行完了,开始执行所有当前所有微任务:[promise2]
//执行promise2完碰到微任务promise4,放进微任务队列:[promise4]
//当前微任务队列不为空,接着执行promise4
//微任务队列为空,接着执行宏任务队列队首[timer2]
//执行timer2时碰到了微任务promise3,放进微任务队列[promise3]
//宏任务timer2执行完了,开始执行所有当前所有微任务:[promise3]


// 打印结果: start promise0 promise1 promise5 timer1 promise2 promise4 timer2 promise3

async, await event polling execution timing

async implicitly returns Promise, which will generate a microtask
await xx; the following code will be executed during the microtask


//1.script start(同步)
console.log("script start");

async function async1() {
  await async2(); // await 隐式返回promise
  console.log("async1 end"); // 这里的执行时机:在执行微任务时执行
}

async function async2() {
  console.log("async2 end"); // 这里是同步代码
}
//2.async2 end(同步)
//微任务队列:[async1 end]
async1();
//宏任务队列:[setTimeout],setTimeOut进入下一loop
setTimeout(function() {
  console.log("setTimeout");
}, 0);
//3.Promise(同步)
//宏任务队列:[setTimeout]
//微任务队列:[async1 end,promise1]
new Promise(resolve => {
  console.log("Promise"); // 这里是同步代码
  resolve();
})
  .then(function() {
    console.log("promise1");
  })
  .then(function() {
    console.log("promise2");
  }); 
//4.script end(同步)
console.log("script end");
//当前loop的宏任务(都是同步代码)都执行完毕
//执行所有微任务[async1 end,promise1]
//执行promise1完后碰到了promise2,加入微任务队列,接着执行
//当前所有微任务都执行完毕,开始执行宏任务队列[setTimeout]

// 打印结果:  script start => async2 end => Promise => script end => async1 end => promise1 => promise2 => setTimeout

process.nextTick in Node

process.nextTick execution order is earlier than microtask

console.log("start");
//定时进入下一loop,宏任务队列:[timeout]
setTimeout(() => {
  console.log("timeout");
}, 0);
//微任务队列:[promise]
Promise.resolve().then(() => {
  console.log("promise");
});
//process.nextTick在微任务队首
//微任务队列:[nextTick,promise]
process.nextTick(() => {
  console.log("nextTick");
  Promise.resolve().then(() => {
    console.log("promise1");
  });
});
console.log("end");
// 执行结果 start end nextTick  promise promise1 timeout 

string

str[i]=assignment

In JavaScript, strings are immutable, str is a basic data type, or string object, and String methods return new values.

Only arrays and objects are mutable, while immutability can bring performance and security benefits.

let str=new String("123")
str[0]="z"
console.log(str[0])//1

str.indexOf('',i):i

let str = "Hello";
let index = str.indexOf("",0);
console.log(index); // 输出 0
 index = str.indexOf("",3);
console.log(index); // 输出 3
 index = str.indexOf("",6);
console.log(index); // 输出 5

n=n++

Cache the original value, auto-increment, use the cached original value to perform operations

Parse from left to right, and form symbols if they can

The compiler will parse character by character from left to right. If the parsed characters can already form a symbol, it will parse the next character and determine whether the next character can be combined with the parsed symbol to form a symbol again. If it can , and then repeat the above process; if not, use the final parsed symbol.

var n=1
n=n++
console.log(n)//1

//等价于
var n=1;
//n=n++运算开始
var temp=n;    //编译器解析到“n=n++”中的“n++”后,会先在内存中缓存n的原值,用来参与其他运算
n = n+1;       //编译器解析到“n=n++”中的“=”后,会在做“=”运算前将n自加
n = temp;      //变量自加结束后,用缓存的原值进行“=”运算
//n=n++运算结束
console.log(n) //1

var a=3,b;
b=a++*a++;
console.log(b)    //12

var a=3,b;
b=a+++a;        //b=(a++)+a, b=3+4
console.log(b)  //7

Reference link: The first part of JS classic interview questions (this, closure, prototype...) with answers - Nuggets

Guess you like

Origin blog.csdn.net/qq_28838891/article/details/132907055