This article will say some basic knowledge of javascript, this article is very suitable for you to review the basics of javascript and some novice help, please carefully check the code in the article, to help you understand
Differences and simple implementations between Call, apply, and bind
In common
It’s all about changing my “this”
The difference between
1. Whether the function is called
- Both Call and Apply can call my function
- Whereas my bind will not call my function, it will return a new function that you must call manually
2. Differences in parameter transfer
- Call, bind If the function needs to pass parameters, you need to pass the corresponding parameters in turn
- The apply function passes parameters that need to be wrapped as arrays
The call to realize
Before implementing it, let’s take a look at the definition of this method in MDN
The call() method calls a function with a specified this value and one or more arguments given separately.
That is, we need to implement the following:
- I have to be a Function to call this method because call is a method in function.prototype
- No argument is passed or the first argument is passed null and this points to the window
- Arguments after the first parameter are received as arguments to the calling function
- Change this to return the result of calling the function
// Calling this method must be a Function, as you can see from the method added in function.prototype
Function.prototype.myCall = function (context) {
// Check whether my object is null or has no value passed in, if so, pointing to window
context = context || window
// Add a fn attribute to my object. The value of fn is the function that calls this method
context.fn = this
// Deconstruct my parameter with the three-point operator and intercept the argument after the first parameter
const args = [...arguments].slice(1)
// Call my method with the corresponding array of arguments destructed as arguments
constresult = context.fn(... args)// This function is placed on my object, call finished, can be deleted
delete context.fn
// Returns the execution result
return result
}
var name = 'yaojin'
const obj = {
name: 'remote close'
}
function showName (age) {
console.log(age)
// The parameter is acceptable to input 18
console.log(this.name)
}
// Call this function normally
showName(18) // yaojin
/ / by myCall
showName.myCall(obj, 18)/ / distance near
}
Copy the code
The realization of the apply
The implementation of Apply is the same as that of Call, except that apply passes an array of parameters
var name = 'yaojin'
function showName (age, money) {
console.log(age)
console.log(money)
// The parameter is acceptable to input 18
console.log(this.name)
}
const obj = {
name: 'remote close'
}
Function.prototype.myApply = function (context) {
if (typeof this! = ='function') throw new TypeError('Error');
context = context || window
context.fn = this
let result
If so, read the second argument, which is an array or an error will be reported
if (arguments[1]) { result = context.fn(... arguments[1])}else {
// If no parameter is passed, the function is called normally
result = context.fn()
}
delete context.fn
return result
}
showName() // This points to Windwo reading yaojin
showName.myApply(obj, 18) // This points to obj
Copy the code
The realization of the bind
The main difference between bind and call and apply is that it returns a function, so the implementation returns a function and changes its “this” reference, which can be specified or, if called by new, “this” refers to its newly created object
Function.prototype.myBind = function(context) {
let _this = this // Cache the function that calls this function
let args = [...arguments].slice(1) // Remove the first argument passed in
var fn = function () {
let bindArgs = [...arguments] // Save all parameters to an array
// If called by new,this refers to my function; if not,this refers to the object I passed in with the corresponding argument
return _this.apply(this instanceof fn ? this : context, args.concat(bindArgs))
}
// If I call new, I need to point the prototype of this of my newly created object to the prototype of my function
fn.prototype = Object.create(this.prototype)
return fn
}
const name = 'yaojin'
const obj = {
name: 'remote close'
}
function showName (age, address) {
this.sex = 'male'
console.log(this.name)
console.log(age)
console.log(address)
}
showName.myBind(obj, 18) ("Foshan") // This points to obj and prints the distance, and the corresponding parameters can also be printed
const newFn = showName.myBind(obj, 18)
var newObj = new newFn('the foshan') // call with new
console.log(newObj.sex) My new object can inherit the properties and methods of my function
Copy the code
What does the New keyword implement?
- Create an empty object, and this object is what I want to display (let’s say my new object is obj)
- Point the implicit prototype of my newly created object to the constructor’s display prototype (obj.proto === xxx.protpType)
- Use apply to change the this reference of my constructor, pass my corresponding parameter to my constructor, call it, and finally return the corresponding result
- And the last thing I want to notice is, all of these return value issues, if there’s any other object returned in the constructor, then that object will be returned, if there’s no other object returned, my newly created object will be returned, and this in my constructor will refer to my newly created object
The following is a code parody of the new implementation
<script type="text/javascript">
function _new() {
// Create an empty object
let target = {};
// Expand the argument I passed and assign it to a new array, the first of which is my constructor and the others are the corresponding arguments in the constructor
let [constructor.args] = [...arguments];
// The implicit prototype of the newly created object points to the display prototype of the constructor, allowing the newly created object to inherit the methods and properties of the constructor
target.__proto__ = constructor.prototype;
// Call the constructor and point this of my constructor to my newly created object, pass in the argument, and assign the function return value to result;
let result = constructor.apply(target, args);
// Determine if my result is an object, if so return the object, if not I return my newly created object;
if (result && (typeof (result) === "object" || typeof (result) === "function")) {
return result;
}
return target;
};
// A custom constructor that takes two parameters
function Person(name, age) {
this.name = name;
this.age = age;
};
// To call the new method I created, I pass in the constructor name and the corresponding two parameters
const yaojin = _new(Person,"Remote close".18);
// Finally print the output
console.log(yaojin.__proto__ === Person.prototype);
console.log(yaojin);
</script>
Copy the code
What is a closure?
A lot of people say that a closure is a function, but I understand it as an object. In fact, you can see it in the console from the debugger as an object, and it contains local variables that are referenced
An object in the console called Closure is the Closure, and you can see that it has two properties: my corresponding variable name (key) and its value (value).
So how do closures come about?
Three conditions need to be met for closure generation
The first conditional function must be nested, that is, there must be at least two functions to generate the closure (as you can see in the figure above, there are two)
The second condition is that it refers to a local variable of my external function.
The third condition is that I have to call a function outside of me
What does a closure do?
Closure function mainly through the scope chain let me internal function can access to the outer function’s local variables, or the global environment can let me reference to internal function variables (specific you can, for example, to the interviewer), is in order to prolong the lifecycle of the I variable, because without the existence of the closure, I complete, the function of local variables will give release!
Disadvantages of closures
There are pros and cons to this. Closures can extend the lifetime of a variable, but if a local variable is not released after the function is executed, it will leak memory
function fn(){
let yaojin = 'remote close';
function me(){
console.log(yaojin)
}
return me;
}
let test = fn(); // The object to which it points is kept in heap memory
test = null; // Make the object it points to empty if it is no longer used
Copy the code
Talk about the direction of this
Normally, the way the function is executed determines what this refers to
- Direct call
var name = 'remote close'
function fn (name) {
console.log(this)
console.log(this.name)
}
fn() // This points to the output of the window
Copy the code
- The object
let obj = {
name: 'yaojin',
fn
}
obj.fn() // This points to obj and outputs yaojin
Copy the code
- The new call
function Person (name) {
this.name = name
}
yaojin = new Person('remote close') // The constructor's this points to yaojin
Copy the code
- Call, apply, bind
var name = 'remote close'
let obj = {
name: 'yaojin',
fn
}
let obj1 = {
name: 'yaojin666'
}
function fn (name) {
console.log(this)
console.log(this.name)
}
fn.call(obj) / / points to obj
fn.apply(obj)/ / points to obj
const fn2 = fn.bind(obj)
fn2()/ / points to obj
Copy the code
In special cases,this points to
- Arrow function
function fn1 () {
console.log(this.name)
return () = > {
console.log(this.name)
}
}
var name = 'yaojin'
const obj = {
name: 'remote close'
}
const newFn = fn1.call(obj) // set fn1's this to obj
newFn() // The function returned is an arrow function whose this points to obj
Copy the code
The arrow function’s this checks whether the outer function has a function. If so, the outer function’s this is the inner arrow function’s this; if not, this is the window.
- The callback function
Timer callback: this points to the window DOM event listener callback: this points to the corresponding DOM element of the binding event
What is a constructor
In JavaScript, functions called with the new keyword are called constructors. Their function names usually start with a capital letter
JavaScript doesn’t actually have constructors, only constructor calls to functions. Constructors are just called to cater to other languages.
Because JavaScript only creates a constructor with a new call, whereas other languages don’t create a constructor with new at all, it has its own unique syntax, and we only create a constructor with new, so we call it a constructor call to a function
Functions and Disadvantages
Constructor function lies in the fact that made me an instance of the object can be inherited the constructor of the attributes and methods, but it’s the same object instance, unable to share the attributes and methods, meaning that when I am by the new constructor creates instance object, I think these objects inherit a the same way, if they are written in the constructor of I, So these two methods are not the same, it will create new space in the heap, which will be a waste of memory!
// Create a constructor
function Person (name, age) {
this.name = name
this.age = age
this.hello = function () {
console.log('Hello, remote near')}}const yaojin = new Person('remote close'.18)
const yj = new Person('remote nearly 666'.18)
console.log(yaojin.hello === yj.hello)//false
// Store the common methods and attributes in Prototype
Person.prototype.say = function () {
console.log('Near you.')}console.log(yaojin.say === yj.say)//true
Copy the code
So there’s the prototype chain, putting all the methods and properties I have in common on one of my instances in a Prototype object! This way, you can find the corresponding properties and methods step by step through the prototype chain!
What is a prototype chain?
The prototype refers to the function’s prototype property and the object’s __proto__ property, but it’s important to note that since my function is also an object, it has the two properties I just described
The prototype attribute is an Object that has at least two attributes: constructor and __proto__, except object.prototype!
The value of the constructor attribute points to its constructor itself
// Create a constructor
function Person (name, age) {
this.name = name
this.age = age
}
// Prototype is an object
console.log(Person.prototype instanceof Object)//true
// The constructor attribute points to its constructor itself
console.log(Person.prototype.constructor === Person)//true
// The Function constructor's __proto__ value points to function.prototype
console.log(Function.__proto__ === Function.prototype)//true
// The constructor's prototype Object whose __proto__ value refers to Object.prototype
console.log(Person.prototype.__proto__ === Object.prototype)//true
const yaojin = new Person('remote close'.18)
// You can see that the object created by new has its __proto__ pointing to its constructor's prototype
console.log(yaojin.__proto__ === Person.prototype)//true
The yaojin object itself does not have the say method, which follows the prototype chain and is eventually found in its constructor, prototype
Person.prototype.say = function () {
console.log('Near you.')}Copy the code
The __proto__ attribute of an object has four values
1. The constructor’s __proto__ value for Function refers to function.prototype
2. An object created by new whose value points to the prototype of its constructor
3. The prototype Object of all constructors, whose value points to Object.prototype
Object. Prototype __proto__ refers to null
And it is this chain of __proto__ attributes that forms the prototype chain
If the prototype constructor doesn’t have one, it will look for its own property. If the prototype constructor doesn’t have one, it will look for object. prototype. If it doesn’t have one, it will return undefined
Prototype chain figure
The prototype chain diagrams circulating on the Internet can give you a better idea
Talk about scopes and scope chains
Scope you can think of as the place where code is stored, and it determines the accessible scope of variables and objects
Scopes are divided into global scopes and local scopes
Global scope
As long as it can be accessed and used anywhere, the object or variable has the characteristics of global scope
Any variable or object that has global scope is simply adding the corresponding variable and method to the Window object
function name () {
var yaojin = 'remote close'
console.log(name)
function showAge() {
console.log(age) // Can be accessed anywhere in the global scope
console.log(name)
}
showAge()
}
var age = 18
console.log(window.name) // Function under the global scope
console.log(window.age)// Global scope variables
name()
Copy the code
As you can see from the above code, I reprint the outer functions inside the function, which are also accessible, and the corresponding functions and variables read from the window are also accessible, which is a feature of the global scope
Local scope
A local scope is the opposite of a global scope. It is only accessible in a specific region. Local scopes can be subdivided into function scopes and block-level scopes (ES6).
- Function scope
Function scope, as the name implies, is only valid within a function. Variables and functions defined in a function are accessible only within the function itself, not globally, except through closures
function name () {
var yaojin = 'remote close'
console.log(yaojin) // Variables in the function scope cannot be accessed globally
}
name()
console.log(yaojin) / / an error
console.log(address) / / an error
Copy the code
We can see that variables and functions in a local scope are not accessible everywhere, and this is the biggest difference between global and local
- Block-level scope
ES6 introduced the new let and const commands, which allow us to create block-level scopes. Variables and objects defined by let and const are limited to the current code block. Those wrapped in curly braces belong to the same block, and there is no promotion of variables
function name () {
console.log(yaojin) / / an error
function test () {
console.log(yaojin1) / / an error
}
test()
let yaojin1 = 'yaojin2070' // The variable will not be promoted
}
const yaojin = 'yaojin'// The variable will not be promoted
name()
Copy the code
:::tip scope is used to isolate variables. Only specific variables can be accessed from different scopes to avoid variable abuse :::
The scope chain
Scope chain is composed of multiple scopes. It is a chain structure formed from inside to outside. Its function is to find a rule of variables
var yaojin = 'remote close'
function check () {
function check1 () {
console.log(yaojin) // Finally found in the global through the scope chain, print near
}
check1()
}
check()
Copy the code
If the global scope is not found, an error is reported. If the global scope is not found, an error is reported
Promotion of variables and functions
To promote a variable or function is to promote it to the top of its scope
Promotion of variables
The promotion of a variable is just the promotion of the declaration, that is, it does not promote the content as well
function test () {
console.log(yaojin) / / print undefined
var yaojin = 'yaojin'
}
test()
Copy the code
As can be seen from the code, we print before the yaojin variable definition, but it does not report an error. This is because there is a promotion of the variable, but the promotion of the variable only elevates the declaration, which means that the final code is as follows:
function test () {
var yaojin
console.log(yaojin) / / print undefined
yaojin = 'yaojin'
}
test()
Copy the code
:::tip From the variable promotion we need to pay attention to, we will try to write the variable at the top of a scope in the future code, so that it is convenient to view themselves, but also convenient to maintain :::
Function increase
Function promotion raises the whole, it raises the whole function to the top of its scope
test()
function test () {
console.log('The function improves, even though I execute the function at the top.')}Copy the code
You can see that the code does not report an error, but instead calls normally, which is the promotion of the function
Note that:
- First, make it clear that there is a declaration followed by an assignment
console.log(yaojin)
yaojin = 'remote close'
var yaojin
Copy the code
As you can see, var Yaojin is promoted to the top of the scope, and it is important to note that the same declaration can only exist once
- First there is the promotion of variables, then there is the promotion of functions
console.log(yaojin)// Prints a function
var yaojin = 'remote close'
function yaojin () {
console.log(1)}console.log(yaojin)// Print near
Copy the code
Some people may look at this and think, is not the function promoted, in fact, it is not, but the function promotion is the overall promotion, it will also improve the defined part, so in the case of the variable with the same name, you can understand that the function promotion is greater than the variable promotion
This is the code above
var yaojin = function () {
console.log(1)}console.log(yaojin)// Prints a function
yaojin = 'remote close'
console.log(yaojin)// Print near
Copy the code
- Variables defined by let and const do not have variable promotion