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
- .
- 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 a
prototype
Prototype object, which provides the member properties and methods to be invoked by the instance object - each
prototype
They bring one with themconstructor
Refers back to the constructor to which the stereotype object belongsconstructor
Lost) - The biggest Boss of the built-in classes is not the base class Object. Object is also constructed from the built-in Function, so
Object.__proto __
= = =Function.prototype
- Built-in functions are also built by themselves, so
Function.__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 no
Symbol.toStringTag
The type of the built-in property is calledtoString()
Is equivalent toString(obj)
The call is thus converted to the corresponding string - There are
Symbol.toStringTag
The 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
- When using
= =
,&&
,||
And other logical operators - 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:
- 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.
- 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:
- Inside a function
- Inside a code block wrapped in a pair of curly braces
Let declaration and var declaration
- There is no variable promotion
- Repeated declarations are not allowed
- A temporal dead zone, or TDZ, is formed
- 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 it
ReferenceError
The exception. - In the non-strict mode,
LHR
Slightly 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 type
TypeError
abnormal
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 a
prototype
Prototype object, which provides the member properties and methods to be invoked by the instance object - each
prototype
They bring one with themconstructor
(constructor property) refers back to the constructor to which the stereotype object belongsconstructor
Lost) - The biggest Boss of the built-in classes is not the base class Object. Object is also constructed from the built-in Function, so
Object.__proto __
= = =Function.prototype
- Built-in functions are also built by themselves, so
Function.__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 object
prototype
: Only constructors have itprototype
Property 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 nullFunction.__proto__
Why Point to yourself: Said built-in aboveFunction
throughFunction
It’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
- 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
- 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