preface
When you are old and look back on your life, you will find that when you study abroad, when you decide to take your first job, when you decide to fall in love with someone, and when you get married are all huge changes in your destiny. However, standing at a fork in the road, the day you made your choice appears in your diary as dull and ordinary. At that time, I thought it was an ordinary day in my life.
A project to transform the interview — the Interview Atlas.
The autumn recruitment season of gold nine silver ten is just around the corner, presumably everyone is itching to challenge better job opportunities. Well, the interview must be the biggest challenge.
For an interview, usual accumulation is certainly necessary, but preparation before the interview is also crucial.
A few months ago, I set up a small team and spent nearly half a year looking for interview questions of big companies, screened out nearly 100 knowledge points and translated them into English. Today, finally open source the first version, the total number of words has been as high as more than 100 thousand words. Every member of the team is a front-line engineer, including one from Google.
It can be said that we are confident to make this project the NO. 1 in interview related field. Because all the content did not copy any books, every knowledge point has detailed access to data before written. Later will add more content, as far as possible to cover most knowledge points.
We don’t think it’s going to do much good to just write the back questions. Only familiar with each knowledge point and mastery, in order to interview. At present, this atlas contains nearly 100 high frequency knowledge points, whether it is the preparation before the interview or in daily learning, we believe that it will definitely help you. At present, the content includes JS, network, browser related, performance optimization, security, framework, Git, data structure, algorithm and so on. Whether it is basic or advanced, or source code interpretation, you can get satisfactory answers in this atlas. I hope this interview atlas can help you better prepare for the interview.
The content of the warehouse will continue to be updated, and there will be more content in the future, such as system design, blockchain, operation and maintenance, back-end, etc. Of course, these are not my strengths, I will invite friends with good experience in this field to write content.
The outline
To apply for a job
Recently I am looking for job opportunities, if there is a good position in Hangzhou, please contact me at [email protected].
Partial preview
MVVM
The MVVM consists of the following three components
- Interface of the View:
- Model: Data Model
- ViewModel: Act as a bridge between View and Model
In the era of JQuery, if you need to refresh the UI, you need to fetch the corresponding DOM and then update the UI, so that the data and business logic is strongly coupled with the page.
In MVVM, THE UI is driven by data. Once the data changes, the CORRESPONDING UI will be refreshed accordingly. If the UI changes, the corresponding data will also be changed. This way you can focus on the flow of data in business processes without having to deal directly with the page. The ViewModel only cares about data and business processing, not how the View handles the data. In this case, the View and Model can be separate, and either side doesn’t have to change the other side, and some reusable logic can be put into a ViewModel. Let multiple views reuse the ViewModel.
In MVVM, the core is two-way data binding, such as dirty data detection in Angluar and data hijacking in Vue.
Dirty data detection
When the specified event is triggered, dirty data detection is performed, and the $digest loop is called to traverse all data observers to determine whether the current value is different from the previous value. If a change is detected, the $watch function is called, and then the $digest loop is called again until no change is found. The loop is at least two times and at most ten times.
Dirty data detection is inefficient, but it can be done regardless of how the data is changed, but this is problematic with two-way binding in Vue. In addition, dirty data detection can realize batch detection of updated values, and then uniformly update UI, which greatly reduces the number of DOM operations. So inefficiency is relative, which is a matter of opinion.
The data was hijacked
Vue uses obeject.defineProperty () internally for bidirectional binding, which listens for set and GET events.
var data = { name: 'yck' }
observe(data)
let name = data.name // -> get value
data.name = 'yyy' // -> change value
function observe(obj) {
// Determine the type
if(! obj ||typeofobj ! = ='object') {
return
}
Object.keys(data).forEach(key= > {
defineReactive(data, key, data[key])
})
}
function defineReactive(obj, key, val) {
// Recursive subattributes
observe(val)
Object.defineProperty(obj, key, {
enumerable: true.configurable: true.get: function reactiveGetter() {
console.log('get value')
return val
},
set: function reactiveSetter(newVal) {
console.log('change value')
val = newVal
}
})
}
Copy the code
The above code simply implements how to listen for data set and GET events, but this is not enough. You also need to add publish subscribe to attributes when appropriate
<div>
{{name}}
</div>
Copy the code
When parsing the template code above, {{name}} is encountered and a publish subscription is added to the attribute name.
// Decouple through Dep
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
// sub is an instance of Watcher
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub= > {
sub.update()
})
}
}
// Global property, with which to configure Watcher
Dep.target = null
function update(value) {
document.querySelector('div').innerText = value
}
class Watcher {
constructor(obj, key, cb) {
// Point dep. target to yourself
// Then trigger the getter for the property to add a listener
// Dep. Target is left blank
Dep.target = this
this.cb = cb
this.obj = obj
this.key = key
this.value = obj[key]
Dep.target = null
}
update() {
// Get a new value
this.value = this.obj[this.key]
// Call the update method to update the Dom
this.cb(this.value)
}
}
var data = { name: 'yck' }
observe(data)
// Simulate parsing to the action triggered by '{{name}}'
new Watcher(data, 'name', update)
// update Dom innerText
data.name = 'yyy'
Copy the code
Next, modify the defineReactive function
function defineReactive(obj, key, val) {
// Recursive subattributes
observe(val)
let dp = new Dep()
Object.defineProperty(obj, key, {
enumerable: true.configurable: true.get: function reactiveGetter() {
console.log('get value')
// Add Watcher to the subscription
if (Dep.target) {
dp.addSub(Dep.target)
}
return val
},
set: function reactiveSetter(newVal) {
console.log('change value')
val = newVal
// Execute watcher's update method
dp.notify()
}
})
}
Copy the code
The above implementation of a simple two-way binding, the core idea is to manually trigger the getter of the property once to implement the publication subscription.
Proxy compared to OBEject.defineProperty
Obeject.defineproperty is already capable of bidirectional binding, but it is still flawed.
- Data hijacking can only be done on attributes, so you need to deeply traverse the entire object
- You can’t listen for data changes with arrays
While it is true that Vue can detect array data changes, it is a hack, and it is flawed.
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
// hack the following functions
const methodsToPatch = [
'push'.'pop'.'shift'.'unshift'.'splice'.'sort'.'reverse'
]
methodsToPatch.forEach(function (method) {
// Get the native function
const original = arrayProto[method]
def(arrayMethods, method, function mutator (. args) {
// Call the native function
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// Trigger the update
ob.dep.notify()
return result
})
})
Copy the code
Proxy, on the other hand, doesn’t have this problem. It natively listens for array changes and intercepts entire objects directly, so Vue will also replace OBEject.defineProperty with Proxy in the next big release
let onWatch = (obj, setBind, getLogger) = > {
let handler = {
get(target, property, receiver) {
getLogger(target, property)
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
setBind(value);
return Reflect.set(target, property, value); }};return new Proxy(obj, handler);
};
let obj = { a: 1 }
let value
let p = onWatch(obj, (v) = > {
value = v
}, (target, property) = > {
console.log(`Get '${property}'=${target[property]}`);
})
p.a = 2 // bind `value` to `2`
p.a // -> Get 'a' = 2
Copy the code
Routing principle
Front-end routing implementation is actually very simple, the essence is to monitor URL changes, and then match routing rules, display the corresponding page, and do not need to refresh. Currently there are only two ways to implement routing for a single page
- Hash pattern
- The history mode
www.test.com/#/ is a Hash URL. When the Hash value after # changes, no data is requested from the server. The hashchange event is used to listen for changes in the URL and jump to the page.
History mode is a new feature of HTML5 that is much nicer than Hash urls
Built-in types
JS is divided into seven built-in types, which are divided into two types: basic type and Object.
There are six basic types: null, undefined, Boolean, number, string, symbol.
The number type of JS is floating point, there is no integer type. And floating point type based on IEEE 754 standard implementation, in the use of some bugs. NaN is also of type number, and NaN is not equal to itself.
For primitive types, if literal, the variable is a literal and will only be converted to the corresponding type if necessary
let a = 111 // This is just a literal, not a number type
a.toString() // It is converted to object type only when used
Copy the code
Object is a reference type, which may encounter the problem of shallow copy and deep copy.
let a = { name: 'FE' }
let b = a
b.name = 'EF'
console.log(a.name) // EF
Copy the code
Typeof
Typeof For basic types, all but NULL can display the correct type
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol(a)// 'symbol'
typeof b // b has no declaration, but it still shows undefined
Copy the code
Typeof displays object for all objects except functions
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
Copy the code
For NULL, although it is a primitive type, object is displayed, which is a long-standing Bug
typeof null // 'object'
Copy the code
PS: Why does this happen? In the original version of JS, the 32-bit system was used. For the sake of performance, the type information of variables was stored in low order. The beginning of 000 represents an object, while null represents all zero, so it was wrongly judged as object. Although the internal type determination code has changed, the Bug has persisted.
If we want to get the right type of a variable, you can through the Object. The prototype. ToString. Call (xx). So we can get a string like [Object Type].
let a
// We can do the same with undefined
a === undefined
// But undefined is not a reserved word and can be assigned in older browsers
let undefined = 1
// Then the judgment will be wrong
// So you can use the following way, and less code
// because void follows any other constituent expression
// return undefined
a === void 0
Copy the code
Type conversion
Turns a Boolean
All values except undefined, null, false, NaN, “”, 0, -0 are converted to true for conditional judgments, including all objects.
Object to basic type
When an object converts a primitive type, valueOf is first called and then toString is called. And these are two methods that you can override.
let a = {
valueOf() {
return 0}}Copy the code
Four operators
Only when one side of an addition is a string will the other be converted to a string. As long as one of the other operations is a number, the other becomes a number. And addition triggers three types of conversion: converting a value to a raw value, converting it to a number, and converting it to a string.
1 + '1' / / '11'
2 * '2' / / 4
[1.2] + [2.1] / / '1,22,1'
// [1, 2].toString() -> 1,2
// [2, 1].toString() -> '2,1'
// '1,2' + '2,1' = '1,2,1'
Copy the code
For the plus sign, notice this expression ‘a’ + + ‘b’.
'a' + + 'b' // -> "aNaN"
// because + 'b' -> NaN
You may have seen + '1' -> 1 in some code
Copy the code
= =
The operator
The toPrimitive in the figure above is an object to base type.
It is generally recommended to use === to determine two values, but if you want to know whether a value is null, you can use xx == null to compare.
[] ==! [] // -> true, the next step is why this expression is true
// [] converts to true, and then inverts to false[] = =false
// in accordance with clause 8
[] == ToNumber(false) [] = =0
// according to clause 10
ToPrimitive([]) == 0
// [].toString() -> ''
' '= =0
// in accordance with clause 6
0= =0 // -> true
Copy the code
Comparison operator
- If it’s an object, it passes
toPrimitive
Converting objects - If it is a string, it passes
unicode
Character index to compare
The public,
Todo
- Complete CSS content
- Complete the Webapck content
- Complete the content related to the small program
- Improve the framework
The above content is expected to be updated in September. You are welcome to participate in the construction of this atlas.
Interview atlas project address, if you think the project is good, you can point a little star to support us, your support is the source of our update power.