js advanced (proxy, shallow copy, deep copy, throttling and anti-shake, closure.hasOwnProperty)

1.Agent

1. Question: How to define an object that will not be modified or traversed?
  1. Define default properties through Object.defineProperty(object, property name, option)

    • cannot be modified
    • cannot be deleted
    • cannot be traversed

    Note: The value passed in by Object.Property and the value returned are the same address

  2. You can configure the properties

    • value: initial value
    • writable:true (true allows to be modified)
    • enumerable:true (rue is allowed to be traversed)
    • configurable:true (rue is allowed to be deleted)
  3. Provides two methods, get and set.

    • Note: get and set cannot be used together with value and writable. When setting the value of a property to an object, set will be triggered.
 // var obj={}
        var o = Object.defineProperty({<!-- -->}, "name", {<!-- -->
            value: "Andy Lau",//initial value
            writable: true,//true allows to be modified
            enumerable: true,//true is allowed to be traversed
            configurable: true//true allows to be deleted

        })
        //delete o.name//delete
        // o.name="Xiaoyi"//Modify
        // for(let k in o){<!-- -->
        // console.log(k,o[k]);//name Andy Lau
        // }//Traverse
        console.log(o);//{name: 'Andy Lau'}
          var person = {<!-- -->
            name: "Wu Yanzu",
        }
        //Give an initial value
        person.age = 0
        // Problem: Directly operating Person and adding attributes to Person may lead to inaccurate values.
        // Hire an agent (secretary)
        var proxy = Object.defineProperty({<!-- -->}, "age", {<!-- -->
            set(val) {<!-- -->
                if (!(val >= 18 & amp; & amp; val <= 50)) {<!-- -->
                    console.log("Illegal value");
                } else {<!-- -->
                    console.log("Value is legal");
                    person.age = val
                }
            },
            get() {<!-- -->
                return `Age${<!-- -->person.age} years old`
            }
        })
        // Reading and writing must go through the proxy
        proxy.age = 22//Set age
        console.log(proxy.age);//Read age
        console.log(person);
2. How many parameters does the viewing method have

Use arguments

3.hasOwnProperty
  1. Arrays are special objects that have the properties and methods of the object’s prototype.

  2. for…in will traverse the properties and methods on the prototype

    solve:

    • If you use Object.prototype.hasOwnProperty for properties and methods on the prototype, it will be false, not true.
  3. for…of will not iterate over the properties and methods on the prototype

    solve:

    • Use Object.keys combined with for…of
Object.prototype.address = "China"
        function Person(name, age, sex) {<!-- -->
            this.name = name,
                this.age = age,
                this.sex = sex
        }
        var p = new Person("Xiaoyi", 22, "female")
        // for..in will traverse to the properties and methods on the parent prototype
        for (let key in p) {<!-- -->
            console.log(key);//name, age, sex,address
        }
        // Solution 1: Use Object.keys combined with for..of
        var keys = Object.keys(p)
        for (let key of keys) {<!-- -->
            console.log(key);//name, age, sex
        }
        // Solution 2: If Object.prototype.hasOwnProperty is a property or method on the prototype, it will be false, not true.
        for (let key in p) {<!-- -->
            // If it is a property or method on the prototype, it is false, not true
            console.log(key,Object.prototype.hasOwnProperty.call(p, key));
            if (Object.prototype.hasOwnProperty.call(p, key)) {<!-- -->
                const el = p[key]
                console.log(el);
               
            }
        }
4.Shallow copy

1. Concept: Except that the first-level addresses are not shared, the addresses at the second level and above are all shared, which is a shallow copy.

2. Object copy method

  1. Object.assign()
  2. {…obj}

3. Shallow copy of array

  1. […arr]
  2. arr.slice(0)
  3. [].concat(arr)
  4. arr.filter((item)=>item)
  5. _.clone(arr) lodash method
 var Person = {<!-- -->
            name: "Lao Liu",
            age: 50,
            children: {<!-- -->
                name: "Xiao Liu",
                age: 20
            }
        }
        // Shallow copy of object
        // method 1 
        // var newPerson=Object.assign({},Person)
        // Method Two
        var newPerson = {<!-- --> ...Person }
        Person.name = "Lao Lao Liu"
        Person.children.name = "Xiao Xiao Liu"
        console.log(Person);
        console.log(newPerson);
        console.log(newPerson === Person);//false
        console.log(newPerson.children === Person.children);//true

        //Array shallow copy
        var arr = ["00", ["11", 22], {<!-- --> id: 1, name: "aa" }, {<!-- --> id : 2, name: "bb" }]
        // var arr1=[...arr]
        // var arr1=arr.slice(0)
        // var arr1=[].concat(arr)
        var arr1 = arr.filter(function(item){<!-- -->
            return item
        })

        arr1[0] = "99"
        arr1[1][0] = "zzz"
        console.log(arr1);
        console.log(arr);
 // Use lodash's clone to implement shallow copy, shallow copy of arrays and objects
        var arr=[11,[22,33],44]
        var arr1=_.clone(arr)
        arr[1][0]="zzzz"
        arr[0]="aaa"
        console.log(arr);
        console.log(arr1);

        var obj={<!-- -->id:1,name:"Andy Lau",children:{<!-- -->id:2,name:"Xiao Xiaoyi"}}
        var obj1=_.clone(obj)
        obj.name="zzzz"
        obj.children.name="ffff"
        console.log(obj);
        console.log(obj1);
Usage of 5.lodash

1Copy lodash.js

.https://www.bootcdn.cn/lodash.js/

2. Open the official website and check the documentation

https://www.lodashjs.com/

6. Deep cloning

1. How to determine the reference type?

1.Object.prototype.toString.call(object name)

? 2.constructor.name

2. How to implement deep cloning?

  1. provided by js

    JSON.stringify and JSON.parse can achieve deep cloning, but methods will be lost

 var p=JSON.parse(JSON.stringify(person0))
  1. Write it yourself

     //------------Write deep clone yourself---------
            var person0 = {<!-- -->
                id: 1,
                name: "Cai Xukun",
                children: {<!-- -->
                    id: 11,
                    name: "Xiao Liu"
                }
            }
            console.log(p);
            function deep(o) {<!-- -->
                let temp;
                if (Object.prototype.toString.call(o).includes("Object")) {<!-- -->
                    temp = {<!-- -->}
                } else if (Object.prototype.toString.call(o).includes("Array")) {<!-- -->
                    temp = []
                }
                for (const key in o) {<!-- -->
                    if (Object.hasOwnProperty.call(o, key)) {<!-- -->
                        // console.log(o[key]);
                        // If it is a reference data type, perform recursion
                        if (typeof o[key] === "object") {<!-- -->
                            temp[key] = deep(o[key])
                            // console.log(deep(o[key]));
                        } else {<!-- -->
                            // If it is a value type, assign it directly
                            temp[key] = (o[key])
                        }
    
                    }
                }
                return temp
            }
            var person1 = deep(person0)
            person0.children.name = "jj"
            // console.log(person0);
            // console.log(person1);
    
            /*
                Array implementation deep cloning
            */
           var arr0=[11,[22,33],44]
           var arr1=deep(arr0)
           arr0[1][0]="hhh"
           console.log(arr0);
           console.log(arr1);
    
  2. Use lodash cloneDeep

 var person2 = {<!-- -->
        id: 1,
        name: "Cai Xukun",
        children: {<!-- -->
            id: 11,
            name: "Xiao Liu"
        }
    }
    var person3 = _.cloneDeep(person2)
    person2.children.name = "mmmm"
    console.log(person2);
    console.log(person3);
7. Closure

1. Concept:

Functions are nested functions. Internal functions can access variables and parameters of external functions. Variables and parameters will not be recycled by the garbage collection mechanism.

2. Benefits of closure

  1. Reduce pollution of global variables
  2. Implement caching

3. Three conditions for forming a closure

  1. function nested function
  2. Leverage scope (local/global)
  3. GC (garbage collection mechanism) will not be recycled if it is used (mark and clear method, reference counting method)

4. Advantages of closure

  1. Save variables so that a variable resides in memory for a long time and will not be released’
 // For outer, a is a local variable
       function outer() {<!-- -->
            var a=100
             // For inner, a is a global variable
             function inner(){<!-- -->
                a+10
            }
            return inner
       }
       var f=outer()
       console.log(f);
8. Throttling and anti-shake

Reduce execution frequency and dilute execution times

? Throttle throttle

 // throttle throttle
       var box = document.querySelector(".box")
        box.onmousemove = throttle(function (e) {<!-- -->
            console.log(e);
            console.log(this);
            console.log(1);
        }, 100)
        // throttle page loading execution
        function throttle(callback, delay = 600) {<!-- -->
            let start = Date.now()
            return function (e) {<!-- -->
                let end = Date.now()
                if (end - start >= delay) {<!-- -->
                    callback.bind(this)(e)
                    console.log(this);
                    console.log(e);
                    //Rewrite the start time of the mark for start
                    start=end
                }
            }
        }

? Anti-shake debounce

 var box = document.querySelector(".box")
        // Anti-shake debounce
        box.onmousemove = debounce(function (e) {<!-- -->
            console.log(e);
            console.log(this);
            console.log(1);
        }, 100)
        function debounce(callback, delay = 600) {<!-- -->
            var timer;
            return function (evt) {<!-- -->
                let self = this
                clearTimeout(timer)
                timer = setTimeout(function () {<!-- -->
                    console.log(this);
                    callback.call(self, evt)
                    // callback.call(self, evt);
                }, delay)
            }
        }

9. Box dragging. (Prototype chain + inheritance + constructor)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {<!-- -->
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
        }

        .boxRed {<!-- -->
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            top: 115px;
        }

        .boxYellow {<!-- -->
            width: 100px;
            height: 100px;
            background-color: yellow;
            position: absolute;
            top: 300px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <div class="boxRed"></div>
    <div class="boxYellow"></div>
    <script>
        // Prototype drag
        function DragBox(cls) {<!-- -->
            this.el = document.querySelector(cls)
        }
        DragBox.prototype = {<!-- -->
            constructor: DragBox,
            dragStart() {<!-- -->
                let self = this
                this.el.onmousedown = function (e) {<!-- -->
                    let disX = e.offsetX
                    let disY = e.offsetY
                    self.dragIng(disX, disY)
                    self.dragEnd()
                }
            },
            dragIng(x, y) {<!-- -->
                let self = this
                document.onmousemove = function (e) {<!-- -->
                    console.log(this);
                    self.el.style.left = e.pageX - x + "px"
                    self.el.style.top = e.pageY - y + "px"
                }
            },
            dragEnd() {<!-- -->
                document.onmouseup = function () {<!-- -->
                    document.onmousemove = document.onmouseup = null
                }
            },
        }
        new DragBox(".box").dragStart()
        // red inheritance
        function DragBoxLimit(el) {<!-- -->
            DragBox.call(this, el)
        }
        DragBoxLimit.prototype = new DragBox;
        DragBoxLimit.prototype.dragIng = function (x, y) {<!-- -->
            let self = this;
            document.onmousemove = function (e) {<!-- -->
                let mX = e.pageX - x
                let mY = e.pageY - y
                if (mX < 0) {<!-- -->
                    mX=0
                }
                if (mY < 0) {<!-- -->
                    mY = 0
                }
                self.el.style.left = mX + "px"
                self.el.style.top = mY + "px"
            }
        }
        new DragBoxLimit(".boxRed").dragStart()
        //yellow inheritance
        function DragBoxLimitText(el) {<!-- -->
            DragBox.call(this, el)
        }
        DragBoxLimitText.prototype = new DragBox;
        DragBoxLimitText.prototype.dragIng = function (x, y) {<!-- -->
            let self = this;
            document.onmousemove = function (e) {<!-- -->
                let mX = e.pageX - x
                let mY = e.pageY - y
                if (mX < 0) {<!-- -->
                    mX=0
                }
                if (mY < 0) {<!-- -->
                    mY = 0
                }
                self.el.style.left = mX + "px"
               
                self.el.style.top = mY + "px"
                self.el.innerHTML = "top:" + self.el.style.top + "<br>left:" + self.el.style.left
            }
        }
        new DragBoxLimitText(".boxYellow").dragStart()
       
    </script>
</body>

</html>

10. Box drag (class)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {<!-- -->
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
        }

        .boxRed {<!-- -->
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            top: 115px;
        }

        .boxYellow {<!-- -->
            width: 100px;
            height: 100px;
            background-color: yellow;
            position: absolute;
            top: 300px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <div class="boxRed"></div>
    <div class="boxYellow"></div>
    <script>
        class box {<!-- -->
            constructor(el) {<!-- -->
                this.el = document.querySelector(el)
            }
            dragStart() {<!-- -->
                let self = this
                this.el.onmousedown = function (e) {<!-- -->
                    let disX = e.pageX-this.el.offsetLeft
                    let disY = e.offsetY
                    self.dragIng(disX, disY)
                    self.dragEnd()
                }
            }
            dragIng(x, y) {<!-- -->
                let self = this
                document.onmousemove = function (e) {<!-- -->
                    console.log(this);
                    self.el.style.left = e.pageX - x + "px"
                    self.el.style.top = e.pageY - y + "px"
                }
            }
            dragEnd() {<!-- -->
                document.onmouseup = function () {<!-- -->
                    document.onmousemove = document.onmouseup = null
                }
            }
        }
        class yellowBox extends box {<!-- -->
            constructor(el) {<!-- -->
                super(el)
                // this.left=e.pageX-e.offsetX
            }
            dragIng(x, y) {<!-- -->
                let self = this
                document.onmousemove = function (e) {<!-- -->
                    console.log(this);
                    self.el.style.left = e.pageX - x + "px"
                    self.el.innerHTML = "left:" + self.el.style.left
                    self.el.style.top = e.pageY - y + "px"
                    self.el.innerHTML = "top:" + self.el.style.top + "<br>left:" + self.el.style.left
                    console.log( self.el.style.left);
                }
            }
        }
        class RedBox extends box {<!-- -->
            constructor(el) {<!-- -->
                super(el)
                // this.left=e.pageX-e.offsetX
            }
            dragIng(x, y) {<!-- -->
                let self = this
                document.onmousemove = function (e) {<!-- -->
                    console.log(this);
                    let mX = e.pageX - x
                    let mY = e.pageY - y
                    if (mX < 0) {<!-- -->
                        mX=0
                    }
                    if (mY < 0) {<!-- -->
                        mY = 0
                    }
                    self.el.style.left = mX + "px"
                  
                    self.el.style.top = mY + "px"

                }
            }
        }
        var b = new yellowBox(".boxYellow")
        var p = new box(".box")
        var r=new RedBox(".boxRed")
        r.dragStart()
        b.dragStart()
        p.dragStart()
    </script>
</body>

</html>

11.tab switching

 var Main = document.querySelectorAll(".main")
    for (var i = 0; i < TabItem.length; i + + ) {<!-- -->
        TabItem[i].onclick = change(i)//change will be executed 4 times
        // console.log(TabItem[i].onclick);
    }
    function change(n) {<!-- -->
        return function (e) {<!-- -->
            for (var i = 0; i < TabItem.length; i + + ) {<!-- -->
                TabItem[i].className = "tab-item"
                // the picture below
                Main[i].className = "main"
            }
            // e.target.className="tab-item active"
            this.className = "tab-item active"
            console.log(this);
            // the picture below
            Main[n].className = "main selected"
        }
    }