This article is in the column “Front-end System” Javscript – the foundation of Web Coder

Online humble, if after reading feel this article is helpful to you, welcome everyone to point a like 👻

preface

It’s been more than a month since the last post. I didn’t write an article about Vue-CLI until now (sorry 🙊). It’s not that I don’t want to write it, but I started writing it right after I posted the vue-Router best Practices. The official document is very detailed, and I don’t want to be perfunctory (in fact, it is my food 😂), so I haven’t finished writing. Also, because the company will evaluate and rank interns soon, so I focus on the functional requirements. In order to prove that I am not looking for excuses, the following screenshots are given, and the cascade assessment requirements of the company are attached (small companies, technical requirements are certainly not as difficult as large companies), everyone can compare their ability to see where

In fact, in addition to the above technical problems, for other aspects of the investigation, this is reflected in your presentation PPT, well, no more nonsense, the following is what I do this month

shift

In fact, the above is the goal I set at the beginning, but later I found it was too much to write, and I also found I had too much to learn. Calculate below oneself from step front end to now nearly a year and a half time, this way can be said to be diligent. Remember didn’t go to work I asked in the front end of a sentence, can get 10 k salary for fresh graduates (when beginner front by big institutions created the idea of bombing of recruit students teacher friends), group a brother said to me, you have to learn every day, code, timing, rising?

This sentence is very deep in my memory, and always reminds me when I want to give up on the road of self-study. The same goes for you now

At that time, I thought for a long time and found that although I seemed to be learning every day, as if I was very serious and hard working, I always felt that I forgot the front after learning. I also asked many people this question, and the old friends in the front group gave me the answer: very normal, everyone is like this. I even asked the training lecturers of those institutions (when listening to those open classes), and the answer I got was that the learning was too fragmented and there was no systematic learning.

Until recently I saw the answer to the article

Why did you forget? People for some too one-sided, too shallow understanding and not hands-on knowledge will only stay in the brain for a short time, over time forgotten, but you can really learn things in a lifetime? Obviously not, so the best way to form a long-term memory is to constantly review and practice. Ensure that your mind will be able to remember quickly when it is about to forget. It is impossible for you to cover every detail of all the knowledge points you have learned, so the way you learn is very important. When you learn this knowledge point, you must have a deep understanding, so that you can have a deep impression of the scene of this knowledge point in your mind. I don’t know if you will have this feeling. It means that even if you haven’t touched it for a long time, you will immediately come across the impression of the scene that you understood at that time

This kind of feeling can only be found for a particular piece of learning that I am very good at. It is also such an opportunity that I began to think that I have learned so much, spent so much time, really can it? That’s why this article was born.

Is actually a title at the beginning * * the interview will be recommended collection 】 【 long list | a swastika, under the set out to write to the as if they haven’t really learned so long the systematic review. To the knowledge point that learns way to learn at the beginning learned at that time thought to have passed, is it true meeting? So I am going to write a series of articles about what I have learned in a year and a half.

The following is my personal front end system map, of course, this is certainly not complete, the content inside I will continue to learn, constantly modify, improve.

! [] (cdn.jsdelivr.net/gh/it-beige…” Build an oaks from the ground up.

In fact, my mental state changed as I wrote this article

Have ten thousand thoughts in your head – > encounter problems in action – > lose morale intermittently – > start over again

Because writing an article is very different from taking notes. Although I have taken a lot of notes, it is very difficult to write a good article. I must not have reviewed all the systems above. Front-end is the most inseparable from JS, with the development of JS, it can be said that the depth of UNDERSTANDING of JS to a large extent to determine whether you can rise from the primary front-end development to advanced front-end development. So I focus on the contents of JS, this article will first JS basic part sent to the follow-up finishing and then sent, the article aims to summarize, refining. For some too basic, I won’t say much, the overall code is more and will give some related interview questions after each knowledge point.

Data type detection and conversion

Data values are the material that a programming language produces. Js contains values of the following types

  • Basic data types (value types)
    • Number
    • String
    • Boolean
    • Null
    • Undefined(null unique in JS)
    • Symbol (ES6 added)
    • BigInt (ES6新)
  • Reference data type (reference type)
    • Object
      • Ordinary objects
      • The function object
      • The array object
      • Regular object
      • The date object
      • .

I’m not going to say much about it, but I’m going to get right to the point.

Data type detection

  • typeof
  • instanceof
  • constructor
  • Object. The prototype. ToString. Call () “best way”

Each of the above method, the Object. The prototype. ToString. Call () this way is the best way.

typeof

let a = 'north song',
    b = 18,
    c = [12.23],
    d = {a: 1},
    e = new Map(),
	f = new Set(),
    g = new RegExp('A-Z'),
    h = new Function(),
    i = null,
    j = undefined,
    k = Symbol(),
    l = false; 

console.log(typeof a); // String
console.log(typeof b); // Number
console.log(typeof c); // object
console.log(typeof d); // object
console.log(typeof e); // object
console.log(typeof f); // object
console.log(typeof g); // object
console.log(typeof h); // function
console.log(typeof i); // object
console.log(typeof j); // undefined
console.log(typeof k); // symbol
console.log(typeof l); // boolean
// => Problem: can't distinguish arrays from objects
Copy the code

How many data types can Typeof detect? What kind of their own count.

Problem a

console.log(typeof[])?console.log(typeof typeof[])?Copy the code

The answer

The result of typeof test is a string, so any data type that you typeof twice or more is a string

Question 2

What are the values of typeof a and typeof B in the following code:

function foo() {
  let a = b = 0;
  a++;
  return a;
}

foo();
typeof a; / / = >???
typeof b; / / = >???
Copy the code

The answer

Let’s look closely at line 2: let a = b = 0. This statement does declare a local variable a. However, it does declare a global variable b.

The variable b is not declared in the foo() scope or global scope. So JavaScript interprets the expression b = 0 as window.b = 0.

In the browser, the above code snippet is equivalent to:

function foo() {
  let a;  window.b = 0;  a = window.b;  a++;
  return a;
}

foo();
typeof a;        // => 'undefined'
typeof window.b; // => 'number'

typeofA is'undefined'. The variable a is declared only within the scope of foo() and is not available outside the scope.typeofB is equal to'number'. B is a value of b0Global variableCopy the code

instanceof

The instanceof operator checks whether an instance object has a prototype property on its prototype

a instaceof B
// => to check whether a is an instance of B, if true, otherwise vice versa


[] instanceof Array; // true
{} instanceof Object; // true
new Date(a)instanceof Date; // true
new RegExp(a)instanceof RegExp // true
Copy the code

Problem 1: There is a difference between primitive type literals and instance creation

console.log(1 instanceof Number) // false
console.log(new Number(1) instanceof Number)// true
Copy the code

Problem 2: We use it to detect true as long as we are on the prototype chain of the current instance

let arr = [1.2.3];
console.log(arr instanceof Array) // true
console.log(arr instanceof Object);  // true
function fn() {}
console.log(fn instanceof Function) // true
console.log(fn instanceof Object) // true

// => < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; white-space: inherit! Important;
let arr = new Array('1'),
    fun = new Function(a); So we start off with the arR array instance object at the top of the array objectObject.prototype impossible andFunctionprototypeconsole.log(arr instanceof Function); // false Put the array prototype chain on the prototype chain, that isArrayThe top of the prototype chainObjectThe. Prototype point has been changed toFunction.prototype
arr.__proto__.__proto__ = Function.prototype;
console.log(arr instanceof Function); // true
// Draw a simple picture below (a little ugly friends can understand)
Copy the code

Instaceof principle

function myInstanceof(leftVal, rightVal) {
	let proto = leftVal.__proto__,
        rightPrototype = rightVal.prototype;
    while(true) {
        if (proto === null) return false;
        if (proto === rightPrototype) return trueproto = proto.__proto__; }}Copy the code

Problem 3: Null and undefined cannot be detected

For the special data types null and undefined, their classes are null and undefined, but the browser does not allow us to access them from outside.

So let’s do a couple of problems

function Foo(){} 
function BFoo(){} 
Foo.prototype = new BFoo();
let foo = new Foo();
console.log(foo instanceof Foo); ?
console.log(foo instanceof BFoo); ?
Copy the code

After talking about the instanceof principle, I believe that the above problem should not be difficult for you. Now let’s see a few more complicated points

console.log(String instanceof String); 
console.log(Object instanceof Object); 
console.log(Function instanceof Function); 
console.log(Function instanceof Object);

function Foo(){} 
function BFoo(){} 
Foo.prototype = new BFoo();
console.log(Foo instanceof Function);
console.log(Foo instanceof Foo);
Copy the code

This is where the prototype chain comes in, and we’ll talk more about prototypes later, but just briefly

  • All instance objects will have one__proto__(we call this the prototype chain property) that points to the owning constructorprototype(Prototype properties)
  • The browser will give eachThe constructorOpen up aprototypePrototype object, which provides the member properties and methods to be invoked by the instance object
  • eachprototypeThey bring one with themconstructorRefers back to the constructor to which the stereotype object belongsconstructorLost)
  • The biggest Boss of the built-in classes is not the base class Object. Object is also constructed from the built-in Function, soObject.__proto __= = =Function.prototype
  • Built-in functions are also built by themselves, soFunction.__proto__ = = =Fcuntion.prototype

In summary, the largest Boss of common objects is Object, and the largest Boss of Function objects is Function

/** * built-in class: * - Function * - Object * - Number * - Array * - String * - Boolean * - RegExp * - Date * - Map * - Set * ....... * /

console.log(String.__proto__ === Function.prototype);
console.log(Number.__proto__ === Function.prototype);
console.log(Boolean.__proto__ === Function.prototype);
console.log(Date.__proto__ === Function.prototype);
console.log(RegExp.__proto__ === Function.prototype);
console.log(Object.__proto__ === Function.prototype);
console.log(Array.__proto__ === Function.prototype);
console.log(Map.__proto__ === Function.prototype);
console.log(Set.__proto__ === Function.prototype);
Copy the code

Well, we can finally get back to business!

Take these two questions for example 🌰

console.log(Object instanceof Object); 
console.log(Foo instanceof Foo);
Copy the code

According to the above principle analysis:

The first question

The first round of assignment:

L = Object.__proto__ = Function.prototype R = Object.prototype

The first round of judgment L! == R = true

__proto__ = function.prototype. __proto__ = object.prototype R = object.prototype

L === R = true

The second question

The first round of assignment:

L = foo. __proto__ = funtion. protoype R = foo. prototype (overwritten as an instance object of BFoo)

The first round of judgment L! == R = true

__proto__ = function.prototype. __proto__ = object.prototype R = foo.prototype (overwritten as an instance Object of BFoo)

If L === R is false, then L == R is false. If L == R is false, then L == R is false

The method has been taught to you and you can judge the rest.

constructor

It simply refers to the constructor of the object

function Foo(){};
var foo = new Foo();
alert(foo.constructor); // Foo
alert(Foo.constructor); // Function
alert(Object.constructor); // Function
alert(Function.constructor); // Function
// This is done by looking for constructor in the prototype chain of the instance object
Copy the code

Problem a

For null and undeinfed invalid values, constructor does not exist and needs to be determined in other ways

Question 2

Constructor by constructor is unstable and unnecessary trouble may arise if the prototype is reset or constructor is lost

function Fn(){}
Fn.prototype = new Array(a)var f = new Fn
console.log(f.constructor) // Array

Fn.prototype = {}
console.log(f.constructor) // Object
Copy the code

Object.prototype.toString.call()

  • Returns an internal property of some data[[class]], can help us accurately determine a data type

This method is one of the most commonly used methods of detecting types

let a = 'north song',
    b = 18,
    c = [12.23],
    d = {a: 1},
    e = new Map(),
	  f = new Set(),
    g = new RegExp('A-Z'),
    h = new Function(),
    i = null,
    j = undefined,
    k = Symbol(),
    l = false; 

console.log(Object.prototype.toString.call(a)); // [object String]
console.log(Object.prototype.toString.call(b)); // [object Number]
console.log(Object.prototype.toString.call(c)); // [object Array] 
console.log(Object.prototype.toString.call(d)); // [object Object] 
console.log(Object.prototype.toString.call(e)); // [object Map] 
console.log(Object.prototype.toString.call(f)); // [object Set]
console.log(Object.prototype.toString.call(g)); // [object RegExp]
console.log(Object.prototype.toString.call(h)); // [object Function]
console.log(Object.prototype.toString.call(i)); // [object Null]
console.log(Object.prototype.toString.call(j)); // [object Undefined]
console.log(Object.prototype.toString.call(k)); // [object Symbol]
console.log(Object.prototype.toString.call(l)); // [object Boolean]
Copy the code

The good way, of course, is to encapsulate a wave

let isType = (type) = > (o) = > Object.prototype.toString.call(o) === `[object ${type}] `;
console.log(isType('Array') ([]));Copy the code

So good method, have you ever wondered how it is implemented inside?

ToStringTag: Symbol. ToStringTag: Symbol. ToStringTag: Symbol. ToStringTag: Symbol.

Symbol. ToStringTag The known Symbol is the string value property used in creating the default string description of the object. It is composed of the Object. The prototype. The toString () method in internal access. This method determines what the [[class]] internal attribute is for all the data types we just mentioned.

let map = new Map(),
    set = new Set(a);console.dir(map);
console.dir(set);
Copy the code

Let’s call their toString method

console.log(map.toString()); // [object Map]
console.log(set.toString()); // [object Set]
console.log(arr.toString()); / / '12 and 23'
Copy the code

Why and map and set call the toString () results and Object. The prototype. The toString. Call the same results () call?? So why not the ARR??

Let me print out the ARR

It doesn’t have a Symbol. ToStringTag method. Looking back at the map and set above, we see that they don’t have a toString() method

Can we understand it this way?

  • There is noSymbol.toStringTagThe type of the built-in property is calledtoString()Is equivalent toString(obj)The call is thus converted to the corresponding string
  • There areSymbol.toStringTagThe type of the built-in property is calledtoString()Returns the appropriate tag (i.e"[object Map]"Such a string)

Back to the point, what gay love does it have with object.prototype.tosting () 🤔️?? Again, in the code

class Super {}
console.log(Object.prototype.toString.call(new Super()))
Copy the code

This should make sense. If we define a class that prints out as “[object Function]”, what if we add a Symbol. ToStringTag built-in property to this object prototype?

class Super {
  get [Symbol.toStringTag]() {
    return 'Test'; // => Symbol. ToStringTag allows us to customize the returned class tag}}console.log(Object.prototype.toString.call(new Super())); // [object Test]
// Note: Symbol. ToStringTag overwrites the tag of the instance object of class Super, not the tag of class Super
console.log(Object.prototype.toString.call(Super)) // "[object Function]"
Copy the code

ToStringTag will access this method internally if the object prototype has Symbol. ToStringTag will implement one for you if it doesn’t, That is why call Object. The prototype. ToString will get specific Object tags

The disadvantages of the first three methods are summarized in a wave:

  • typeof
    • Objects and arrays cannot be subdivided
    • There is no distinction between special objects such as null
  • instanceof
    • The basic types created by literals are not well judged
    • As long as the object on the left side of the stereotype chain is the same as the object on the right side of the stereotype chain, there is a problem with class inheritance
    • The null and undefined types cannot be detected
  • constructor
    • Invalid for null and undefined
    • In the constructor approach, problems can also arise if prototype objects are overridden or inherited

So the last one is by far the perfect one

Data type conversion

Know js is a weakly typed language, in addition to this label it also has a js is a dynamic language, dynamic language understandable for all data types are uncertain, in the process of operation type conversion may occur, such as the definition is a string, converted by operators may be a numeric type.

Casts.

Other data types are converted to String

  • The toString () method
  • String () function

Note that null and undefined cannot call the toString() method, and that every built-in class overrides the toString method

let a = 123,
 	b = null,
 	c = undefined;
a.toString() / / "123"
b.toString() // "error"
c.toString() // "error"

// => toString()
String({a: 1}) // "[object object]" => convert to this
String([1.2.3]) / / "1, 2, 3"
String([1]) / / "1"
String(null) // 'null'
String(undefined) // 'undefined'
String(new Map()) // "[object Map]"
String(new Set()) // "[object Set]"

// => Special cases
console.log(class A {}.toString()) // 'class A {}'
console.log(function () {}.toString()) // 'function () {}'
console.log(/(\[|\])/g.toString()) // '/(\[|\])/g'
console.log(new Date().toString()) // 'Fri Mar 27 2020 12:33:16 GMT+0800 '

Copy the code

Other data types are converted to Number

One thing to remember is that actively converting to numbers is all about converting other types to strings and then converting to numbers

  • The Number () function
  • parseInt()&parseFloat()
  • +, -, * / operations

The Number() function converts null false to 0 and true to 1 for basic type conversions.

// Basic type
Number(true) / / 1
Number(false) / / 0
Number(null) / / 0
Number(3.15) / / 3.15
Numer(0x12) // 18 => Hex dec OCT bin can be identified
Copy the code
  • ParsetInt () parses the integer part of a string that is not converted to a string first
  • ParseFloat () parses the small (floating point) part of a string
parseInt(null) // => NaN

// Give us a typical interview question
let arr = [10.18.0.10.25.23.345.2345]
arr = arr.map(parseInt)
// arr => ?
Copy the code

This is an interesting problem and you can try to solve it, but if you can’t solve it, look at my solution

/* parseInt([value], [n]) - value: To convert value to a number, first convert value to String, then look for the first character to the left of String, and convert any valid numeric character found to a number until a non-valid numeric character is encountered. We're going to put value in base N, and then we're going to convert it to decimal - normally it's a 10, but it's not a 10 by default. Such as: field begin with 0 x | 0 x, hexadecimal conversion is go - between n range [2 ~ 36] is not in the, in addition to 0 and 10, the rest are NaN * /
Copy the code

parsing

/** * parseInt('10.18', 0) * => count as decimal: 10 * parseInt('0', 1) * => Count as decimal: NaN * parseInt('10', 2) * => Count as decimal: NaN * parseInt('10', 2) * => Count as decimal: NaN * parseInt('10', 2) * => Count as decimal: NaN * parseInt('10', 2) * => Count as decimal: '10' and then convert it to 1 decimal * => Binary to decimal: use the current number (0) * the current number (2) to the power of [n](0) * => 0:0 * 2^0 => 0 * 1 = 0 * => 1: 1 * 2 ^ 1 = > 1 * 2 = 2 * * 2 * = > results parseInt (' 25 ', 3) * = > as in base 3: ParseInt ('23', 4) * => parseInt('23', 4); Contains 0, 3 * = > 3 * 4 ^ 0 = = > > 3 * 1 * 2 * 4 ^ 2 * 4 * 1 = > = > results 11 * * * parseInt (' 345 ', 5) * = > as hexadecimal 5: Contains 0, 3, 4 * 4 * = > 5 ^ 0 = = > > 4 * 1 * 3 * 5 ^ 1 = > 3 * 5 * = > results 19 * * parseInt (' 2345 ', 6) * = > as 6 hexadecimal: Contains 0,1, 2, 3, 4, 5 * 5 * 6 = > ^ 0 = = > > 5 * 1 = > 5 * 4 * 6 ^ 1 = > 4 * 6 = = > > 24 * 3 * 6 ^ 2 = > 3 * 6 * (6) = = > > 108 * 2 * 6 ^ 3 = > 2 * (6 * 6 * 6) = > 432 * => Result 569 * */ 
Copy the code

Isn’t that nice?

Other data types are converted to Boolean

  • Boolean
  • ! (Convert to Boolean and reverse)
  • !!!!! (If you convert it to a Boolean and then invert it and invert it, you’re just converting it to a Boolean.)

Null, undefined, 0, NaN, and “(empty string) convert Boolean to false and the rest to true, just remember this rule

A reference type is converted to another type

Since all reference types in JS are objects, I’ll just call them objects for short.

  • Object to a string
  • Object to a value

Object to a string

  • Calls the toString() method of the object, converts the value to a string if it returns a primitive type, and returns it
  • If there is no toString() method or the return is not a primitive type, call the valueOf() method to get its primitive type value and convert the value back to a string
  • If the object does not have either method or neither transformation succeeds, throw the error directly

Object to a value

  • Call the object’s valueOf() method to get its original type, convert the value back to a numeric value
  • If there is no valueOf() method or the value returned is not of the primitive type, the toStrig() method is called to get its primitive type value, and the value is converted to a numeric value
  • If the object does not have either method or neither transformation succeeds, throw the error directly

There’s a lot of nonsense up there about who comes first and who comes last, and it depends on whether or not the basic method call comes after the primitive type.

The flowchart is as follows:

Common object conversion string

[] = >' '
[1] = >1
[12.23] = >'12 and 23'
[' '] = >' '
{a: 1} = >'[object Object]'
Copy the code

Common object conversion values

If you want to convert an object to a value, you need to go through the process of converting an object to a string, because even if you use valueOf to get the original valueOf the object, it’s still the object type.

Let’s go through the above process with some bizarre techniques.

let obj = {}, // To convert values
    arr = [], // Used to convert to a string
    testError = {};

// ===================================> Convert a string
obj.toString = function() { / / go it
  return [12] // The return is not the original type, which means we are going backwards
}
obj.valueOf = function() {
  return 12 // Return the original value 12.
}

console.log(String(obj), typeof String(obj)); // 12 string => The result is returned as a string


// ===================================> Convert values
arr.toString = function() {
  return '12' // Return the original value 12, note that it is a String,
} 
arr.valueOf = function() { / / go it
  return {}  // The return is not the original type, which means we are going backwards
}
console.log(Number(obj), typeof Number(obj)); // 12 number =


/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = > the one more to go
testError.toString = function() {
  return {} 
} 
testError.valueOf = function() { 
  return{}}console.log(Number(testError)); / / wrong

// You can test the other procedures for yourself
Copy the code

Let’s practice with an interview question

let a = ?
if (a == 1 && a == 2 & a == 3) {
    console.log(1)}// How to make the result enter 1??
Copy the code

There’s a lot of ways to do this, but I’m talking about the object conversion rules, and I said that the different types of comparisons are automatically converted and that both of them are converted to numeric comparisons.

All right, now that we know how to do this, we can solve this problem.

let a = {value: 0}
a.valueOf = function() { // We increment a by overwriting valueOf to call valueOf every time we compare
    return ++this.value;
}
if (a == 1 && a == 2 & a == 3) { // call valueOf to get the original valueOf the object during the comparison
	console.log(1)}// In addition to overwriting valueOf, you can also override toString to achieve the same effect
let a = {
    value: 0.toString: function() {
        return ++this.value; }}Copy the code

In addition to this way there are many ways, the above can be regarded as ES6 before the code, the following write a ES6 after the implementation of the train of thought

// => object.definedProperty (); // => object.definedProperty ();
let value = 0;
Object.defineProperty(window.'a', {
	get() {
      	console.log('Called'); 
		return++value; }})if (a == 1 && a == 2 & a == 3) {
	console.log(1)}Copy the code

So this is going to be called three times, and you might say, well, there’s no access to the properties of object A, so why would get happen?

Ask this question shows that there is no good, said the implicit conversion object will invoke the valueOf | toString, except that it is for the use of implicit call. DefinedProperty is not the same as the getter method of the new object in ES6. It does not get the target object and properties, so there is no argument in the get method above. But understand this line – before the object conversion will be called once the valueOf () | toString () method

Implicit conversion

As mentioned in the previous part of js dynamic characteristics, implicit conversion will appear when calculating, which is also a point that JS has been criticized for. Let’s learn to understand implicit conversions thoroughly

Conditions for implicit conversion

  1. When using= =,&&,||And other logical operators
  2. When using+ - * /Four operators to operate

Automatically converted to a Boolean value

If (12 + 'px) {/ / 12 +' px = > Boolean (' 12 px) to true}Copy the code

Automatically converted to a numeric value

// Remember that the + operator is a concatenation if one end of the string appears
true + 1 / / 2
'true' + 1 // 'true1'
2 + null / / 2
undefined + 1 // NaN
2 + NaN // NaN = NaN
'5' - '2' / / 3
'5' * '2' / / 10
true - 1  / / 0
'1' - 1   / / 0
'5' * []    / / 0
false / '5' / / 0
'abc' - 1   // NaN
Copy the code

Automatically converted to a string

'6' + true // "6true"
'6' + false // "6alse"
'6' + {} // "6object Object]"
'6' + [] // "6 => '6' + String([]) => '6' + ''
'6' + function (){} // "6function (){}"
'6' + undefined // "6undefined"
'6' + null // "6null"
Copy the code
  • Implicit conversions in “==” comparisons
{name: 'north song'} = = {name: 'north song'} // => For reference types, compare memory addresses[] [] = = = >false

let obj1 = {},
    obj2 = obj1;
obj1 == obj2 // true
Copy the code

Transformation rules

  • The only difference is that (object == string) converts the object to a string
  • Null == undefined: true; congruent: false; special memory is required
  • NaN is not equal to anyone. You can compare NaN using the object.is () method in ES6

To consider

12+true+false+null+undefined+ + []'north song'+null+undefined+ + []true!!!!!""+!!!!!""-!!!!!false ||document.write("Can you print?") 
Copy the code

I will not talk about the above problem, through the above explanation of this problem is not difficult to everyone

Let’s do a few more questions, and you’re done

console.log([] == 0); 
console.log(! [] = =0);
console.log([] == ! [])console.log([] == []);
console.log({} == ! {});console.log({} == {});
Copy the code

Choose this abnormal condition problem 😣

console.log(! [] = =0);
Copy the code
  • The first rule you should know is that every type of comparison converts numbers
  • ! [] the use of “!” Cast to a Boolean and take the inverse false
  • False == 0 false Converts the number to 0
  • 0 = = 0

All right! Is so magical (pit dad), the rest see you 🙃.

One output for SB answer parsing

“2021.5.11.”

(! (~ + []) + {}) [- [~ +""] + [] [] * [~ + []] + ~ ~! + + []] + [] ({}) [[~! + []] * ~ + []]Copy the code

In addition to the pre-knowledge of the implicit transformation above, you need to understand:

  • Operator precedence
  • ~(bitwise operator)

A simplified version of the priority list is shown below, with a more detailed priority list diagram later in the article

Note that ⚠ : [] is an array or member access in the code

[1.2] [0] = >1// Member access[] => [] =>/ / array
Copy the code

Bitwise operators: can be simply understood as taking the number backwards and subtracting one

~0= >0The not - > -0(js essence is not -0=>0 - 1= > -1
~1= >1The not - > -1= > -1 - 1= > -2~ -1= > -1The not - >1= >1 - 1= >0
Copy the code

“Parse graph”

“Parsing code”

Note ⚠ : It is easier to understand with this diagram

The whole is divided into two parts

1Subexpression1)                                     2Subexpression2) (! (~ + []) + {}) [- [~ +""] + [] [] * [~ + []] ~ ~! + + []] + [] ({}) [[~! + []] * ~ + []]Copy the code

“Subexpression 1” section

1.1Subexpression3) (! (~ + []) + {}) []1.2Subexpression4) - [~ +""] + [] [] * [~ + []] + ~ ~! + []1.11.Subexpression5)! (~ + []) + + {}1.121.Subexpression6)  
{}


1.21.Subexpression7) - [~ +""] + [] [] * [~ + []] +1.22.Subexpression8) ~ ~! + []1.21.1.Subexpression9) - [~ +""*] [+ []]1.21.2.Subexpression10) [~ + []]Copy the code

“Subexpression 2” section

2.1Subexpression11) {} + [] []2.2Subexpression12* ~) [~! + []] + []]2.21.Subexpression13*) [~! + []]2.22.Subexpression14) ~ + []Copy the code

“Global operation”

Subexpression 3

(! (~ + []) + {}) = >(! (-1) + {}) = > 'false[object Object]'
Copy the code

Note:

{} - ({}) Parsed as object - {} parsed as block ~+[] This superposition operator must be the proximity principleCopy the code

Subexpression 4

Subexpression4)  2 + 1= >3- [~ +""] + [] [] * [~ + []] + ~ ~! +[] (subexpression7) -2 * [-1] = >2- [~ +""] + [] [] * [~ + []] - [~ +""] + [] [] = > - [...1] [0] = > -2* [~ + []] = > [...1] (subexpression8) 1~ ~! + [] = > ~ ~true= >~ -2= >1
Copy the code

‘false[object object]'[3] => s

Subexpression 2

({} + []) [[~! + []] * ~ + []]Copy the code

This is not too hard to parse at once

({} + []) = >'[object Object]'
[[~!+[]]] * ~+[] => [[-2] * -1] = > [2]
Copy the code

‘[object object]'[2] => b

There you have it 🙃

Diagram the chain of scopes

The introduction

A scope is a set of rules that determine where and how to find variables (identifiers).

Scopes are layered; an inner scope can access variables in an outer scope, and vice versa.

Let’s look at an example where a bubble metaphor for scope might make sense:

The final output is 2, 4, 12

  • Bubble 1 is global scope with identifier foo;
  • Bubble 2 is scope foo, with identifiers a, b, bar; The parameter a in the function foo also corresponds to the private variable (identifier) in the function
  • Bubble 3 is scope bar and has only identifier C.

Scope (scope)

There are two kinds of scopes in JavaScript

  • Global scope: Objects with global scope can be accessed anywhere in the code.
  • Local scope: As opposed to global scope, local scope is generally accessible only within fixed code snippets. The most common is function scope.
Global scope

There are generally several cases in which a global scope exists in JS:

  1. Outermost functions and outermost variables:
var globleVariable= 'global';  // The outermost variable
function globalFunc(){         // Outermost function
    var childVariable = 'global_child';  // Inside the function
    function childFunc(){        // The inner function
        console.log(childVariable);
    }
    console.log(globleVariable)
}
console.log(globleVariable);  // global
globalFunc();                 // global
console.log(childVariable)   // childVariable is not defined
console.log(childFunc)       // childFunc is not defined
Copy the code

As you can see from the above code, globleVariable and globalFunc are accessible from anywhere, whereas variables that do not have global scope can only be used within their scope.

  1. Variables with direct assignment not defined (made global due to variable promotion)
function func1(){
    special = 'special_variable'; // Global variables are automatically promoted without var declaration
    var normal = 'normal_variable';
}
func1();
console.log(special);    //special_variable
console.log(normal)     // normal is not defined

// What's the difference between var and no var?
// => Var cannot be deleted by delete

var a = 10;
	b = 20;
delete a; False cannot delete the value stored in this variable
delete b; // True can be deleted
Copy the code

It is possible to declare functions and variables at the global scope and make them global, but it is not recommended to do so because it may conflict with other variable names. On the one hand, if we declare variables using const or let, an error will be reported.

// Variable conflict
var globleVariable = "person";
let globleVariable = "animal"; // Error, thing has already been declared
Copy the code

On the other hand, if you declare variables with var, a second declaration of the same variable will overwrite the previous one, making your code hard to debug.

// The code written by Zhang SAN
var name = 'beige'

// The code written by Li Si
var name = 'yizhan'
console.log(name);  // yizhan
Copy the code
Local scope

In contrast to global action, local scopes are generally accessible only within fixed snippets of code. The most common is function scope.

1. Function scope

Variables defined in a function are in the scope of the function. Parameter variables are declared in the function, and each function has its own scope. This means that variables with the same name can be used in different functions and cannot be accessed from each other.

function test1() {
    var a = 10;
    console.log(a);
}

function test2() {
    var a = 20;
    console.log(a);
}

test1(); / / 10
test2(); / / 20

// => < span style = "box-size: border-box; color: RGB (74, 74, 74);
Copy the code

2. Block-level scope

ES6 introduced block-level scopes to make the life cycle of variables more manageable. Block-level scopes can be declared with the new let and const commands. Variables declared are not accessible outside the scope of the specified block. Block-level scopes are created when:

  1. Inside a function
  2. Inside a code block wrapped in a pair of curly braces

Let declaration and var declaration

  1. There is no variable promotion
  2. Repeated declarations are not allowed
  3. A temporal dead zone, or TDZ, is formed
  4. There is no mutual mapping to the global window

Code demo

// Variable promotion
console.log(str); // undefined;
var str = 'north song'; 

// There is no variable promotion
console.log(str); // str is not defined;
let str = 'north song'; 

// Allow repeated declarations => The back overwrites the front
var a = 10;
var a = 20;

// Not allowed to repeat declarations => Identifier 'b' has already been declared
let a = 10;
let a = 20;

// TDZ
function foo1() {
    console.log(a); // a is not defined
    var a = 10;
}

function foo2() {
    console.log(a); // Cannot access 'a' before initialization
    let a = 10;
}

foo1()
foo2()

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

// There is no mapping
var a = 10;
console.log(window.a); // undefined => the window object does not have this property
window.a = 20;
console.log(a); / / 10
Copy the code

The magic of binding block scope in loops

for (let i = 0; i < 10; i++) {
  // ...
}
console.log(i);
// ReferenceError: i is not defined
Copy the code

In the above code, the counter I is only valid inside the for loop; referencing it outside the loop causes an error.

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

In the above code, the variable I is declared by the var command and is valid globally, so there is only one variable I globally. The value of the variable I is changed each time we loop, and the console.log(I) inside the loop that is assigned to array A refers to the global I. In other words, all the I’s in array A point to the same I, so the runtime prints the last I, which is 10.

If let is used, the declared variable is valid only in the block-level scope, and the final output is 6.

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

In the above code, the variable I is declared by let, and the current I is only valid in the round, so each time I is a new variable, so the final output is 6. You might ask, if the variable I is redeclared for each round of the cycle, how does it know the value of the last round to calculate the value of this round? This is because the JavaScript engine internally remembers the value of the last round of the loop, and when the variable I of the round is initialized, it is calculated on the basis of the last round of the loop.

In addition, a special feature of a for loop is that the part that sets the loop variables is a parent scope, while the inner part of the loop body is a separate child scope.

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc
Copy the code

The above code runs correctly, printing ABC three times. This indicates that the internal variable I and the loop variable I are not in the same scope, and have separate scopes.

The internal implementation is equivalent to this

{
    // Parent scope
    let i; 
    for (i = 0; i < 3; i++) {
        // Subscope
        let i = 'abc'; 
        console.log(i); }}Copy the code

The scope chain

Before we talk about scope chains, how does JavaScript execute?

How is JavaScript executed?

To fully understand how JavaScript works, you need to start thinking like the engine (and its friends), asking questions from their perspective, and answering them from their perspective.

  • The engine is responsible for the compilation and execution of the entire JavaScript program from beginning to end.
  • One of the best friends of the compiler and engine, responsible for the dirty work of parsing and code generation
  • Scope • Another good friend of the engine, collects and maintains a series of queries for all declared identifiers (variables), and enforces a very strict set of rules about the currently executing code’s access to these identifiers.

JavaScript code execution is divided into two phases:

The analysis phase

The javascript compiler compiles, generates the code and analyzes it

  • Analysis function parameter
  • Analysis variable declaration
  • Analysis function declaration

At the heart of the analysis phase, an AO(Active Object) is created after the analysis is complete (that is, immediately after the next function execution phase).

Execution phase

Analysis phase After successful analysis, the AO(Active Object) is given to the execution phase

  • The engine asks the scope if there is an identifier called X in the scope.
  • If the scope has an identifier (variable), the engine uses that identifier (variable)
  • If there is none in the scope, the engine continues to look (to the upper scope), and if the identifier (variable) is not found at the end, the engine throws an error.

The core of the execution phase is to find, how to find, LHS query and RHS query will be explained later.

This section provides an example for executing JavaScript

Look at some code:

function a(age) {
    console.log(age);
    var age = 20
    console.log(age);
    function age() {}console.log(age);
}
a(18);
Copy the code

First, enter the analysis phase

As mentioned earlier, the moment a function runs, it creates an AO (Active Object).

AO = {}
Copy the code

Step 1: Analyze function parameters:

Parameter: ao.age =undefinedArgument: ao.age =18
Copy the code

Step 2: Analyze variable declarations:

// Line 3 has var age
Ao.age = 18, with the same name attribute, does not do anythingThe AO. Age =18
Copy the code

Step 3: Analyze the function declaration:

// Line 5 contains the function age
Function age(){} pays ao.age
AO.age = function age() {}

Copy the code

Enter the execution phase

After the analysis phase is successful, the AO(Active Object) will be given to the execution phase. The engine will ask the scope to find the process. So the code above in the AO chain should end up with

AO.age = function age() {}
/ / after
AO.age=20
/ / after
AO.age=20
Copy the code

So the final output is:

function age(){}20
20
Copy the code

Special instructions for LHS and RHS queries during the search

LHS and RHS are terms that appear when the engine queries for identifiers (variables). It’s also clearly described in javaScript You Don’t Know (part 1). The answer above freecodecamp describes it well:

LHS = Variable assignment or write to memory. Imagine saving a text file to your hard drive. RHS = variable lookup or read from memory. Imagine opening a text file from your hard drive.

LHS and RHS features

  • Is queried in all scopes
  • In strict mode, the engine will throw a variable if it cannot find itReferenceErrorThe exception.
  • In the non-strict mode,LHRSlightly more special: a global variable is automatically created
  • When the query is successful, the engine will throw an unreasonable operation on the value of a variable, such as a function call on a value that is not a function typeTypeErrorabnormal

LHS and RHS examples from Javascript You Don’t Know (part 1)

function foo(a) {
    var b = a;
    return a + b;
}
var c = foo( 2 );
Copy the code
Engine: I said scope, I need an LHS reference for C, have you seen it? Scope: Don't say I've seen it. The compiler kid just declared it. Here you go. Engine: dude too enough meaning! Engine: Scope, one more thing. I need to do an assignment for C, foo RHS reference have you seen that? Scope: We've seen this before, the compiler recently referred to it as a function engine: Ok now I'm going to execute Foo, it better be a function type engine scope, one more thing. I need to make an LHS reference for A, have you seen this? Scope: We've seen this before. The compiler recently named it as a formal argument to foo. Here you go. Engine: Thank you so much. You're always so good. Now I'm going to assign 2 to a. Engine: Sorry to bother you again, buddy. I'm going to give B an LHS citation. Have you met this guy? Scope: we two who and who, and that's what I do. The compiler that boy just declare it, I'll give you a engine: mua. Can you help me find the RHS reference to A again? I remember it, but I want to make sure. Scope: Don't worry, this variable has not changed, take away, thank you. Engine: Can you help me find the RHS references for A and B again? I remember it, but I want to make sure it's scoped again: don't worry, this variable hasn't changed, take it away, thanks. Engine: Ok, now I'm going to return 2 + 2Copy the code

Now look at the process the engine is looking for in scope: LSH (write to memory) :

c=, a=2(implicit variable assignment), b=Copy the code

RHS(read memory) :

Read the foo (2), = a, a ,b
(returnWhen a + b, we need to look for a and b.Copy the code

A final summary of the scope chain is illustrated with a graphic from Javascript You Don’t Know (part 1)

Ok, you should now think of the scope chain as a building in your mind, with the currently executed scope located on the first floor and the global scope at the top. The scope collects and maintains all declared identifiers (variables). When a function is called, it looks up one level (the previous scope) if it does not have the identifier, and stops when the window is empty.

Finally, let’s look at the code

let str = 'global' // Global scope
function outer() { // Layer 2 scope
    let str = 'outer';
    return function inner() { // Layer 1 scope
        console.log(str); }}let inner = outer();
inner(); // outer
Copy the code

Scope or concept more, in fact, is a upward search rules, this article may write a little verbose, in fact, mainly from the scope topic leads to the JS operating mechanism 😊, the title also has nothing to do.

The prototype,

Is originally don’t want to write the prototype, closure, this these, because this kind of article is really too much and speak very detailed, but it is study for the first time since the do summary these are written, but for these three articles I want to change a way to write, give priority to with the code, from some related interview questions to explain some difficult to understand the knowledge. Considering that the people who read my article should be the same as me who have stepped into the front for a short time. So also posted a personal think pretty good article, for this piece of not quite understand can see again to brush the problem

  • The most detailed JS prototype and prototype chain ultimate detailed, no “could be”. (a)
  • The most detailed JS prototype and prototype chain ultimate detailed, no “could be”. (2)
  • The most detailed JS prototype and prototype chain ultimate detailed, no “could be”. (3)

After reading the above three articles, you can basically get a good idea of the prototype chain, but since the above articles were written in ’16, they are detailed but some of the content and ideas may be slightly different after ES6. In this article, I doubt that Function. Prototype refers to an empty Function, so I will summarize my understanding of the prototype chain.

Let me start with a few words that I summarized about prototypes above

  • All instance objects will have one__proto__(we call this the prototype chain property) that points to the owning constructorprototype(Prototype properties)
  • The browser will give eachThe constructorOpen up aprototypePrototype object, which provides the member properties and methods to be invoked by the instance object
  • eachprototypeThey bring one with themconstructor(constructor property) refers back to the constructor to which the stereotype object belongsconstructorLost)
  • The biggest Boss of the built-in classes is not the base class Object. Object is also constructed from the built-in Function, soObject.__proto __= = =Function.prototype
  • Built-in functions are also built by themselves, soFunction.__proto__ = = =Fcuntion.prototype

The difference after ES5 and ES6

The difference in terminology

Before ES6 has no concept of class with class constructor simulation, so has the concept of class, after ES6 by class to class its principle is also defined by (the class itself to the constructor (class = class. The prototype. The constructor), so also is the constructor of another kind of syntactic sugar.

In the case of __proto__, this genus is the prototype property of the instance object’s implicit constructor. It was intended to abolish this property before it was standardized before ES6, since most modern browsers have this property and it was standardized after ES5, but it is not recommended to use this method to find the prototype of an instance Object, after ES6 we can get it by using object.getPrototypeof

The difference in writing

// ===========================> ES5
// Point the superclass stereotype to the subclass
function inheritPrototype(subType, SuperType) {
  let prototype = Object.create(SuperType.prototype); // Get a prototype copy of the parent class
  prototype.constructor = subType; // Solve the problem of subclass overwriting stereotype object constructor missing
  subType.prototype = prototype
}

/ / parent class
function Es5Super(colors) {
  this.colors = ['red'.'blue'.'green'];
}
Es5Super.prototype.getColor = function (index) {
  console.log(this.colors[index]);
}

/ / subclass
function Es5(name) {
  this.name = name;
}

inheritPrototype(Es5, Es5Super); 

// Write the method on the prototype
Es5.prototype.getName = function() {
  console.log(this.name + 'Public Member');
}
// Add members to the function object
Es5.getName = function() {
  console.log(this.name + 'Private Member');
}

// ===========================> ES6
class ECMAScript{
  constructor(version) {
    this.version = version; }}class Es6 extends ECMAScript {
  constructor(name, version) {
    super(version)
    this.name = name;
    this.version = this.version;
}

  getName() { // Write the method on the prototype
    console.log(this.name + 'Public Member');
  }

  getVersion() {
    console.log(this.version);
  }
  
  static getName() { // Add members to the function object
    console.log(this.name + 'Private Member'); }}let es5 = new Es5('es5')
let es6 = new Es6('es6'.'ES2015')

console.log(es5);
console.log(es6);
// < span style = "box-sizing: border-box; color: RGB (255, 255, 255); line-height: 22px; font-size: 14px! Important; white-space: inherit! Important;"
Copy the code

Talk about your own understanding from the archetypal god diagram

The following offering prototype god diagram 👇

Draw and analyze a wave

From the picture above, we can draw several conclusions:

  • Why is there no instance objectprototype: Only constructors have itprototypeProperty points to the prototype object
  • Object.prototype.__proto__Why null: Prototype objects (that is, objects created by the browser for the constructor) are instances of the base class Object, so the prototype Object is null__proto__Pointing to object.prototype, same thingObject.prototype.__proto__Also, it doesn’t make any sense to point to yourself so I’ll set it to null
  • Function.__proto__Why Point to yourself: Said built-in aboveFunctionthroughFunctionIt’s constructed soFunction.__proto__And it points to itself.

Prototypes related interview questions

an

class Re {
  constructor () {
    this.num = 3;
  }
  rand () {
    return this.num; }}var c1 = new Re();
console.log(c1.num, c1.rand()); 
Re.prototype.num = 4;
Re.prototype.rand = function () {
  return this.num;
}
var c2 = new Re();
console.log(c1.num, c1.rand()); 
console.log(c2.num, c2.rand()); 
Copy the code

Question 2

let name = 'oop'
let Person = function (options){
  this.name = options.name 
}

Person.prototype.name = 'Person'
Person.prototype.getName = function(){
  return this.name 
}
let p = new Person({name: 'Beige'})


Object.getPrototypeOf(p) === p.__proto__;
let proto = Object.getPrototypeOf(p);
let targetObj = Object.assign(proto, {public: 'Front End Self-taught Post'})

console.log(targetObj === p.__proto__);
console.log(p.__proto__.constructor === Person)
console.log(p instanceof Person) 
console.log(p.__proto__ === Person.prototype) 
console.log(p.__proto__.public);
console.log(p.hasOwnProperty('name')) 
console.log(p.hasOwnProperty('getName')) 


let getName = p.getName 
console.log(getName === Person.prototype.getName) 
console.log(getName()) 
console.log(Person.prototype.getName()) 
console. log(p.getName()) 
Copy the code

Question 3

function Foo() {
  getName = function () {console.log(1); };return this;
}

Foo.getName = function() {console.log(2); }; Foo.prototype.getName =function() {console.log(3); };var getName = function() {console.log(4); };function getName() {console.log(5)}
Foo.getName(); 
getName(); 
Foo.getName();
getName(); 


var a = new Foo.getName(); 
var b = new Foo().getName();
var c = new new Foo().getName(); 
console.log(a, b, c);
Copy the code

As usual, I’ll take the last one.

This problem is relatively easy, but the hard part is the last three outputs. The prototype that knows the answer is basically passed.

function Foo() {
  getName = function () {console.log(1); };return this;
}
// Add a private member to the Foo function object
Foo.getName = function() {console.log(2); };// Add public members to the function prototype
Foo.prototype.getName = function() {console.log(3); };// The expression declares a global variable value as a function
var getName = function() {console.log(4); };// At this point in the execution of the reassignment before the declarative function
// Declare a function with a higher priority than above
function getName() {console.log(5)}
Foo.getName(); / / 2
getName(); / / 4
Foo.getName(); / / 2
getName(); / / 4

/ / the difficulty
var a = new Foo.getName(); 
var b = new Foo().getName();
var c = new new Foo().getName(); 
console.log(a, b, c);
Copy the code

For the last three outputs, we need to talk about operator precedence first. Member access must be greater than new without parentheses. We need to give a list of priorities first.

Let’s analyze the first one

var a = new Foo.getName(); 
// => first new foo. getName, with priority member access greater than new without parentheses, so it should be
new (Foo.getName)() // => New (foo.getName ()) as a wholeSo this returns the instance object constructed by foo. getNameCopy the code

The second

var b = new Foo().getName();
// This is different from the above, new Foo() with parentheses is consistent with the priority of member access, which should follow from left to right
(new Foo()).getName()
The new Foo() constructor returns the value returned by the instance calling getName()
Copy the code

The third

This is even sicker. Ahem

var c = new new Foo().getName(); 
// => new (new Foo().getName())
// => new (return instance.getname)()
// => Return new instance. getName() constructs the instance object
Copy the code

After all this, I don’t know if I’m right, so let’s verify

// Let's change the code a little to verify that the above is correct
function Foo() {
  getName = function () {console.log(1); };return this;
}

Foo.getName = function(name) {
    console.log(2);
    this.name = name;
};
Foo.prototype.getName = function() {
    console.log(3);
    retrun 'Front End Self-taught Post'
    // return {info: 'self returned object '} => If the reference type is returned, the second and third parties will get the object
};
var getName = function() {console.log(4); };function getName() {console.log(5)}
Foo.getName(); 
getName(); 
Foo.getName();
getName(); 


var a = new Foo.getName(name); 
// new (foo.getName)() => This is equivalent to using foo.getName as a constructor to new
console.log(a) // {name: 'Bei ge '}
console.log(a.__proto__.constructor === Foo.getName) // true


var b = new Foo().getName();
// (new Foo()).getName() => Return the result of the instance call to.getName()
// Foo does not add a private getName member method to the instance, so it calls the prototype method, so I return a non-reference type in order not to affect the following
console.log(b) // 'Front self learning post'


var c = new new Foo().getName(); 
// => new ((new Foo())getName()) // =
console.log(c.__proto__.constructor === Foo.prototype.getName)
console.log(c) / / {}
Copy the code

closure

There are many closure related articles I don’t want to go into too much detail, here first shameless recommend one of my closure related articles, a thorough understanding of JS closures

I never understood JavaScript closures until someone explained them to me like this…

This

This: the body of the current method execution (who last executed the method, then this is who, so this has nothing to do with where the current method was created or executed

The binding rule and priority of this

In JavaScript, this points to one of four binding rules:

  • 1. Default binding (in non-strict mode, this refers to window, in strict mode, this refers to undefined).
  • 2. Implicit binding (this is implicitly bound to the object that called it when the function is called)
  • 3. Explicit binding (functions are called by call(), apply(), bind(), and this refers to the bound object.)
  • 4. New binding (the function is called by new, and this refers to the object constructed from new.)

The priority of the binding rule is new Binding > Explicit binding > Implicit binding > Default binding

function test() {
  this.a = 'Ge';
}

let obj = {
  a: 'Bei'.fn() {
      console.log(this); }};function scope() {   // Put it inside the function to prevent it from affecting the result
    test() // Default binding
	obj.fn() // Implicit binding
	test.call(obj) // Show bindings
	new test() / / new binding
}

// Show bindings
const Bar = test.bind(obj);

/ / new binding
const bar = new Bar();
console.log(obj.a, The '-', bar.a) // Bei -- Ge

newThe binding changed the one specified in the display bindingthis(obj) Display binding >newThe bindingCopy the code

Several cases of this

  • This in global scope points to window (also in strict mode)
  • If you bind a function to the event behavior of an element, then this in the function refers to the element currently bound
  • “This” in a function depends on whether there is a dot before the function is executed. If there is a dot, this refers to whoever is in front of the dot, and if there is no dot, it refers to window. “This” in a self-executing function always refers to window
  • The this function in the timer points to window
  • This in the constructor refers to the current instance
  • Call, apply, and bind can change the reference to this
  • There is no this in the arrow function, so if you print this, it will print this in the scope in which the arrow function was defined
  • It is also possible for parenthesis expressions to change this, because if there is only one item in parenthesis this will not point to window if there are two or more
  1. This in the global scope defaults to widNow. In strict mode, nothing is undefined
function windowScope() {
    // => this: window
}
Copy the code

2. Bind an event to an element in a method where this is the element of the current operation

document.body.onclick = function () {
    //=>this:body
};
Copy the code

If there is no dot, this is the window. (in strict mode, this is undefined if there is no dot)

let fn = function () {
    console.log(this.name);
};
let obj = {
    name: 'ha ha'.fn: fn
};
fn();//=>this:window
obj.fn();//=>this:obj
Copy the code

Constructor execution. This in a method is typically an instance of the current class

let Fn = function () {
    this.x = 100;//=>this:f
};
let f = new Fn;
Copy the code

5. The arrow function does not have its own this,this is this in the context

let obj = {
    fn: function () {
        // this:obj
        setTimeout(() = > {
            //this:obj
        }, 1000); }}; obj.fn();Copy the code

6. In parenthesis expressions, this is affected

let obj = {
    fn: function () {
        console.log(this); }}; (obj.fn)();// => this:obj; (12, obj.fn)();//=>this:window
Copy the code

Conclusion: If there is only one argument in the parenthesis expression,this does not change. If there are multiple arguments,this refers to window

function foo() {
    console.log( this.a );
}

var a = 2;
var o = { a: 3.foo: foo };
var p = { a: 4};

o.foo(); / / 3
(p.foo = o.foo)(); / / 2
// Conclusion: The special case is that if there is an expression statement in the parenthesis expression, this still points to window
// Another way to say that p.foo = o.foo refers to the memory address, that is, foo refers to the memory address, anonymous function will execute the function referred to by foo,
// this -> window
Copy the code

7. Use call/apply/bind to change this

fn.call(obj); // => this:obj
fn.call(12); // => this:12
fn.call(); // => this: if the first argument of call/apply/bind is not written in strict mode or null or undefined, this is window. If the first argument of call/apply/bind is not written in strict mode, this is window
Copy the code
  1. This in the timer specifies window
setInterval(function() {
  console.log(this);
}, 1000);
Copy the code

It can also be understood as an anonymous function in which the execution main defaults to window

Interview questions related to this

an

var num = 10
const obj = {num: 20}
obj.fn = (function (num) {
  this.num = num * 3
  num++
  return function (n) {
    this.num += n
    num++
    console.log(num)
  }
})(obj.num)
var fn = obj.fn
fn(5)
obj.fn(10)
console.log(num, obj.num)
Copy the code

Question 2

var a = {
    name:"zhang".sayName:function(){
        console.log("this.name="+this.name); }};var name = "ling";
function sayName(){
    var sss = a.sayName;
    sss(); //this.name = ?
    a.sayName(); //this.name = ?
    (a.sayName)(); //this.name = ?
    (b = a.sayName)();//this.name = ?
}
sayName();
Copy the code

Question 3

var obj = {
  a: 1.foo: function (b) {
    b = b || this.a
    return function (c) {
      console.log(this.a + b + c)
    }
  }
}
var a = 2
var obj2 = { a: 3 }

obj.foo(a).call(obj2, 1)
obj.foo.call(obj2)(1)
Copy the code

Is four

var name = 'window'
function Person (name) {
  this.name = name
  this.obj = {
    name: 'obj'.foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () = > {
        console.log(this.name)
      }
    }
  }
}
var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)

person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)
Copy the code

After the language

Articles in general or to present by way of summary, for this series of articles I am front-end system 】 【 holding the very serious, very want to write a good mentality, but after all, I still front small white & writing, if the article is that piece of writing is not very good or problem welcome to point out that I will be in the back of the paper. I hope I can grow with you as I progress. Those who like my article can also pay attention to it

I’ll be grateful to the first people to pay attention. At this time, you and I, young, packed lightly; And then, rich you and I, full of it.

series

【 Front-end system 】 Talk about understanding EventLoop from an interview question (updated analysis of four advanced questions)

[Front end system] Build a great oaks from the foundation

[Front-end System] The application scenario of re in development is not just rule verification

Refer to the article

Implementation principle (CONSTRUCTOR)

Data types in JavaScript and their detection

JavaScript data type conversions

JavaScript You Don’t Know