JavaScript数组和函数

news2024/11/25 16:50:57

1. 数组

1.1 init

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        两种方式创建数组:
            1. new Array();     (对象)
            2. [1,2,3,4...];    (字面量)
     -->
    <script>
        var array = [1, 2, 'fs', true];    //可以存放任意类型的数据
        console.log(array);
        console.log(array[2]);

        
        array.length = 8;               //手动修改数组长度
        console.log(array);


        var Array = [1,1,3];
        Array[3] = 4;                   //增加了一个元素
        console.log(Array);
        
        
        Array = "Hello World!";         //将原来Array中的元素给全部覆盖了
        console.log(Array);

    </script>
</head>
<body>
    
</body>
</html>

在这里插入图片描述

1.2 数组

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        // var arr = [1,2,3];
        var arr = new Array();
        var arr1 = new Array(2);    //长度为2,为empty*2
        var arr2 = new Array(2, 3);  //分别是2,3
        console.log(arr1);
        console.log(arr2);
        //检测是否为数组
        console.log(arr1 instanceof Array); //way1
        console.log(Array.isArray(arr2));   //way2
        //
        arr.push('hello');  //尾插
        arr.unshift(1);     //头插
        console.log(arr);
        arr.pop();          //尾删
        arr.shift();        //头删
        console.log(arr);
        //
        var Arr1 = ['pink', 'red', 'green'];
        Arr1.reverse();
        console.log(Arr1);

        var Arr2 = [13, 4, 77, 1, 7];
        // Arr2.sort(); //并不是想象中的排序
        // console.log(Arr2); 
        // 如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,
        // 说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,
        // 首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
        var arr = new Array(6)
        arr[0] = "George"
        arr[1] = "John"
        arr[2] = "Thomas"
        arr[3] = "James"
        arr[4] = "Adrew"
        arr[5] = "Martin"
        document.write(arr + "<br />")
        document.write(arr.sort())
        //
        // 请注意,上面的代码没有按照数值的大小对数字进行排序,要实现这一点,就必须使用一个排序函数
        Arr2.sort(function (a, b) {
            return a - b;  //升序
            // return b - a;   //降序
        });
        console.log(Arr2);
        //indexof(),lastindexof()
        //toString()
        var ARR = [1, 2, 3];
        console.log(ARR);               //[1,2,3]
        console.log(ARR.toString());    //1,2,3 ---字符串
        console.log(ARR.join('#'));     //1#2#3 ---字符串
    </script>
</head>

<body>

</body>

</html>

在这里插入图片描述

2. 函数

2.1 函数

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        函数的定义:
            1. 命名函数; 
            2. 匿名函数; 
            3. new Function('arg1', 'arg2', 'arg3'); ( 里面的参数必须都是字符串格式 ) ( 不太常用 )
            4. 所有函数都是Function的实例对象; 
            5. 函数也属于对象; (add instanceof Object)
     -->
    <script>
        //1. 命名函数**********************************************************
        function sum() {
            var sum = 0;
            for (var i = 0; i <= 100; i++) {
                sum += i;
            }
            console.log(sum);
        }
        sum();


        //2. 函数表达式(匿名函数)*************************************************
        var NUM = function (num) {
            console.log('functioal expression!');
            console.log(num);
        }
        NUM(111);


        //3. new Function() ****************************************************
        var f = new Function('a', 'b', 'console.log(a + b)');
        f(999, 1000);
        console.log(f instanceof Object);  // true


        //3. 带参函数************************************************************
        function add(a, b) {
            console.log(a + b);
        }
        add(1, 2); //3
        add(1, 2, 3); //3(多余的参数直接被忽略)
        add(1); //NaN


        //4. 函数返回************************************************************
        //(1)eg1
        function sub(num1, num2) {
            return num1 - num2;
        }
        console.log(sub(3, 5));
        //(2)eg2
        function getArrayMax(arr) {
            var max = 0;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] > max) {
                    max = arr[i];
                }
            }
            return max;
        }
        console.log(getArrayMax([2, 4, 1, 5, 2, 6, 4]));
        //(3)eg3
        function result(num1, num2) {
            return [num1 + num2, num1 - num2, num1 * num2];
        }
        console.log(result(1, 4));


        //5. 嵌套调用************************************************************
        function out() {
            console.log('i am out!');
            In();
        }
        out();

        function In() {
            console.log('i am in!');
        }

        //6. other 
        function test() {}
        console.log(test()); // test()没有return, 则返回undefined
    </script>
</head>

<body>
</body>

</html>

2.2 arguments伪数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        /*
            1. 当我们不确定有多少个参数传递的时候,可以用arguments对象来获取; 
                在JS中,arguments实际上它是当前函数的一个内置对象; 
                [所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参!]
                arguments对象的展示形式是一个[伪数组],因此可以进行遍历;

            2. 作用:有了arguments就不用在函数中写形参了; 

            3. 伪数组具有以下特性:
                1. 具有length属性; 
                2. 按索引方式存储数据; 
                3. 不具有数组的push,pop等方法; 
                4. (1) 正常模式下,arguments对象可以在运行时修改; 
                   (2) 严格模式下,arguments对象是一个只读对象,修改它是无效的,但不会报错; 
        */

        
        function fun() {
            console.log(arguments);
            console.log(arguments.length);
            console.log(arguments[1]);
            for(var i =0 ;i < arguments.length;i++) {
                console.log(arguments[i]);
            }
        }
        fun(1,2,3,4,5);


        /**************************************************************************/
        function max() {
            var max = arguments[0];
            for(var i = 0;i < arguments.length;i++) {
                if(arguments[i] > max) {
                    max = arguments[i];
                }
            }
            return max;
        }
        console.log(max(1,2,3));
        console.log(max(1,2,3,4,5));
        console.log(max(11,21,63,98,21,12));

    </script>
</head>
<body>
    
</body>
</html>

2.3 函数的调用方式

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <!-- 
        函数的调用方式:
            1. 普通函数的调用; 
            2. 对象的方法的调用; 
            3. 构造函数; 
            4. 事件绑定函数; 
            5. 定时器函数; 
            6. 立即执行函数; 
     -->
</head>

<body>
    <script>
        // 1. 普通函数
        function fn() {
            console.log('人生的巅峰');
        }
        fn();   
        fn.call(); 


        // 2. 对象的方法
        var o = {
            sayHi: function() {
                console.log('人生的巅峰');
            }
        }
        o.sayHi();


        // 3. 构造函数
        function Star() {};
        new Star();


        // 4. 绑定事件函数
        // btn.onclick = function() {};   // 点击了按钮就可以调用这个函数


        // 5. 定时器函数
        // setInterval(function() {}, 1000);  这个函数是定时器自动1秒钟调用一次


        // 6. 立即执行函数: 自动调用
        (function() {
            console.log('人生的巅峰');
        })();
    </script>
</body>

</html>

2.4 函数中的this指向问题

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <!-- 
        函数中的this指向问题:
            1. 普通函数的调用;      this指向window; 
            2. 对象的方法的调用;    this指向对象;
            3. 构造函数;            this指向实例对象; 
            4. 事件绑定函数;        this指向调用者, 比如按钮; 
            5. 定时器函数;          this指向window; 
            6. 立即执行函数;        this指向window; 
     -->
</head>

<body>
    <script>
        // 1. 普通函数
        function fn() {
            console.log('人生的巅峰');

        }
        fn();   
        fn.call()


        // 2. 对象的方法
        var o = {
            sayHi: function() {
                console.log('人生的巅峰');

            }
        }
        o.sayHi();


        // 3. 构造函数
        function Star() {};
        new Star();


        // 4. 绑定事件函数
        // btn.onclick = function() {};  


        // 5. 定时器函数
        // setInterval(function() {}, 1000);  


        // 6. 立即执行函数: 自动调用
        (function() {
            console.log('人生的巅峰');
        })();
    </script>
</body>

</html>

2.5 高阶函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        高阶函数:是对其他函数进行操作的函数, 它接收函数作为参数 或 将函数作为返回值输出; 
     -->
</head>
<body>
    <script>
        // 1. 函数作为参数进行传递
        function fun(a, b, callback) {
            console.log(a + b);
            callback && callback();
        }
        fun(1, 2, function () {  
            console.log('last call!');
        }); 
    </script>

    <script>
        // 2. 返回函数
        function Fun() {
            return function(a, b) {
                console.log(a - b);
            }
        }
        var _f = Fun();
        _f(1, 3);
    </script>
</body>
</html>

2.6 值址传递

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        /*
            1. 值传递: 函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是```值传递```; 
                       ```这意味着,在函数体内修改参数值,不会影响到函数外部```; 

                        var num = 2;
                        function f(_num) {
                            _num = 3;
                        }
                        f(num);
                        console.log(num);  // 2
        */


        /*
            2. 址传递:但是,如果函数参数是复合类型的值(```数组、对象、其他函数````),传递方式是```传址传递```; 
                      也就是说,传入函数的是原始值的地址,因此在函数内部修改参数,将会影响到原始值; 

                        var obj = {
                            num: 1
                        };

                        function fff(o) {
                            o.num = 222;
                        }

                        fff(obj);
                        console.log(obj);   // {num: 222}
        */


        /*
            3. 注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值; 
                    下面代码中,在函数test内部,参数对象obb被整个替换成另一个值, 这时不会影响到原始值; 
                    这是因为,形式参数(o)的值实际是参数obb的地址; 
                    重新对o赋值导致o指向另一个地址,保存在原地址上的值当然不受影响; 
        */
        var obb = [1, 2, 3];
        function test(o) {
            o = [4, 5, 6];
        }
        test(obb);
        console.log(obb);   // [1,2,3]
    </script>
</body>

</html>

2.7 改变this指向的三个方法

(1)call()方法

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。
        有时,需要把this固定下来,避免出现意想不到的情况。
        JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。
      -->
    <!-- 
        call(thisValue, arg1,arg2...): 
            1. 调用函数; (add.call();)
            2. 修改函数运行时的this指向; 
     -->
</head>

<body>
    <script>
        // [1.] 函数实例的call方法,可以指定函数内部this的指向,然后在所指定的作用域中,调用该函数。
        var obj1 = {};
        var fun = function () {
            return this;
        };
        console.log(fun() === window); //true
        console.log(fun.call(obj1) === obj1); // true, call方法可以改变this的指向,指定this指向对象obj; 


        // [2.] call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局对象(window)。
        var num = 123;
        var OBJ = {
            num: 456
        };
        function callback() {
            console.log(this);
            console.log(this.num);
        }
        callback.call();                // Window 123
        callback.call(null);            // Window 123
        callback.call(undefined);       // Window 123
        callback.call(window);          // Window 123
        callback.call(OBJ);             // OBJ 456


        // [3.] call的主要作用是实现继承
        function Father(uname, age, sex) {
            this.uname = uname;
            this.age = age;
            this.sex = sex;
        }
        function Son(uname, age, sex) {
            Father.call(this, uname, age, sex);
        }
        var son = new Son('刘德华', 18, '男');
        console.log(son);
    </script>


    <!-- call方法的一个应用是调用对象的原生方法。(后话) -->
    <script>
        var object = {};
        console.log(object.hasOwnProperty('toString')); //false
        object.hasOwnProperty = function () {
            return true;
        };
        console.log(object.hasOwnProperty('toString')); //true
        //使用call调用对象的原生方法
        console.log(Object.prototype.hasOwnProperty.call(object, 'toString')); //false
        //上面代码中,hasOwnProperty是obj对象继承的方法,如果这个方法一旦被覆盖,就不会得到正确结果。
        //call方法可以解决这个问题,它将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。
    </script>
</body>

</html>

(2)apply()方法

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 
        apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。
        唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下。
        func.apply(thisValue, [arg1, arg2, ...])
            第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。
            原函数的参数,在call方法中必须一个个添加,但是在apply方法中,必须以数组形式添加。
     -->
    <script>
        // (0) 初步使用
        function fun(num1, num2) {
            console.log(num1 + num2);
        }
        fun.call(null, 1, 3);
        fun.apply(null, [1, 4]);    //apply() 接受一个数组作为参数, 1、4依次作为fun()函数的参数  


        // (1) 找出数组最大元素
        // JavaScript 不提供找出数组最大元素的函数。结合使用apply方法和Math.max()方法,就可以返回数组的最大元素。
        // Math.max(value1, value2, ...) ; 
        var arr = [10, 2, 3, 45, 1];
        console.log(Math.max.apply(null, arr));     // arr的所有成员依次作为参数,传入max函数, 相当于max(10, 2, 3, 45, 1)
        console.log(Math.max.apply(Math, arr));     // 这样写更为合适


        //(2) 将数组的空元素变为undefined (后话)
        //通过apply方法,利用Array构造函数将数组的空元素变成undefined。
        var array = ['a', , 'b'];
        Array.apply(null, array);
        console.log(array);         // ["a", empty, "b"]
        // 空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined。因此,遍历内部元素的时候,会得到不同的结果。
        var testArray = ['a', , 'b'];
        function print(value) {
            console.log(value);
        }
        testArray.forEach(print);                       // a b => 跳过了空元素
        Array.apply(null, testArray).forEach(print);    // a undefined b 
    </script>


    <script>
        //(3) 转换类似数组的对象 (后话)
        // 另外,利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。
        console.log(Array.prototype.slice.apply({
            0: 1,
            length: 1
        })); //[1]
        console.log(Array.prototype.slice.apply({
            0: 1
        })); //[]
        console.log(Array.prototype.slice.apply({
            0: 1,
            length: 2
        })); //[1,empty]
        console.log(Array.prototype.slice.apply({
            length: 1
        })); //[empty]
        // 上面代码的apply方法的参数都是对象,但是返回结果都是数组,这就起到了将对象转成数组的目的
        // 从上面代码可以看到,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键。

        var _A = new Array();
        console.log(_A);
    </script>
</body>

</html>

(3)bind方法1

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        bind()方法用于改变函数体内this的指向, 然后返回一个新函数; 
        bind()方法不会调用函数, 但是能改变函数内部的this指向; 
        fun.bind(thisArg, arg1, arg2, ...); 
        返回值:返回由指定的this值和初始化参数改造的原函数拷贝; 
     -->
     <!-- 
         何时用?
            如果有的函数我们不需要立即调用, 但是又想改变这个函数内部的this指向, 此时用bind最合适了; 
      -->
</head>

<body>
    <button>点击</button>
    <script>
        var object = {
            name: 'tom'
        }
        function fun(a, b) {
            console.log(this);      // this此时指向object
            console.log(a + b);
        }
        var f = fun.bind(object, 1, 3);
        f();
    </script>

    <script>
        // 我们有一个按钮, 当我们点击了之后, 就禁用这个按钮, 1秒后重新启用; 
        // 法一:注意定时器中的this是window, 所以之前的做法是 var that = this, that.disabled = false;
        // 法二:bind(); 
        var btn = document.querySelector('button');
        btn.onclick = function () { 
            this.disabled = true;
            setTimeout(function() {
                this.disabled = false;
            }.bind(this), 1000);         // 此时定时器内部的this就是btn了 
                                        // 此处bind()函数中的参数可以是btn, 也可以是this, 都是代指btn; 但是this是最好的写法, 因为btn可能随时改变
         }
    </script>
</body>

</html>

(4)bind方法2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 
        bind()方法用于将函数体内的this绑定到某个对象, 然后返回一个新函数; 
        bind()方法不会调用函数, 但是能改变函数内部的this指向; 
        fun.bind(thisArg, arg1, arg2, ...); 
        返回值:返回由指定的this值和初始化参数改造的原函数拷贝; 
     -->
    <script>
        var d = new Date();
        console.log(d.getTime());
        var show = d.getTime;
        // show();         // Uncaught TypeError: this is not a Date object.
        // 上面代码中,我们将d.getTime方法赋给变量show,然后调用show就报错了。
        // 这是因为getTime方法内部的this,绑定Date对象的实例,赋给变量print以后,内部的this已经不指向Date对象的实例了。
        // bind方法可以解决这个问题:
        var print = d.getTime.bind(d);
        print();    //1613100200254
    </script>

    <script>
        // bind方法的参数就是所要绑定this的对象
        var counter = {
            count: 0,
            inc: function() {
                this.count++;
            }
        };
        var func = counter.inc.bind(counter);   //意思是将counter对象的inc方方法绑定到counter对象上,然后赋值给func
        func();
        console.log(counter.count); //1
        // 上面代码中,counter.inc方法被赋值给变量func。
        // 这时必须用bind方法将inc内部的this,绑定到counter,否则就会出错。
    </script>

    <script>
        // bind还可以接受更多的参数,将这些参数绑定原函数的参数。
        var add = function(x,y) {
            return x * this.m + y*this.n;
        };
        var obj = {
            m: 2,
            n: 2
        };
        var newAdd = add.bind(obj,5);
        console.log(newAdd(5));     //20
        // 上面代码中,bind方法除了绑定this对象,还将add函数的第一个参数x绑定成5,
        // 然后返回一个新函数newAdd,这个函数只要再接受一个参数y就能运行了。

        // 如果bind方法的第一个参数是null或undefined,等于将this绑定到全局对象,函数运行时this指向顶层对象(浏览器为window)。
        function sum(x,y) {
            return x + y;
        }
        var plus = sum.bind(null,5);
        console.log(plus(6));   //11
        // 上面代码中,函数add内部并没有this,使用bind方法的主要目的是绑定参数x,
        // 以后每次运行新函数sum,就只需要提供另一个参数y就够了。
        console.log('----------');
    </script>

    <script>
        // bind方法有一些使用注意点:
        //(1) 每一次返回一个新函数;
        
        //(2)结合回调函数使用;
        // 回调函数是 JavaScript 最常用的模式之一,但是一个常见的错误是,将包含this的方法直接当作回调函数。
        // 解决方法就是使用bind方法
        var Counter = {
            count: 0,
            Inc: function() {
                'use strict';
                this.count++;
            }
        };
        function callIt(callback) {
            callback();
        }
        callIt(Counter.Inc.bind(Counter));
        console.log(Counter.count);     //1
        // 上面代码中,callIt方法会调用回调函数。
        // 这时如果直接把counter.inc传入,调用时counter.inc内部的this就会指向全局对象。
        // 使用bind方法将counter.inc绑定counter以后,就不会有这个问题,this总是指向counter。
    </script>

    <script>
        var person = {
            age : 12,
            add: function() {
                this.age++;
            }
        };
      var Fun = person.add.bind(person);
      Fun();
      console.log(person.age);  //13
    </script>
</body>
</html>

(5)call-apply-bind区别

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 
        相同点:都可以改变函数内部的this指向; 
        不通点:
            1. call 和 apply 都会调用函数; 
            2. call 和 apply的区别在于call传递的是arg1, arg2...参数, 而apply传递的参数必须是数组形式; 
            3. bind 不会调用函数; 
        应用场景:
            1. call 经常做继承; 
            2. apply经常跟数组有关系; (比如借助数学对象实现数组最大值最小值) 
            3. bind 不调用函数, 还想改变this指向; (比如改变定时器内部的this指向) 
     -->
</body>
</html>

2.8 函数的递归

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        var num = 1;
        function fn() {
            if (num == 6) {
                return;
            } else {
                console.log('hello');
            }
            num++;
            fn();
        }
        fn();
    </script>

    <script>
        //  求阶乘
        function fun(num) {
            if (num === 1) {
                return 1;
            }
            return num * fun(num - 1);
        }
        console.log(fun(3));
    </script>

    <script>
        // 利用递归遍历数据: 输入id号, 返回对应的数据对象; 
        // 存在重大bug( 后话 )
        var array = [{
            id: 1,
            name: '家电系列',
            goods: [{
                id: 11,
                gname: '冰箱系列',
                goods: [{
                    id: 111,
                    gname: '海尔冰箱'
                }, {
                    id: 112,
                    gname: '美的冰箱'
                }]
            }, {
                id: 12,
                gname: '洗衣机系列',
                goods: [{
                    id: 121,
                    gname: '1类洗衣机'
                }, {
                    id: 122, 
                    gname: '2类洗衣机'
                }]
            }]
        }, {
            id: 2,
            name: '服饰系列'
        }];

        function getId(_array, id) {
            var obj = {}; 
            _array.forEach(function(item) {
                if(item.id === id) {
                    obj = item;
                } else if(item.goods && item.goods.length > 0) {
                    obj = getId(item.goods, id); 
                }
            })
            return obj;
        }
        console.log(getId(array, 1)); 
        console.log(getId(array, 2)); 

        console.log(getId(array, 11)); 
        console.log(getId(array, 111)); 
        console.log(getId(array, 112)); 

        console.log(getId(array, 12)); 
        console.log(getId(array, 121)); 
        console.log(getId(array, 122)); 
    </script> 


    <script>
        function test() {
            return { name: 'XingWei', age: 23} ;
        }
        console.log(test());
    </script>
</body> 

</html> 

2.9 闭包

(1)闭包1

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        1. 闭包: 指 有权访问另一个函数作用域中变量的 函数; 
           首先,闭包也是一个函数; 
        2. 闭包的作用:延伸了变量的作用范围;
           闭包的另一个用处,是封装对象的私有属性和私有方法; 
     -->
</head>

<body>
    <ul class="test">
        <li>hello</li>
        <li>world</li>
        <li>love</li>
        <li>you</li>
    </ul>
    <script>
        // 1. fn就是一个闭包函数; 
        function fn() {
            var num = 10;
            function fun() {
                console.log(num);
            }
            fun();
        }
        fn();
        // 2. 闭包的作用:延伸了变量的作用范围, 此时f()函数也可以使用num变量了! (num是函数中的局部变量, 默认不能在外面访问, 通过闭包延伸了变量的作用域范围)
        function Fun() {
            var num = 20;
            return function() {
                console.log(num);
            }
        }
        var f = Fun();
        f();
    </script>
</body>

</html>

(2)闭包2

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,
        // 因此可以把闭包简单理解成“定义在一个函数内部的函数”。
        // 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
        // 闭包的最大用处有两个,一个是可以读取函数内部的变量,
        // 另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
        function createIncrementor(start) {
            return function () {
                return start++;
            }
        }
        var inc = createIncrementor(5);
        console.log(inc()); //5
        console.log(inc()); //6
        console.log(inc()); //7    //通过闭包,延长了内部变量start的生命周期
        // 上面代码中,start是函数createIncrementor的内部变量。
        // 通过闭包,start的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。
        // 为什么会这样呢?原因就在于inc始终在内存中,而inc的存在依赖于createIncrementor,
        // 因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收。
    </script>

    <script>
        // 闭包的另一个用处,是封装对象的私有属性和私有方法。
        function Person(name) {
            var _age;
            function setAge(n) {
                _age = n;
            }
            function getAge() {
                return _age;
            }
            return {
                name: name,
                setAge: setAge,
                getAge: getAge,
            }
        }
        var p1 = Person('ZhangSan');
        p1.setAge(25);
        console.log(p1.getAge());
        // 上面代码中,函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。
        // 注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,
        // 所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。
    </script>
</body>

</html>

(3)闭包案例

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul class="test">
        <li>hello</li>
        <li>world</li>
        <li>love</li>
        <li>you</li>
    </ul>
    <script>
        // 1. 利用闭包的形式得到当前小li的索引号
        var lis = document.querySelector('.test').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            // 创建4个立即执行函数
            (function (i) {
                lis[i].onclick = function () {
                    console.log(i);
                }
            })(i);
        }

        // 2. 打车案例
        console.log('----------'); 
        var car = (function () {        // 该函数就是闭包
            var start = 13; 
            var total = 0; 
            return {
                price: function (n) {
                    if (n <= 3) {
                        total = start;
                    } else {
                        total = start + (n - 3) * 5;
                    }
                    return total;
                },
                yongdu: function (flag) {
                    return flag ? total + 10 : total;
                }
            }
        })();
        console.log(car.price(5));
        console.log(car.yongdu(false));
        console.log(car.yongdu(true));
    </script>
</body>

</html>

2.10 全局函数

(1)eval()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 
        1. eval() 函数会将传入的字符串当做 JavaScript 代码进行执行; 
        2. eval()是一个全局的函数; 
            语法:eval(string); 
                string: 一个表示JavaScript表达式、语句或一系列语句的字符串。表达式可以包含变量与已存在对象的属性; 
            返回值:返回字符串中代码的返回值。如果返回值为空,则返回 undefined; 
        3. 永远不要使用eval()!!! 它是一个危险的函数!!!
     -->
</head>
<body>
    <script>
        /*
            1. 将字符串当做语句执行; 
                    eval('var a = 1;');
                    console.log(a);             //上面的代码将字符串当做语句执行,生成了变量a
        */
        eval('var a = 1;');
        console.log(a);         // 1


        /*
            2. eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题; 
                    eval('a = 5');              // 此时,已经修改了外部变量a的值,由于这个原因,eval()有风险
                    console.log(a);
        */
        eval('a = 5');      
        console.log(a);    // 5


        /*
            3. 为了防止这种风险,JavaScript规定,如果使用严格模式,eval内部声明的变量,不会影响到外部作用域; 
                    (function(){
                        'use strict';
                        eval('var foo = 456;');
                        // console.log(foo);   // error => foo is not defined
                    })(); 
                上面代码中,函数f内部是严格模式,这时eval内部声明的foo变量,就不会影响到外部; 


                不过,即使在严格模式下,eval依然可以读写当前作用域的变量; 
                    (function() {
                        'use strict';
                        var foo = 1;
                        eval('foo = 2; ');
                        console.log(foo);   // 2
                    })(); 
                上面代码中,严格模式下,eval内部还是改写了外部变量,可见安全风险依然存在; 
                此外,eval的命令字符串不会得到 JavaScript 引擎的优化,运行速度较慢。这也是一个不应该使用它的理由; 
        */
    </script>
</body>
</html>

(2)isNan()

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

<head> 
    <meta charset="UTF-8"> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    <title>Document</title> 
</head> 

<body>
    <script>
        /*
            1. isNan(): 用来判断一个值是否为NaN(not a number); 
        */
        console.log(isNaN(NaN));        // true
        console.log(isNaN(123));        // false
        console.log(isNaN({}));         // true
        console.log(isNaN(['xyz']));    // true

        console.log(isNaN([]));         // false
        console.log(isNaN([123]));      // false
        console.log(isNaN(['123']));    // false
    </script>
</body>

</html>

(3)parseInt()/Float()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
    /* 
        1. parseInt(string): 将字符串转为整数; 
            基本用法:
                1. 如果字符串头部有空格,空格会被自动去除; 
                2. 如果parseInt的参数不是字符串,则会先转为字符串再转换; 
                3. 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符, 
                   就不再进行下去,返回已经转好的部分; 
                4. 如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN; 
                5. 所以,parseInt的返回值只有两种可能,要么是一个十进制整数,要么是NaN; 
                6. 如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析; 
                7. 如果字符串以0开头,将其按照10进制解析; 
            进制转换:
                1.parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数; 
                    默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制; 
    */
        console.log(parseInt('1000', 10)); // 1000
        console.log(parseInt('1000', 2)); // 8
        console.log(parseInt('1000', 6)); // 216
        console.log(parseInt('1000', 8)); // 512


    /* 
        2. parseFloat(): 将一个字符串转为浮点数; 
            基本用法:
                1. 如果字符串符合科学计数法,则会进行相应的转换; 
                2. 如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分; 
                3. parseFloat方法会自动过滤字符串前导的空格; 
                4. 如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN; 
                5. 尤其值得注意,parseFloat会将空字符串转为NaN; 
    */
    </script>
</body>
</html>

3. 面向对象案例完善

请添加图片描述

https://gitee.com/xingweicoding/studys

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/574407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

肉豆蔻酰五肽-8/Myristoyl Pentapeptide-8/sympeptide222

作用机理----肉豆蔻酰五肽-8 随着年龄增大&#xff0c;皮肤逐渐丧失弹性&#xff0c;肌肉功能弱化&#xff0c;而使眼睛周围皮肤松弛形成眼袋。眼睑部位水分的过度积累即眼睑水肿。肉豆蔻酰五肽-8抑制血管紧张素转换酶&#xff0c;增强眼部淋巴循环&#xff0c;促进水分排出 …

vue面试题汇总

vue面试题汇总 1. 谈谈你对MVVM开发模式的理解&#xff1f;2. v-if 和 v-show 有什么区别&#xff1f;3. r o u t e 和 route和 route和router区别4.vue自定义指令5.vue项目优化6.vue模板如何编译7.vue2响应式原理8.vue3响应式原理9.刷新浏览器后&#xff0c;Vuex的数据是否存在…

Go语言的学习【3】常量

目录 注意事项常量常量还可以用作枚举&#xff1a;iota 报错及解决经验和教训 注意事项 如果在相同的代码块中&#xff0c;我们不可以再次对于相同名称的变量使用初始化声明&#xff0c;例如&#xff1a;a : 20 就是不被允许的&#xff0c;编译器会提示错误 no new variables …

【Linux】死锁

文章目录 死锁关于阻塞的理解死锁的四个必要条件避免死锁的方法 死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态 单执行流可能导致死锁问题吗? 可能&#xff01;例如:某一个执行流连续申请了…

类型转换(2)

类型转换 知识回顾static_castconst_castreinterpret_cast 类型转换dynamic_cast动态转换和静态转换区别动态转换的使用 知识回顾 static_cast 静态转换应用范围&#xff1a; 基本数据类型的转换&#xff0c;但不能实现基本数据类型指针的转化&#xff0c;但是可以将无类型转…

Linux 下进行权限修改

查看权限 ls -l 文件名该命令可以查看文件的详细属性&#xff0c;包括文件的权限 权限含义 -rwxrwxrwx在文件系统中&#xff0c;user、group、others的权限是分开的&#xff0c;第一个rwx代表user的权限、第二个rwx代表group的文件、第三个rwx代表others的权限 字符含义值…

真无线蓝牙耳机什么品牌比较好?五大高性价比真无线耳机推荐

与有线耳机相比&#xff0c;无线蓝牙耳机重量轻&#xff0c;便于携带。最重要的是避免了耳机线的麻烦&#xff0c;所以很受当代人的欢迎。什么牌子的蓝牙耳机好&#xff1f;哪个好用&#xff1f;本文中整理了五款市场上高性价比的无线蓝牙耳机&#xff0c;为您提供参考。 第一…

每天一个面试题之final在java中有什么作用?

final在java中有什么作用&#xff1f; final关键字表示最终的含义 当它用来修饰一个引用时&#xff1a; <1>:如果引用为基本数据类型&#xff0c;则该引用为常量&#xff0c;该值无法被修改。<2>:如果引用为引用数据类型&#xff0c;例如&#xff0c;对象/数组等…

使用Nodejs搭建简单的HTTP服务器 - 内网穿透公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 转载自cpolar内网穿透的文章&#xff1a;使用Nodejs搭建HTTP服务&#xff0c;并实现公网远程访问「内网穿透」 前言 Node.…

SSM 如何使用 Saga 机制实现分布式事务?

SSM 如何使用 Saga 机制实现分布式事务&#xff1f; 在分布式系统中&#xff0c;事务管理一直是一个复杂的问题。传统的 ACID 事务只适用于单体应用&#xff0c;随着微服务架构的兴起&#xff0c;分布式事务成为了必须解决的问题。Saga 是一种解决分布式事务问题的机制&#x…

聊聊API 安全

API 安全的现状 随着互联网的高速发展和技术的日趋成熟&#xff0c;人们在享受技术所带来的便利之时&#xff0c;也开始关注技术层面的安全问题。 近年来&#xff0c;应用市场成为各大互联网平台企业的最爱&#xff0c;Facebook、Twitter、新浪微博、微信公众号、抖音等均使用了…

5月面试太难,吃透这份软件测试面试笔记后,成功跳槽涨薪30K

5月开始&#xff0c;生活工作渐渐步入正轨&#xff0c;但金三银四却没有往年顺利。昨天跟一位高级架构师的前辈聊天时&#xff0c;聊到今年的面试。有两个感受&#xff0c;一个是今年面邀的次数比往年要低不少&#xff0c;再一个就是很多面试者准备明显不足。不少候选人能力其实…

ThreadLocal的应用

1. ThreadLocal 是什么 JDK 对ThreadLocal的描述为&#xff1a; 此类提供线程局部变量。这些变量与普通变量的不同之处在于&#xff0c;每个访问一个变量的线程&#xff08;通过其get或set方法&#xff09;都有自己的、独立初始化的变量副本。ThreadLocal 实例通常是类中的私有…

ReentrantLock 和 synchronized 关键字有什么区别?

ReentrantLock 和 synchronized 关键字有什么区别&#xff1f; 在 Java 中&#xff0c;有两种常用的锁机制&#xff1a;ReentrantLock 和 synchronized 关键字。它们都可以用来实现线程同步&#xff0c;但在具体的使用上有一些区别。本文将介绍 ReentrantLock 和 synchronized…

如何用Thanos 和 Prometheus 打造一个高可用的K8S监控系统

概 述 对于弹性伸缩和高可用的系统来说&#xff0c;一般有大量的指标数据需要收集和存储&#xff0c;如何为这样的系统打造一个监控方案呢&#xff1f;本文介绍了如何使用 ThanosPrometheusGrafana 构建监控系统。 集群容量概览 用户故事 直到今年 1 月&#xff0c;我一直在…

C#小项目之记事本

C#小项目之记事本 子窗体设计 frmChild.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; …

第 2 章 Servlet 编程

文章目录 第 2 章 Servlet 编程2.1 Servlet 简介2.2 Servlet 基础2.2.1 用记事本写一个 Servlet2.2.2 Servlet 体系结构2.2.3 Servlet 接口2.2.4 Servlet 生命周期2.2.5 Servlet 生命周期示例 2.3 Servlet API编程常用接口和类2.3.1 GenericServlet 类2.3.2 HttpServlet类2.3.3…

使用object.defineProperty来更新数据示例

Object.defineProperty() 方法会直接在一个对象上定义一个新属性&#xff0c;或者修改一个对象的现有属性&#xff0c;并返回此对象。 Object.defineProperty&#xff08;&#xff09;可以为对象的属性添加特性&#xff0c;每一个被添加过的属性&#xff0c;都会拥有属于自己的…

公司来了个00后,真是卷死了呀,辞职信已经写好了·····

人们都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;三月份春招我们公司来了个00后&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪20K&#xff0c;都快接近我了。 后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡…

chatgpt赋能python:Python单行命令:while

Python单行命令&#xff1a;while 介绍 在Python中&#xff0c;while循环是一种重复执行代码块的结构&#xff0c;只要满足循环条件&#xff0c;就会一直循环下去。而单行命令则是指一行代码就完成了某个任务。在Python语言中&#xff0c;我们可以使用单行命令在 while循环中…