This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.

Write in front, round and round, back and forth, from the beginning to learn JS to now has been working these next year, I and JS everyday life can be used to describe. But I don’t think I know him well enough. So start all over again, from the basics. Go!!!!!!

new

  • The freshman became an object

  • Link to the prototype

  • Binding this

  • Return a new object

All four of these things happen during a call to new, and we can try to implement a new ourselves

function create() {

// Create an empty object

let obj = new Object()

// Get the constructor

let Con = [].shift.call(arguments)

// Link to the prototype

obj.__proto__ = Con.prototype

// Bind this to the constructor

let result = Con.apply(obj, arguments)

// Make sure new comes out as an object

return typeof result === 'object' ? result : obj

}
Copy the code

instanceof

Instanceof can correctly determine the type of an object because the internal mechanism is to determine if the prototype of the object can be found in the prototype chain

We could also try instanceof

function instanceof(left, right) {

    // Get the prototype of the type

    let prototype = right.prototype

    // Get the prototype of the object

    left = left.__proto__

    // Determine whether the type of the object is equal to the prototype of the type

    while (true) {

        if (left === null)

        return false

        if (prototype === left)

        return true

        left = left.__proto__}}Copy the code

this


function foo() {

    console.log(this.a)}var a = 1

foo()

var obj = {

    a: 2,

    foo: foo

}

obj.foo(a)// In both cases' this' only depends on the object before the function is called, and the second case has precedence over the first case

// The following is the highest priority: 'this' is bound only to' c 'and cannot be referred to by' this' in any way

var c = new foo()

c.a = 3

console.log(c.a)

// Another option is to use call, apply, bind to change this, which is next in priority to new

Copy the code

Look at this in the arrow function

function a() {

    return() = > {return () => {

            console.log(this)

        }

    }

}

console.log(a()()())
Copy the code

The arrow function does not have this. The this in this function depends only on the this of the first function outside it that is not the arrow function. In this case, because calling a matches the first case in the previous code, this is the window. And once this is bound to the context, it will not be changed by any code

closure

The definition of A closure is simple: if function A returns A function B, and function B uses A variable of function A, function B is called A closure.

function A() {

    let a = 1

    function B() {

        console.log(a)

    }

    return B

}
Copy the code

Do you wonder why function A is already off the call stack, and why function B can still refer to A variable in function A? Because the variables in function A are stored on the heap. Today’s JS engines can use escape analysis to identify which variables need to be stored on the heap and which need to be stored on the stack.

Var defines a function using a closure in a loop


for ( var i=1; i<=5; i++) {

    setTimeout( function timer() {

        console.log( i );

    }, i*1000 );

}

Copy the code
  • First of all, because setTimeout is an asynchronous function, it will complete the loop first, at which point I will be 6, so it will output a bunch of 6’s.

There are three solutions, the first using closures

for (var i = 1; i <= 5; i++) {

    (function(j) {

        setTimeout(function timer() {

            console.log(j);

        }, j * 1000);

    })(i);

}
Copy the code

The second option is to use the third parameter of setTimeout

for ( var i=1; i<=5; i++) {

    setTimeout( function timer(j) {

        console.log( j );

    }, i*1000, i);

}
Copy the code

The third way is to use let to define I

for ( let i=1; i<=5; i++) {

    setTimeout( function timer() {

        console.log( i );

    }, i*1000 );

}
Copy the code

Because for let, it creates a block-level scope equivalent to

{ // form block-level scopes

    let i = 0

    {

        let ii = i
        setTimeout( function timer() {

            console.log( i );

        }, i*1000 );

    }

    i++

    {

        let ii = i

    }

    i++

    {

        let ii = i

    }

    ...

}
Copy the code

Depth copy

let a = {

    age : 1

}

let b = a

a.age = 2

console.log(b.age) / / 2
Copy the code
  • As we can see from the example above, if you assign an object to a variable, the value of both will be the same reference, and if one changes, the other will change.

  • Usually in development we don’t want to have this problem, we can use shallow copy to solve this problem

Shallow copy

The first solution to this problem is object.assign

let a = {

    age: 1

}

let b = Object.assign({}, a)

a.age = 2

console.log(b.age) / / 1
Copy the code

Of course we can also expand the operator (…) To solve the

let a = {

    age: 1

}

let b = {...a}

a.age = 2

console.log(b.age) / / 1

Copy the code

Shallow copy usually solves most of the problems, but deep copy is needed when we encounter the following situations

let a = {

    age: 1,

    jobs: {

        first: 'FE'

    }

}

let b = {...a}

a.jobs.first = 'native'

console.log(b.jobs.first) // native
Copy the code

Shallow copies only solve the problem at the first level, and if there are any objects in the following values, then we’re back to where we started, and both share the same reference. To solve this problem, we need to introduce deep copy

Deep copy

Parse (json.stringify (object)) this problem can usually be solved with json.parse (json.stringify (object))

let a = {

    age: 1,

    jobs: {

        first: 'FE'

    }

}

let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'

console.log(b.jobs.first) // FE
Copy the code

But there are limitations to this approach:

  • Ignores undefined

  • Non-serializable function

  • Cannot resolve object referenced by loop

let obj = {

    a: 1,

    b: {

        c: 2,

        d: 3,

    },

}

obj.c = obj.b

obj.e = obj.a

obj.b.c = obj.c

obj.b.d = obj.b

obj.b.e = obj.b.c

let newObj = JSON.parse(JSON.stringify(obj))

console.log(newObj)
Copy the code

If you have such a circular reference object, you will find that you cannot use this method for deep copy

  • When a function or undefined is encountered, the object will not serialize properly
let a = {

    age: undefined,

    jobs: function() {},

    name: 'poetries'

}

let b = JSON.parse(JSON.stringify(a))

console.log(b) // {name: "poetries"}
Copy the code

You’ll notice that the method ignores functions and ‘undefined’ in the above cases.

  • But in general, complex data is serializable, so this function solves most of the problems, and it is the fastest deep-copy function among the built-in functions. Of course, you can use LoDash’s deep-copy function if your data has any of the above.

END~~~