Prototype chain
- Refer to JS prototype and prototype chain analysis
inheritance
- Refer to several kinds of JS inheritance
Call, apply, bind usage and implementation
- What it does: Change, in a nutshell
this
To call a method from one object to another
usage
apply
withcall
Is similar in that it executes the function directly
A.sayName.call(B,'tom')
A.sayName.apply(B,['tom'])
Copy the code
bind
Usage andcall
Similar, but different, she doesn’t execute it immediately, she returns a copy of the original function
let bSay = A.sayName.bind(B,'tom') / / copy
bSay()/ / call
Copy the code
implementation
//A.myCall(B,arg1,arg2)
// Mount to Function's prototype object for inheritance to Function object calls
Function.prototype.myCall = function (originFun, ... args) {
// myCall from A, where this refers to A function
console.log(this)
// Define A private property in B to point to function A
originFun.__thisFn__ = this
//B calls A, this refers to B
letresult = originFun.__thisFn__(... args)// Delete useless attributes
delete originFun.__thisFn__
return result
}
Copy the code
Methods for determining types
-
The typeof and instanceof
-
Object.prototype.toString.call(); Every Object has a toString() method, which by default is inherited by every Object and returns [Object type] if it is not overridden. Type is the type of the Object. Such as:
let obj= new Object() obj.toString() // "[object object]" Copy the code
But for other cases
var arr =new Array(1.2) arr.toString() / / output 1, 2, "" Copy the code
This is because when the so-called Array, String and other types inherit from the base class Object, they rewrite the toString method. When calling, when searching up the method through the prototype chain, they stop searching and call the method directly when they find the toString above Array, so the output is different from the expected. How do I get arR to call this method on Object? Borrow call() for obvious reasons
Object.prototype.toString.call(arr) // Output "[object Array]" Copy the code
The slice method is then used to intercept the type
// Whether it is a string export const isString = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='String' // Whether it is a number export const isNumber = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Number' / / a Boolean export const isBoolean = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Boolean' // Is a function export const isFunction = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Function' // Whether the value is null export const isNull = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Null' / / is undefined export const isUndefined = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Undefined' // Whether to object export const isObj = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Object' // Whether an array is available export const isArray = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Array' // Whether the time export const isDate = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Date' // Is regular export const isRegExp = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='RegExp' // Whether the object is an error export const isError = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Error' // Is the Symbol function export const isSymbol = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Symbol' // Whether the object is a Promise export const isPromise = (o) = > Object.prototype.toString.call(o).slice(8, -1) = = ='Promise' Copy the code
Capture and bubble
- Event capture and bubbling process
capture
-
The event capture phase checks whether an event is registered, layer by layer, from the outside in
-
How do I register events during the capture phase?
- use
addEventListener
Registers the event, and the third parameter indicates whether the event is processed during the capture phase, set totrue
<div class="box"> <button class="btn">button</button> </div> <script> // display div first and then display BTN const box = document.querySelector('.box') box.addEventListener( 'click'.() = > { alert('Div is clicked')},true ) const btn = document.querySelector('.btn') btn.addEventListener( 'click'.() = > { alert('Button is clicked')},true ) </script> Copy the code
- use
The bubbling
-
In contrast to capture, during the event bubbling phase, events are checked to see if they are registered from the inside out
-
By default, all events are registered in the bubbling phase. How do I prevent events from bubbling?
-
W3 standards
event.stopPropagation() Copy the code
-
IE browser
event.cancelBubble=true Copy the code
-
Event delegation
- More often than not, multiple elements register the same event and can delegate those events to its parent element
ul
The inside of theli
Tag click event
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
const ul = document.querySelector('ul')
ul.addEventListener('click'.(e) = > {
if (e.target.nodeName == 'LI') {
alert(e.target.innerText)
}
})
</script>
Copy the code
The closure problem
- Access the scope of an outer function in an inner function
Isolation scope
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
returnprivateCounter; }}};// Counter1 and Counter2 do not affect each other. Modifying variables in a closure does not affect variables in the other closure
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */
Copy the code
The classic for loop closure problem
for (var i = 1, arr = []; i < 5; i++) {
setTimeout(() = > {
console.log(i)
}, 500)}/ / 5,5,5,5
// Use closures
for (var i = 1, arr = []; i < 5; i++) { ; (function (i) {
setTimeout(() = > {
console.log(i)
}, 1000 * i)
})(i)
}/ / 1, 2, 3, 4
Copy the code
What happens when you implement a new object
const myNew = (constructorFn, ... args) = > {
// Create a new object
let obj = {}
// Create a private property that points to the constructor's prototype object
obj.__proto__ = constructorFn.prototype// Execute the constructorconstructorFn.call(obj, ... args) // Return this objectreturn obj
}
function Person(name, age) {
this.name = name
this.age = age
}
const Per1 = new Person('Tom'.12)
console.log('Per1', Per1)
const Per2 = myNew(Person, 'Tom'.12)
console.log('Per2',Per2)
Copy the code
Anti-shake and throttling
- The realization of anti-shake and throttling
Depth copy
- Basic types of
String
,Number
Are allAccording to the valueIts value is stored in the stack - Reference types are accessed by reference, which stores reference addresses on the stack and then creates space on the heap for their values
Shallow copy
- If it is a primitive type, the value of the primitive type is copied directly; if it is a reference type, the reference address of the reference type is copied
- Shallow copies do not affect each other for basic types, but for reference types, because they copy addresses that eventually point to the same heap, they affect each other
implementation
- ES6 expansion operator
let obj1 ={name:'tom'.age:12.addr: {lng:26.0.lag:45.0},friends: ['john'.'jerry']}
letobj2={... obj1} obj2.name='jerry'
obj2.frinds[0] ='tom'
Copy the code
The ES6 expansion operator behaves differently for different structures of data. Deep copy for one-dimensional objects or arrays, shallow copy for multi-dimensional objects or arrays
- Object.assign()
let obj1 ={name:'tom'.age:12.addr: {lng:26.0.lag:45.0},friends: ['john'.'jerry']}
let obj2= Object.assign({}, obj1);
Copy the code
Same thing as deconstructing assignments
- lodash.clone()
var objects = [{ 'a': 1 }, { 'b': 2 }];
var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
Copy the code
Deep copy
- For reference types, it creates a new space for objects so that the two deep-copied objects don’t interact
implementation
- JSON.parse(JSON.stringfy() )
let obj1 ={name:'tom'.friends: ['jerry'.'john']}
let obj2 =JSON.parse(JSON.stringify(obj1))
obj2.name='jerry'
obj2.friends[0] ='tom'
Copy the code
- lodash.cloneDeep()
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
Copy the code
- Recursive traversal implementation
function clone(targetObj) {
// Check whether there are no objects, objects to traverse the copy
if (typeof targetObj === 'object') {
// Determine whether the source data is an object or an array
let cloneTarget = Array.isArray(targetObj) ? [] : {}
for (const key in targetObj) {
// Recursive copy
cloneTarget[key] = clone(targetObj[key])
}
return cloneTarget
} else {
// The object is not returned directly
return targetObj
}
}
Copy the code