catalogue
Chapter 3 function scope and block scope
The second part is} this and object model
Chapter 2} this comprehensive analysis
Chapter 4} mixed object "class"
Conclusion: on July 2, 2021, it is finally finished. I originally wanted to spend a week reading this volume, but I didn't expect to spend more than ten days before and after. Fortunately, I gained a lot. The contents of the book really gave me a deeper understanding of the language JavaScript.
This knowledge combing is suitable for those who have read the first volume of JavaScript I you don't know, but still feel confused. I have also read the knowledge combing of this book written by many bloggers, mostly a simple stacking and explanation of the contents of the book, which makes my JavaScript Xiaobai always confused when understanding the concepts in the book, which may be the reason for my beginner, When I see many concepts in the book, it's like learning a mathematical theorem and knowing the meaning of the theorem, but I don't know how to use the mathematical theorem and can't know the meaning expressed in the book. Therefore, in the process of mathematics learning, I often want to know the understanding of others. Therefore, I decided to write a "JavaScript you don't know" to sort out the knowledge and carefully guess the author's meaning, so as to understand the concepts in the book more popularly and try to understand what each chapter of the book wants to express. The book was read in a hurry. If there is any error, please correct it in the comment area. I will carefully consult the information and modify it.
Soon, I will read the remaining two books, and I will write my understanding in my blog. I hope visitors can pay attention to me and give me some corrections.
Part I: scope and closure
Chapter 1. What is the scope
I think the difficulties of this chapter are:
Let's answer the title of this chapter first:
What is the scope?
Scope is the accessible scope of variables and functions, which controls the visibility and life cycle of variables and functions. Using the function understanding in mathematics, it is said that the scope is the value range.
function foo(a) { console.log(a); //2 }; foo(2);
The above code is a dialogue between the engine and the scope. Note here that LHS and RHS perform the assignment operation (foo() function can also be understood as assignment operation, which is equivalent to assigning a function to Foo and then executing foo), that is, whether there is a container to be stored on the left of the assignment operation and whether there is a value of our operation on the right of the assignment operation
LHS query:
When foo() is executed, the query for foo (which is a function)
When foo(2) is executed, query a in foo (a is a parameter)
RHS query:
Assignment to a when foo(2) is executed
Execute console Reference to the log() method when log()
Execute console Log (a), the operation of assigning value to a
From the above, we can understand why there are two kinds of errors ReferenceError and TypeError in RHS query
The former is because the assignment operation cannot be found, and the latter is because the assignment operation is found but unreasonable operation is carried out, such as this
let foo = null; foo(2);
Therefore, I think the TypeError error can be understood as the RHS query succeeded, but the illegal operation was carried out. Of course, as mentioned in these books, I sort out one side of logic here.
This is the code of the quiz. After reading the explanation in the book, I understand the above content. This quiz is a piece of cake
function foo (a){ var b = a; return a + b; }; var c = foo( 2 );
LHS query: the container on the left of the assignment operation. RHS query: the value on the right of assignment operation.
LHS: c =, a=2 (the implicit operation of foo(2) is to find whether there is a parameter, because even if the function has formal parameters, it can not write arguments), b=
In fact, I'm confused about why = 2 on the right of a=2 assignment operation is not defined as RHS query; Let me guess here, because = 2 doesn't need to be checked, because 2 itself is a value, the essence of the query is to find, and the variable is the container for storing data, so it needs to be found.
RHS: foo this function, = a, return a and B of a+b(return is equivalent to an assignment operation, and a+b is the value of the assignment operation),
Important knowledge of this chapter:
1.JavaScript is a compiled language, and its compilation takes place in a few subtle steps before code execution. That is, compilation and execution are almost synchronized. Therefore, JavaScript will try every means to optimize performance.
2. Engine, compiler, scope. Simply understand the function.
3.LHS and RHS queries
4. Nested scope: that is, in the nested scope, the engine's LHS query will implement bubble rule search
5. Unsuccessful LHS query will automatically create a global variable (non strict mode). ReferenceError exception will be thrown in strict mode, and unsuccessful RHS query will throw ReferenceError exception
Chapter 2} lexical scope
I think the difficulties of this chapter are as follows:
First answer the title of this chapter:
Lexical scope: that is, the language provides a set of writing rules for code writing. The scope formed according to this rule is the lexical scope. In other words, it is the scope of the code block. For example, when writing a function, the internal data of the function is generally inaccessible externally. The scope of the function is part of the lexical scope.
In this figure, the three scope bubbles are lexical scope, that is, the scope of the code block formed according to the code writing rules.
Scope bubbles are strictly included, that is, only bubble inclusion and no bubble crossover will occur
Explain the dynamic scope mentioned in Appendix A of the book
1.JavaScript has only lexical scope! (but this mechanism is very similar to dynamic scope)
function foo() { console.log(this.a); //2 console.log(a); //2 } function bar() { var a = 3; foo(); } var a = 2; bar();
Here, if JavaScript is a dynamic scope, the output will be 3, because the dynamic scope will find the call stack.
2. Lexical scope is determined when writing code or definition, while dynamic scope is determined at run time.
Detailed explanation of eval cheating morphology
//eval deceptive morphology function foo(str, a) { eval(str); //deception console.log(a, b); } var b = 2; foo('var b = 3;', 1)
Basically, there is nothing to say, that is, it will directly convert the incoming string into js code, that is, eval(str) at this time is completely equivalent to var b = 3;
Let's talk about the wonderful use of this function. Eval will execute strings. When our data is an executable string, it's cool to use eval.
A detailed explanation of the word "with" deception
Let's first understand that with will be associated with an object, and all variables in with will be mapped to the same name attribute of the associated object. If a variable in with is not mapped to an attribute with the same name, the LHS query will bubble up
function foo(obj) { with(obj) { //The scope bubble is created var b = 3; //It will actually be defined in the foo function // let c = 6;// Will be limited to with a = 2; //This a will directly find the attribute a of obj console.log(a); //2 console.log(obj.a); //undefined console.log(b); //3 console.log(obj.b); //undefined }; // console.log(a) //ReferenceError console.log(b); //3 // console.log(c); }; var o1 = { a: 3 } var o2 = { b: 3 }; foo(o1); console.log(o1.a); //2 // // console.log(a); //RHS query, ReferenceError // foo(o2); // console.log(o2.a); //undefined // console.log(o2.b); //undefined // console.log(a); //2,window.a
1. The first half of this sentence means that with will create a scope bubble; The second half of the sentence means that the properties of the incoming object will be associated with the identifier with the same name in the with scope bubble. For example, in line 6, a can be directly output as 2; At this time, in line 11 and line 23, the value of output a is ReferenceError.
That is to say, the rule of assignment operation in with is: assignment operation gives priority to the corresponding attribute of the object passed into with. When there is no corresponding attribute, the assignment operation will bubble LHS to query the corresponding variable container.
Therefore, when we write c=2 in with, if the incoming object has no c attribute, with will bubble the query; If there is a c attribute, with will stop searching and assign a value to this attribute.
2. This paragraph: in line 3 of the code, after var is used to declare variable b, variable b can be accessed outside the scope bubble of with, that is, inside the bubble of foo function, that is, the variable declared by var here belongs to the scope bubble of with.
When you understand here. The trick of with is that it creates a scope bubble for the incoming object, that is, the lexical scope.
That is, a=2 in this bubble cannot be accessed externally. If this object does not have this attribute, a=2 can modify the variables of the bubble in the external scope.
Let's talk about the wonderful use of with. You can dynamically modify the data of the object by embedding Eval into with and passing in the code to modify the attributes of the associated with object to eval. But don't do this, it will lead to extreme performance degradation.
It is hoped that readers will release the above code comments to run and view. Some details need to be experienced by running the code.
Important knowledge of this chapter:
1. Lexical scope refers to the scope defined in the lexical stage, that is, the scope is determined by the position of the function declaration when writing code.
2. The scope will stop when the first matching identifier is found, so there will be a "masking effect".
3. Deceptive morphology: eval and with (will create scope bubbles)
4. The JavaScript engine will perform several performance optimizations at the compilation stage
5. Cheating on lexical will make the JavaScript engine unable to optimize the scope search at compile time.
6. Scope lookup always starts from the innermost scope where the runtime is located.
Chapter 3 function scope and block scope
I think the difficulties of this chapter are as follows:
1. A small example of an executive function
undefined = true; //Attempt to overwrite undeined console.log(undefined); //undefined, it can be seen that the modification is unsuccessful (function IIFE(undefined) { console.log(undefined) //undefined, var a; if (a === undefined) { console.log('Undefined is safe here!') } })(); //No parameters passed in
In this example, I want to override the default value, but it is actually found that undefined will not be overridden
2. The Iife function inverts the execution order of the code
var a = 2; (function IIFE(def) { def(window); })(function def(global) { var a = 3; //There will be a masking effect console.log(a); //3 console.log(global.a); //2 });
This code is actually well understood, that is, def is passed to IIFE as a parameter and executed inside IIFE. The difference between the two outputs is actually caused by masking effect
Important knowledge of this chapter:
1. No matter where the identifier declaration appears in the scope, the scalar or function represented by this identifier will be attached to the bubble of the scope. (the principle here should be variable promotion and function priority)
2. There is a scope bubble inside each function. Based on this, we can wrap the code in the function scope bubble. This scope based hiding method is the minimum privilege principle.
function foo() { function bar(a) { i = 3; //Modify i in the scope of the for loop for (var i = 0; i < 10; i++) { bar(i * 2); //This creates an infinite loop } } }
Here is the variable conflict. We should make the i inside the bar function a local variable.
3. In order to avoid variable conflict, many libraries mostly define a unique object and make each variable and method become the attribute of the variable.
4. Named and anonymous function expressions
//Note that because it is an expression, you need to use a semicolon at the end //Anonymous function expression (function() { var a = 3; console.log(a); }); //Named function expression (function foo() { var a = 3; console.log(a); });
5. Execute function expression
//Form I (function foo(a) { console.log(a); }(3)); //Form II (function foo(a) { console.log(a); })(3);
6. On the surface, JavaScript language has no function related to block level scope, In fact, with (only the attribute identifier with the same name of the associated object has block level, and the language expression ability is limited. Please go to the above with explanation and check. This expression is called block level in the book, which I think is not rigorous enough, because the attribute identifier with non same name declared in with is actually defined in the scope of with) Each catch of try/catch creates a block level scope. The performance of try/catch is poor
7.let keyword can bind variables to any scope, that is, the variables that let can declare implicitly hijack the block scope.
Chapter 4 - lifting
I think the difficulties of this chapter are as follows:
1. Function promotion mechanism of intra block scope. JavaScript may change this mechanism in the future, so try not to declare functions within blocks.
// foo(); //TypeError: foo is not a function var a = true; console.log(foo); //undefined if (a) { //It's actually promoted into the if block function foo() { console.log('a'); } } else { function foo() { console.log('b'); } } console.log(foo);
Important knowledge points of this chapter:
1. Before compiling, the JavaScript compiler will first find all declarations and associate them with the appropriate scope. Therefore, all declarations, including variables and functions, are processed first before any code is executed.
//It says this foo(); function foo() { console.log(a); //undefined var a = 2; } //The actual operation is this function foo() { var a; console.log(a); a = 2; } foo();
2. Both function declaration and variable declaration will be promoted, that is, when the function name and variable name have the same name, function promotion will cause variables with the same name to be ignored. That is, function promotion has higher priority.
Chapter 5: scope closure
At this time, I really understand what closures are, and then I realize the enlightenment - closures in JavaScript are everywhere!!! The meaning of this sentence.
I think the difficulties of this chapter are as follows:
function foo() { var a = 2; function bar() { console.log(a) } return bar; } foo()(); //2 var baz = foo(); //2 baz();
Closure is that the JavaScript engine prevents the garbage collection of the function being referenced, that is, the bar in the code is continuously referenced, that is, the scope bubble of foo is continuously referenced.
In this example, the foo function has been executed, and the foo function should be recycled, but the JavaScript engine prevents recycling.
We commonly understand closure, that is, the function is enclosed in the scope bubble, but the function call is outside the scope bubble.
The above is what I try to explain and understand closures in the book, but I always think they are too academic. Therefore, my understanding:
0. I understand function execution as that the function name is the switch for function execution, and the function name () will turn on this switch to "trigger" the function.
1. The execution of a function and the value of a variable are both triggers; That is, the function name () directly refers to the variable name, which is the "trigger" of functions and variables.
2. However, functions are different from variables. The execution of functions is the function name (). The function name is the variable (I call the variable container), which is only the container for storing functions (in fact, it stores the pointer of the function, that is, the shortcut of the function). Please see the following code
(function() { function foo() { var a = 2; function bar() { console.log(a) } return bar; } console.log(foo); //Function foo console.log(window.foo); //undefined foo = 12; console.log(foo) //12 console.log(window.foo); //undefined })();
It shows that foo can be assigned and is not the attribute of window object, so it can be concluded that foo is a variable (container). Of course, those who have studied C language or other languages know this. I just want to be more sure.
3. Therefore, I say that the "trigger" of a function requires two conditions: the function name and (). () will automatically find the function in the variable and execute it
//Deep analysis of closures function foo() { var a = 2; function bar() { console.log(a) } return bar; } foo()(); //2 var baz = foo(); //2 baz();
In this code, bar is just a variable to store the function, and the bar variable will be returned after the function foo is executed.
4. Now pull back, because JavaScript is a lexical scope, the scope of function execution is within the scope defined by the function.
5. That is, the function foo returns the "trigger" switch of the bar function to the outside. The function bar in foo is executed by using () outside, and then the operation of normal lexical scope is carried out.
function setupBot(name, selector) { $(selector).click(function activator() { console.log('Activating' + name); }) } setupBot('Closure Bot 1', '#bot_1')
It is understood that the reason why the above code is a closure is that the execution of the internal callback function is controlled by the external setupBot.
6. Explain loops and closures
for (var i = 1; i <= 5; i++) { // var j = i; setTimeout(function timer() { console.log(j) }, i * 1000); }
There are only two levels of scope, the global scope (in the for loop) and the scope in the callback function. According to the lexical scope rules, the callback function scope will share the global scope, so 6 will be output in the end
for (var i = 1; i <= 5; i++) { (() => { var j = i; setTimeout(function timer() { console.log(j) }, i * 1000); })(); }
Here, the immediate execution function (ES6 syntax) is used. Therefore, there are three levels of scope, namely, the global scope (within for), the scope of the immediate execution function and the scope of the callback function. Explain in detail: each iteration will have 5 immediate execution function scope siblings and 5 callback function scope siblings, which are inclusive relationships respectively
Therefore, the j variables defined in each iteration belong to the scope of the five vertical execution functions, that is, if there is no J for data storage, the callback function will bubble up from the lexical scope rules to find i, so it still outputs five 6
for (var i = 1; i <= 5; i++) { ((j) => { setTimeout(function timer() { console.log(j) }, j * 1000); })(i); }
The improved code actually shows that the parameters will be bound every time the function is executed. Much like using let
for (let i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i) }, i * 1000); }
7. Modules are used with closures. A module is a closed function that returns an object (the essence of the function is also an object). Therefore, a closure is formed inside the module. Therefore, the returned object can continuously reference and operate inside the module.
var foo = (function CoolModule(id) { function change() { //Modify public API publicAPI.identify = identify2; }; function identify1() { console.log(id); }; function identify2() { console.log(id.toUpperCase()); }; var publicAPI = { change: change, identify: identify1 }; return publicAPI; //Return module })('foo module'); //At this time, foo continues to refer to its module //Therefore, the following methods execute the functions inside the module foo.identify(); foo.change(); foo.identify();
Once you understand closures, understanding modules becomes easy. What the above code doesn't say is that the module generates a closure and then performs some operations on the continuous reference inside the module.
8. A code case of modern module mechanism in the book
//Modern modular mechanism var MyModules = (function Manager() { var modules = {}; function define(name, deps, impl) { for (var i = 0; i < deps.length; i++) { deps[i] = modules[deps[i]]; }; modules[name] = impl.apply(impl, deps); }; function get(name) { return modules[name]; }; return { define: define, get: get, } })(); MyModules.define('bar', [], function() { function heool(who) { return 'Let me introduce: ' + who; }; return { //Object returned heool: heool }; }); MyModules.define('foo', ['bar'], function() { var hungry = 'hippo'; function awesome() { console.log(bar.hello(hungry).toUpperCase()); }; return { //Object returned awesome: awesome }; }); var bar = MyModules.get('bar'); var foo = MyModules.get('foo'); console.log(bar.hello('hippo')); //Let me introduce:hippo foo.awesome();
In fact, it's very understandable, but it's a little around:
Let's first talk about the defined function: a parameter name will add an attribute to modules. The second parameter deps is to traverse the attributes of modules, and pass the traversal into the third parameter impl (callback function). The third parameter will also become the attributes of modules.
Let's talk about the get function: simply get the properties of modules
Let's talk about the first execution of momodules An empty array is passed in during define(). Obviously, modules cannot get the attribute, then the following impl The deps passed in by apply () is empty; In other words, the second parameter of apply is empty, and the second parameter of apply is passed to the original function, that is, when it is executed for the first time, no value is passed in the callback function. The same goes for the second time.
Of course, you still need to understand the code carefully.
9. Some understandings on the morphology of "this" in Appendix C
In setTimeout, this points to the window. The answer given on the official website is that the code called by setTimeout() runs in an execution environment completely separated from the function
In my opinion, obj Cool refers to the cool function, and the js engine is executing obj Cool() is a call decorated with obj; Therefore, foo also points to the cool function, so foo is a direct reference to the cool function, and foo() is an unmodified call when executed;
Therefore, I think the setTimeout parameter is equivalent to foo, which is an unmodified call to the cool function.
//Appendix C this morphology var obj = { id: 'awesome', cool: function coolFn() { console.log(this.id); // console.log(this); } }; var id = 'not awesome'; obj.cool(); //awesome //The binding of this depends on the calling location, so here is a direct reference to the coolFn function, that is, a direct call var foo = obj.cool; foo(); //not awesome // It can be seen that this is also a direct reference setTimeout(obj.cool, 100); //not awesome // console.log(window.id)
Knowledge points of this chapter:
1. Basically, they are difficult points. We should not remember much, but we need to understand them.
2. Necessary conditions for module mode:
① it must be an external chalk function, which must be called at least once (each call will create a new module instance).
② the closed function must return at least one internal function, so that the internal function can form a closure in the private scope and access or modify the private state.
3. The contents of the module file are treated as contained in the scope closure. Similar to function closure module
The second part is} this and object model
Chapter 1} about this
This chapter is about some misunderstandings about this
I think the difficulties of this chapter are as follows:
nothing
Knowledge points of this chapter in the book:
1. Why use this? This provides a more concise and reusable API design. We can implicitly "pass" a reference to an object by changing the point of this.
2.this does not point to itself.
// About this function foo(num) { console.log('foo: ' + num); //Record the number of times foo was called this.count++; }; foo.count = 0; var i = null; for (i = 0; i < 10; i++) { if (i > 5) { foo(i); } } console.log(foo.count); //0
3. Under no circumstances does this point to the lexical scope of the function, which exists inside the JavaScript engine.
4. The classic this error, it tries to cross the border
var obj = {} function foo() { var a = 2; this.bar(); } function bar() { // It seems that LHS will automatically create attributes when querying objects, which should be changed. console.log(this.a); //undefined console.log(obj.a); //undefined } // this.foo(); //undefined //I think the functions defined in the global scope will also become the properties of the global object foo();
5. The binding of this has nothing to do with the declaration position of the function, only depends on the calling method of the function That is, this is actually a binding that occurs when a function is called. What it points to depends entirely on where the function is called.
Chapter 2} this comprehensive analysis
This chapter is about the rules of this pointing and how to modify this pointing,
I think the difficulties of this chapter are as follows:
1. The last part of the MDN bind implementation in the book is not understood
if (!Function.prototype.bind) { //Check whether the prototype of the Function has a bind method Function.prototype.bind = function(OThis) { //Define bind method if (typeof this !== 'function') { //Check whether the caller is a function //Closest to ECMAScript 5 //Internal iscalacle function throw new TypeError( //If it is not a function, an error is thrown, and the function will stop the execution of subsequent code 'Function.prototype.bind - what is trying' + 'to be bound is not callable' ); }; //Split the parameters of the bind function. slice can split the pseudo array arguments. 1 means to split arguments from the second index var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, //bind caller fNOP = function() {}, // fBound = function() { return fTobind.apply( ( this instanceof fNOP //Is the prototype chain of fNOP on this prototype chain && OThis ? this : OThis //Does this exist ), aArgs.concat( Array.prototype.slice.call(arguments) ) ); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; } }
2. The soft binding source code in the book, I haven't fully understood it yet
//Soft binding if (!Function.prototype.softBind) { Function.prototype.softBind = function(obj) { var fn = this; //Capture the desired curried parameter var curried = [].slice.call(arguments, 1); var bound = function() { return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply(curried, arguments) ); }; bound.prototype = Object.create(fn.prototype); return bound; } } function foo() { console.log('name: ' + this.name); } var obj = { name: 'obj' }, obj2 = { name: 'obj2' }, obj3 = { name: 'obj3' }; var fooOBJ = foo.softBind(obj); //Bound to obj fooOBJ(); //name:obj obj2.foo = foo.softBind(obj);//Bind to obj obj2.foo(); //name:obj2, which seems to be similar to implicit binding fooOBJ.call(obj3); //name:obj3 setTimeout(obj2.foo, 100); //name:obj
3. The arrow function captures this that calls the parent function and cannot be modified. The arrow function can ensure that this of the function is bound to the specified object like bind. In essence, the lexical scope is used to replace this mechanism, which is similar to var self = this; This code
//Arrow function function foo() { //Returns an arrow function return (a) => { //this inherits from foo() console.log(this.a) } } var obj1 = { a: 2 }; var obj2 = { a: 3 }; var bar = foo.call(obj1); bar.call(obj2); //2
Important knowledge points of this chapter:
1. The call location is where the function is called in the code (not the declared location). The call stack needs to be analyzed.
2. When the function runs in "non strict mode", the function will execute the default binding; However, calling a function in strict mode does not affect the default binding of the function. Distinguish between running and calling. Default binding means that global functions are bound to global objects by default.
3. When a function references a context object, the implicit binding rule will bind this in the function call to the context object. In the attribute reference chain of an object, only the upper or last layer plays a role in the call location
function foo() { console.log(this.a) } var obj2 = { a: 42, foo: foo } var obj1 = { a: 2, obj2: obj2 } obj1.obj2.foo(); //42
3. The essence of this loss caused by implicit binding is the direct reference to a function (function call without any modification)
4. The function of the callback function may modify this. In popular JavaScript libraries, the event processor often forcibly binds this of the callback function to the DOM element that triggers the event. I use jQuery to find that it is not like the second half of the sentence
window.addEventListener('load', function() { console.log(this); //window document.querySelector('p').addEventListener('click', function(e) { function foo() { console.log(this); //window } foo(); //Here is the DOM element bound to the trigger console.log(this); //p console.log(e.target); //p }) }) $(function() { console.log(this); //#Document, which seems to be the document object of jQuery $('p').on('click', function(e) { function foo() { console.log(this); //window } foo(); console.log(this); //p console.log(e.target); //p }) })
5. Hard bind call and apply2. Hard binding is to isolate call and apply statements with new functions.
//Hard binding, function foo() { console.log(this.a) } var obj = { a: 2, foo: foo }; var a = 3; var bar = function() { // foo(); return foo.call(obj); //2 }; bar(); setTimeout(bar, 100); //2 //It is impossible for a hard bound bar to modify its this. //Like nonsense, bar is now a new function. These operations are all operations on the new function. How can you modify this of foo bar.call(window); //2
6. The new operator calls ordinary functions, that is, all functions can be called with new. There is no so-called "constructor", only the "construction call" of the function and the operation of new:
1. Create (or construct) a completely new object
2. The new object will be connected by [[Prototype]]
3. The new object will be bound to this of the function call
4. If the function does not return another object, the function call of the new expression will automatically return the new object
function foo(a) { this.a = a; } var bar = new foo(2); //A new object is returned, so you can use bar A access the properties of the new object console.log(bar.a); //2
7. Judge this:
Is the function called in new (new binding)? If so, this binds to the newly created object.
var bar = new foo();
② whether the function is called through call, apply (display binding) or hard binding? If so, this binds to the specified object.
var bar = foo.call(obj2)
Is the function called (implicit binding) in a context object? If so, this binds to the context object.
var bar =obj1.foo();
④ if none, use the default binding. If in strict mode, bind to undefined, otherwise bind to global objects.
var bar = foo();
8. Coriolism: pass all parameters except the first parameter (the first parameter is used to bind this) to the lower level function (this technology is called "partial application", which is a kind of "coriolism")
9. The easiest way to create an empty object in JavaScript is object create(null). Doing so will not create an object The prototype delegate is more empty than {}.
10. For the default binding, it is not whether the call location is in strict mode that determines the binding object of this, but whether the function body is in strict mode.
11. Hard binding will greatly reduce the flexibility of functions. After using hard binding, you cannot use implicit binding or display binding to modify this.
Chapter 3: object
There is a common saying that "everything in JavaScript is an object", which is obviously wrong.
This chapter covers some operations of objects: creation, configuration and sealing
Difficulties in this chapter:
1.Symbol.iterator : a default iterator is defined for each object. The iterator can be used by a for of loop. For of will find the built-in @ @ iterator object and call the next() method to traverse the data
//Custom object iterator var myObject = { a: 2, b: 3 }; Object.defineProperty(myObject, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function() { var o = this; var idx = 0; var ks = Object.keys(o); return { next: function() { return { value: o[ks[idx++]], done: (idx > ks.length) }; } }; } }) //Manually traverse myObject var it = myObject[Symbol.iterator](); console.log(it.next()); //{value:2,done:false} console.log(it.next()); //{value:3,done:false} console.log(it.next()); //{value:undefined,done:true} //For of traversal for (var v of myObject) { console.log(v) }; //2,3
Code means defining a symbol Iterator attribute. The value of this attribute is a function. There are various operations inside the function. It's a little hard to express in words. You can try to run the code and experience it yourself
Knowledge points of this chapter:
1. There are six main types of javascript: string, number, boolean, null, undefined, and object.
typeof null; The reason why object is returned is that if the first three binary bits in JavaScript are all 0, it will be determined as object type, while null binary means all 0, so it will naturally be determined as object
2. Built in objects: String, Number, Boolean, Object, Function, Array, Date, RegExp, Error.
3.JavaScript will automatically convert strings, numbers, etc. into built-in objects when using methods, such as' I am string '. In fact, it will perform new String('I am string')
4. In an object, the property name is always a string. If you use a value other than string (literal, the storage of string is fixed) as the property name, it will be converted to a string first;
5. Array is also an object, so you can add a property to the array, but if you try to add a numeric like property to the array, this property will become a numeric subscript when you access the key
var myArray = ['foo', 'turnip', 43]; myArray['3'] = 'kkk'; myArray.length; //4 myArray[3]; //43
6.Object.defineProperty official description: Object.defineProperty . This method can configure objects
'use strict' //If you modify the read-only attribute, an error will be reported var myObject = {}; Object.defineProperty(myObject, 'a', { value: 2, writeable: false, //Not writable, read-only configurable: true, //Configurable enumerable: true //enumerable }); myObject.a = 3; console.log(myObject.a); //2
7. Combining writeable:false and configurable:false creates a real constant attribute (which cannot be modified, redefined, or deleted)
var myObject = {}; Object.defineProperty(myObject, 'FAVORITE_NUMBER', { value: 42, writable: false, configurable: false })
8. Object. Official interpretation of preventextensions: Object.preventExtensions . This method can make an object non extensible, that is, it can never add new attributes.
var myObject = { a: 2 }; Object.preventExtensions(myObject); myObject.b = 3; console.log(myObject.b); //undefined
9. Object. Seal official interpretation: Object.seal . This method encloses an object, prevents the addition of new properties, and marks all existing properties as non configurable and non removable. The value of the current property can be changed as long as it is writable.
10. Object. Freeze official explanation: Object.freeze() . This method can be applied to objects at a high level of immutability.
11.getter and setter are both hidden functions. The former is called when getting properties, and the latter is called when setting properties.
var myObject = { //Define a getter for a get a() { return this._a_; }, set a(val) { this._a_ = val * 2; } } myObject.a = 2; console.log(myObject.a);//4 console.log(myObject._a_); //4. An attribute is created
Enumerable is equivalent to being able to appear in the traversal of object properties. For in is silent, but the for loop can.
propertyIsEnumerable() It checks whether the given property name exists directly in the object (not on the prototype chain) and meets enumerable: true
Object.keys() An array containing all enumerable properties will be returned, Object,getOwnpropertyNames() Will return an array containing all attributes, whether they are enumerable or not;
Object.prototype.hasOwnProperty The difference between and in is whether to find the [[Prototype]] chain
object.keys() and object Getownpropertynames() will only find the properties directly contained in the object
var myObject = {}; Object.defineProperty(myObject, 'a', //Let a enumerate like a normal attribute { enumerable: true, value: 2 }); Object.defineProperty(myObject, 'b', //Let a enumerate like a normal attribute { enumerable: false, value: 2 }); console.log(myObject.b); //3 console.log(('b' in myObject)); //true console.log(myObject.hasOwnProperty('b')); //true for (var key in myObject) { console.log(key, myObject[key]); }; //'a' 2 console.log(myObject.propertyIsEnumerable('a')); //true console.log(myObject.propertyIsEnumerable('b')); //false console.log(Object.keys(myObject)); //['a'] console.log(Object.getOwnPropertyNames(myObject)); //['a','b']
Chapter 4} mixed object "class"
As long as you understand the point and object of this, the content of this chapter is easy to understand. It is just some concepts.
Difficulties in this chapter:
1. Polymorphism means that any method can refer to the methods at the upper level of the inheritance hierarchy, and inheritance enables the methods to be mapped in multiple classes.
2. Displaying polymorphism is to introduce the method of the parent class into the subclass, but at this time, the method shows that the bound object is the subclass
Knowledge points of this chapter:
1. Class / inheritance describes the address structure of a code -- a modeling method for the problem domain in the real world in software. Object-oriented programming emphasizes that data and the behavior of operating data are essentially interrelated.
2. There are no classes in JavaScript. JavaScript only provides some similar class syntax. Therefore, the class of JavaScript is a design pattern (the class itself is a design pattern). Such as class in ES6
3. A class instance is constructed by a special class method. This method name is usually the same name as the class and is called a constructor.
4. Class inheritance is actually replication
Chapter 5: Prototype
The essence of prototype is the relationship between objects.
Difficulties in this chapter:
1. The essence of the prototype is an association relationship. The prototype chain is an association tree, that is, the JavaScript engine will find the prototype chain
var anotherObject = { a: 2 }; //Create an object associated with another object var myObject = Object.create(anotherObject); //Note that MyObject A does not exist, but the JavaScript engine looks for this attribute on the prototype chain console.log(myObject.a); //2
2. Implicit shielding
var anotherObject = { a: 2 }; var myObject = Object.create(anotherObject); console.log(anotherObject.a); //2 console.log(myObject.a); //2 console.log(anotherObject.hasOwnProperty('a')); //true console.log(myObject.hasOwnProperty('a')); //false console.log(anotherObject); console.log(myObject); //It belongs to the next level of otherobject myObject.a++; //myObject.a= myObject.a + 1 console.log(anotherObject.a); //2 console.log(myObject.a); //3 console.log(myObject.hasOwnProperty('a')); //true
3. The association of new, the operation of new, is to create a new object associated with other objects. In fact, we don't copy "classes", we just associate them
function Foo() {} var a = new Foo(); //After the new operation, it will be associated with foo On a prototype object console.log(Object.getPrototypeOf(a) === Foo.prototype); //true
Knowledge points of this chapter:
1. When using for in to traverse an object, the principle is similar to finding the [[Prototype]] chain. Any attribute that can be accessed through the Prototype chain will be enumerated. When the in operator is used to check whether the attribute exists in the object, the whole Prototype chain of the object will also be found.
2. All ordinary [[Prototype]] chains will eventually point to the built-in object Prototype.
3. The function is not a constructor, but when and only when new is used, the function call becomes a "constructor call".
4.Object.create() A new object will be created and associated to the object we specified
//Compatible object create if (!Object.create) { Object.create = function(o) { function F() {}; //Declare empty function F.prototype = o; return new F(); } }
5. Internal delegation. Avoid that the current object does not have this property, but it can be called magically. It also makes the API design clearer
var anotherObject = { cool: function() { console.log('cool!'); } } var myObject = Object.create(anotherObject); myObject.doCool = function() { this.cool(); //Internal delegation } myObject.doCool();
Chapter 6} entrustment
There is nothing to say in this chapter, that is, to explain the design pattern of delegation. After understanding the mechanism, object and prototype of this, there are no difficulties in the code in the book.
Knowledge review:
1. If the required attribute or method reference is not found on the first object, the JavaScript engine will continue to find the object associated with [[Prototype]].
2. The essence of the prototype chain mechanism of JavaScript is the relationship between objects.
Difficulties in this chapter:
1. Comparison between class theory and entrustment Theory:
//Class theory (pseudo code) class Task { id; //Function Task() Task(ID) { id = ID; } outputTask() { output(id); } }; class XYZ inherits Task { label; //Constructor XYZ XYZ(ID, Label) { super(ID); label = Label; } outputTask() { super(); output(label); } }; class ABC inherits Task { //... }; //Entrustment theory Task = { setID: function(ID) { this.id = ID; }, output: function() { console.log(this.id) } }; // Delegate XYZ to Task XYZ = Object.create(Task); XYZ.prepareTask = function(ID,Label){ this.setID(ID); this.label = Label; } XYZ.outputTaskDetails = function(){ this.outputID(); console.log(this.label); }; //ABC = Object.create(Task); //ABC ... = ...
It can be seen from class theory: when instantiating a subclass, the instance of the subclass will copy the behavior of the parent and subclass. You can refer to the principles of java classes
Delegation Theory: "the subclass" (object) is delegated to the "parent class" through [[Prototype]]. When calling a method not in the subclass, it will find the associated object through the delegation relationship. Because the call location triggers the implicit binding rule of this, the binding of this is still a "subclass" ", which is exactly what we want. Therefore, the entrusted design pattern is more concise
Knowledge points of this chapter:
None