js知识储备

1.函数提升问题

1.1用var 声明的变量 都具有变量提升 会提升到当前作用域的顶部变量会提升 但赋值发生在原地

1.2 函数声明会整体提升,函数表达式的提升规则古河变量提升规则

  console.log(test2); // undefined

        test2();// 报错  赋值发生在原地  此时test2 还不是一个函数 而是undefined 

        var test2 = function() {
            console.log("====test2 ====== ");
        }
        test2();

1.3 函数提升优先于变量提升

       // 解析后的代码如下
         
        // function test3(){
        // }
        // var test3;
        // test3 = 10
        

        此处会报错.......
        var test3 = 10;
        function test3 () {
            console.log("hello world");
        }
        test3();

2.let const 与var的区别

var 不存在块的概念,可以跨块访问变量,但是不能跨域访问变量

2.1.let 拥有块级作用域 2.不存在变量提升 3.不能重复命名 4.可以先声明后赋值

在初始化之前不能访问 c变量

2.2const 常量

​ 1.拥有块级作用域 2.不存在变量提升 3.不能重复命名 4.必须初始化时有值 (即不能先声明后赋值) 5.不能修改常量 否则报错

3.argument 实际上是一个伪数组 可以使用 length属性 可以像数组一样取值 但不能使用数组的API

把伪数组强制转换伪数组对象 Array.from() from 静态方法 必须是Array 大写的调用 console.log(arguments instanceof Array);// false

 function fn4() {
            if (arguments.length === 0) return;
            //  实际上是一个伪数组  可以使用    length属性 可以像数组一样取值  但不能使用数组的API
            // 把伪数组强制转换伪数组对象
            //  Array.from()  from 静态方法 必须是Array 大写的调用
            // console.log(arguments instanceof Array);// false 

            var newArray = Array.from(arguments);
            var max = newArray[0]

            newArray.forEach(function (v) {
                if (v > max) max = v;
            })
            return max;
        }

        console.log("max = ", fn4(1, 2, 21, 1, 3, 45, 34, 3));

4.Array.isArray()与instanceof 的意义

1.Array.isArray()判断一个对象是否为数组 返回值为true 或者 false

let array = [1,2,3,4];

let result = Array.isArray(array);//true·······

  1. instanceof instance 实例(对象)

​ // 判断是否为一个对象

​ var a = {};

​ var b = [1,2];

​ console.log(a instanceof Object);

​ console.log(b instanceof Array);

5.数组常见的api

1.

 var arr = [9,8,4,2,1];
        // includes 包含
        // 参数1: 要查找的值
        // 参数2: 可选的  开始的索引位置  默认从0开始

        // 返回值 true or false
        var result =  arr.includes(8,1);
        console.log("找到了没 == ",result);
2.

 var arr = [9,8,4,2,1,8];
        // indexOf  查找目标元素的第一次出现的索引
        // 找到就返回第一次出现的索引值 找不到则返回-1
        var result = arr.indexOf(1,0);
        console.log("result = ",result)

3.

        // lastIndexOf(8,3) 是倒着数
        var arr = [9,8,4,2,1,8];

        var result = arr.lastIndexOf(8,3);
        
        console.log("result = ====  ",result)
4.

 var arr = [4,5,2,1];
        // 1.
        // push 推  往数组末尾追加
        // 返回的是追加后数组的长度
        // 参数:可以同时追加多个
        let num = arr.push(789);
        // console.log("num = ",num);
        console.log("num = ",arr);
5.

  // 2.unshift 添加到数组的开头
        // 返回的是追加后数组的长度
        // 参数:可以同时追加多个
        let num1 = arr.unshift(100,200);
        console.log("num1 = ",num1);
        console.log("num1 = ",arr);

6.

 // 3.splice 截取和追加   拼接
        // 两个参数时 是截取数组  会改变原数组
        // 参数1: 开始的位置 (包含开始位置)
        // 参数2: 截取的个数   默认从开始位置到结束

        // 返回值: 被截取的内容组成的新数组
        
        var arr = [4,5,2,1];

        // let newArr = arr.splice(1,2);
        // console.log("原数组: ",arr);
        // console.log("新数组: ",newArr);

      
        // 三个参数时 是追加,追加在截取的位置
        var newArr = arr.splice(1, 2, 789, 123, 125);
        console.log("原数组: ", arr); //[4, 789, 123, 125, 1]
        console.log("新数组: ", newArr); // [5, 2]

7.

// 4.pop 弹出  删除数组中最后一个元素
        // 参数:无
        // 返回值 被删除的元素
        var arr = [4,5,2,1];
        var x = arr.pop();
        console.log("原数组: ",arr);
        console.log("x = : ",x);
8.


        // 5.slice 切片
        // 剪切
        // 参数1:start 开始索引 包含
        // 参数2: end  结束的索引 不包含

        // 返回值 被截取的元素 组成的新数组   
        // 不改变原数组
        var arr = [4,5,2,1];
        var newArr = arr.slice(1,2);
        console.log("原数组: ",arr);
        console.log("新数组: ",newArr);
9.

// 6.shift  删除数组中的第一个

        // 参数: 无
        // 返回值 别删除的第一个元素的值
        // 改变原数组
        var arr = [4,5,2,1];
        var x = arr.shift();
        console.log("原数组: ",arr);
        console.log("x   : ",x);

10.

 // 7.join 连接
        // 参数: 可选  字符串  字符串的分隔符
        // 返回值 数组元素组成的字符串 默认以,分隔
        var arr = [4,5,2,1];
        var str = arr.join("xxxx");
        console.log("str= ",str);
        console.log("原数组: ",arr);
11.

   // 8.把数组转换成字符串
        var arr = [4,5,2,1];
        var str = arr.toString()
        console.log("str= ",str);
12.

 // 9.forEach方法
        // 遍历的方法

        var arr = [4,5,2,1];

        // foreach 有一个回调函数 
        // 参数1: 值
        // 参数2: 索引
        // 参数3: 数组本身
        // 记住参数有顺序问题
        arr.forEach(function (v,i,a) {
            console.log(" === v ==",v, "index = ",i ,"array =",a);
        })

//数组高级api
1.

 //1. find 方法
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
        var arr = [1, 5, 8, 10];

        // find方法的参数 是一个函数  测试函数
        // 测试函数 需要返回值的 而测试函数的返回值 为true 或  false
        // find方法 也是有返回值的
        // 数组依赖于测试函数的返回值  如果测试函数返回true     则得到对应value值 如此题为8
        //                       如果测试函数 条件都不满足时  返回false 则返回 undefined的
        var num = arr.find(function (v, i, arr) {
            console.log(" ==== 测试  ====");
            if (v > 5) {
                return true;
            }
            else {
                return false;
            }
        });
        console.log("num = ", num);//8

2.

 // 2. 找索引findIndex
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1var arr = [1, 5, 8, 10];
        // 所有的高级api  其实把函数做为参数进行传递 
        //测试函数的返回值  决定着 高级函数的返回值
        var index = arr.findIndex(function (v, i, array) {
            if (v > 5) {
                return true;
            }
            else {
                return false;
            }
        })
        console.log("==== index === ", index);//2,数组得到对应值的索引

3.//indexOf()
方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-14.// 3. map 映射 
        // map返回一个新的数组
        // foreach map 
        // arr.forEach();方法没有返回值    void空的
        // map  返回一个新的数组
        var arr = [1, 5, 8, 10];
        var newArray = arr.map(function (v, i, array) {
            return v * 10;
        })
        console.log("===== new Array ", newArray);


4.

  //  4.filter 过滤
        //  满足测试函数条件 组成的新数组
        var arr = [1, 5, 8, 10];
        var newArray = arr.filter(function (v, i, array) {
            return v > 5;
        });

        console.log("===== new Array   filter ", newArray);//[8,10]


5.

 // 5.some 一些
     5.1   // 只要测试函数 有一次返回为true some函数即返回为true
        var arr = [1, 5, 8, 10];
        var res = arr.some(function (v, i, array) {
            return v > 5;
        });
        console.log("res some === 0", res);//true
     5.2  
        var arr = [1, 2, 3];
        var bloon = arr.some(v => {
            if (v > 2) {
                console.log(111);
                return true; //注意用some方法如果不写return true;那bloon会一直为false//其实some的意思也就是只要有一次是返回true的那结果就为true
            }
        })
        console.log(bloon); //true

6.

  // 6.every  所有
        // 测试函数 都满足条件时 返回为true  有一个返回为false 则 every函数返回为false,那必然如果不写return是不可以的,但对于箭头函数有时候可以省略return
        var arr = [1, 5, 8, 10];
        var res = arr.every(function (v, i, array) {
            return v >= 1;
        });
        console.log("res 2  every=== ", res);//true
//every函数还可以用来遍历数组,前提是return true;如果哪次遍历的时候返回false则,不执行下面的遍历,可以模拟break和continue;注意在用foreach方法遍历数组的时候里面是不可以写break和continue的会报错1)   arr.every(function(v) {
            if (v == 5) {
                // 当为5的时候跳过
            } else {
                console.log(v);  
            }
            return true;
        })//打印结果为1,8,10除了52)
 arr.every(function(v) {
            if (v == 5) {
                return false;
            }
            console.log(v);
            return true;
        })//执行结果为1,5和5之后的数字将不执行,对于every遇到一次返回值为false执行也就不在继续了
7.数组中用for in的方法遍历数组是支持breakcontinue的,但注意遍历时候的参数index索引是字符串不是数字
for (let index in arr){
    if(index==2){//此时的==为两个=,不能为三个=
        break;
    }
    console.log(index,arr.[index]);
}

7.

  // 7.reduce  聚合 ,根据返回值的特点可以用来求最大小值和求总和
        //测试函数的返回值 会做为下次执行时的previousValue
        // 1.
        var arr = [1, 5, 8, 10];
        var num = arr.reduce(function (previousValue, currentValue, currentIndex, arrray) {
            console.log("previousValue  ", previousValue);
            console.log("currentValue  ", currentValue);
            console.log("currentIndex  ", currentIndex);
            return previousValue + currentValue;
        })
        console.log("num = ", num);//24
  // 2 使用reduce方法实现 找到最大值
        var arr = [101, 53, 108, 123];
        // 测试函数的返回值 会做为下次执行时的previousValue
        var num = arr.reduce(function (previousValue, currentValue, currentIndex, arrray) {
            if(currentValue > previousValue) return currentValue;
            else return previousValue;
        })
        console.log("num = ", num);//123


        // 3 reduce 方法拥有两个参数  
        //   params1: 回调函数
        //   params2: 初始值
        var arr = [1, 2, 3, 4];
        // 测试函数的返回值 会做为下次执行时的previousValue
        var num = arr.reduce(function (previousValue, currentValue, currentIndex, arrray) {
            return previousValue + currentValue;
        },100)
        console.log("num = ", num);//110

8.

 // 8.sort  排序
        // return a - b 是升序
        // return b - a 是降序
        var arr = [101, 53, 108, 123];
        arr =  arr.sort(function (a,b) {
            
            return b-a;
        });
        console.log("排序后的数组 == ",arr)


 






6. Date时间对象


        var date = new Date();
        console.log(date);
      1.  

// 年
        var year = date.getFullYear();

        console.log(year);
     2.

// 月 0- 11  
        var month = date.getMonth();
        console.log(month);

      3.

// 日
        var day = date.getDate();
        console.log(day);

       4.

// 获取 时分秒

        var hours = date.getHours();
        console.log(hours);

        var minutes = date.getMinutes();
        console.log(minutes);

        var seconds = date.getSeconds();
        console.log(seconds);

      5.

// 星期
        // 周日 0  - 6
        var week = date.getDay();
        console.log(" === ", week);

        switch (week) {
            case 0:
                week = "周日";
                break;

            case 1:
                week = "周一";
                break;

            default:
                break;
        }

       6.

// 获得是从 现在距离 1970年1月1日 0 点0分 (世界标准时间  格林威治时间 )  的 总毫米数
       
        console.log(" ===== ",date.getTime());//实例方法

        // 
        console.log("====== ",  Date.now());//静态方法

7.stringAPI

 var str = "helloworld";
        // var str = 'helloworld';

        // 1.获取字符串的长度
        console.log("长度 ===", str.length);

        // 2.遍历一般用for of 取值,用for in 取到的是索引号
        // 没有foreach方法
        // str.forEach(element => {
        //     console.log("element = ",element);
        // });

        for (const v of str) {
            // console.log("====v ==",v);
        }

        // 3.转换大写 小写字母
        var newStr = str.toUpperCase();// 大写
        console.log("new str ", newStr);
        var newStr2 = newStr.toLowerCase();// 小写
        console.log("new str2 ", newStr2);

        // 4.以...开始 或结尾
        var str = "helloworld";

        console.log(str.startsWith("hell", 2));// fasle

        console.log(str.endsWith("d"));// true

        // 5.查找字符的索引,indexOf() 
        console.log(str.indexOf("he"));

        // 6.includes 是否包含
        console.log(str.includes("he"));

        // 7.slice 切片,不改变原字符串的值
        console.log(str.slice(1, 3)); // 包含开始 不包含结束      string没有splice的api

        // 8. split 分隔
        var url = "username=admin&password=123";

        var array = url.split("&");// ['username=admin', 'password=123'],这可以用来把字符串转化为数组,而数组可以用array.join('')转化为字符串
        for (var str of array) {
            var arr = str.split("=");
            for (var value of arr) {
                console.log("截取的值:", arr[1]);
            }
        }
        var url = "username=admin&password=123&gf=3";
        //  limit 限制切成几段
        var array = url.split("&", 2);
        console.log(array);

        // 9.replace 替换
        var str = "hello";
        str = str.replace("el","大头鬼");

        console.log("replace  = ",str);
        // 10.concat 连接
        var a = "a";
        var b = "b";
        var c = a.concat(b);
        console.log("concat  = ",c)

        var c = a.concat(...[1,2,3,4,5,67]);// 传递多个
        console.log("concat  = ",c)

        // 11.charAt 根据索引查找字符
        var str = "abc";

        console.log(" === ",str.charAt(0));

        // 12.charCodeAt() 查找对应字母ASCII码值 A65  a97

        var str = "abc";

        console.log(" === ",str.charCodeAt(0));

        // 13. substring 截取字符串
        var str = "helloworld";
        console.log(str.substring(1,3));//el
        console.log(str);//"helloworld"

        // 14.trim 去除首尾空格
        var str = "     a      b       c                           ";
        str =  str.trim()
        console.log("除去首尾空格 =",str);

8.构造函数的内部原理

1.在函数体最前面隐式的加上this={};其实也不是空对象里面有this ={

–proto–:Person.prototype;指向原型

}

2.执行this.xxx=xxx;

3.隐式的返回this这个对象;

 function Student(name, age, sex) {
            //var this={
            //    name:'';
            //    age:'';
            // }
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.grade = 2019;
            //return this;
        }
        var student = new Student('xicuui', 23, 'meale');

7.包装类

        var str = new String('acc');
        var bol = new Boolean('true');
        var num = new Number(123);
        num.name = 'xx';
        console.log(num);
        //var kong = new Null('null');,报错,undefined和null不可以设置
        // console.log(kong);

1.原始值是不能有属性和方法的;对象可以有(数组,对象本身,函数)

//对于对象
        var arr = [1, 2, 3, 4];
        arr.length = 2;
        console.log(arr); //[1,2]
        //对于原始值 number
        var num = 4;
        num.len = 3; //系统会自动 new Numder(4).len=3;  然后delete
        console.log(num.len); //undefined//因为当你访问的时候,系统会 new Numder(4).len 和上个new Number不是一个,所以并没有赋值,结果为undefined

        //对于原始值string有一点·特殊是string可以访问.length属性

        varstr = 'abcd';
        str.length = 2;// str.length不是可以写的,但是可读
        console.log(str); //'abcd'//系统会new String('abcd').length=2;  delete
        console.log(str.length); //4//系统会new String('abcd').length,然后这个创建的对象字符的长度为4,所以可以出现结果为4
//再来一题
       var str='abc';
       str+=1;
       var test=typeof(str);
       if(test.length==6){
            test.sign='type地返回值'//系统会new String(test).sign='xxx';
            
       }
       console.log(test.sign);//undefined//new String(test).sign因为和双面构造的test对象不是一个对象所以结果为undefined

9.set集合 类似于数组一样的容器 但其值唯一 无序 数组是有序的

var set = new Set([1, 2, 3, 1]);//{1,2,3}
        // set 添加add         array push 
        set.add(20);
        // 删除
        set.delete(10);
        // 清除所有的
        set.clear();
        // 属性的调用 直接对象.属性;   
        // 对象.方法();
        var size = set.size;
        // 检验集合中中是否包含某个值
        var you = set.has(10);
        var set = new Set(["a", "b"]);
        // set 也是可以使用foreach方法的
        set.forEach(function(value1, value2, set) {
            // value1  value2都是指向 集合中的值,没有区别//因为set无序,所以并没有索引号
            console.log("value1 =", value1, "value2 =", value2) //执行结果第一次为a  a 第二次为b  b
        })
        set.forEach(function(value1, set) {
            // 执行的结果为第一次为a,第二次为b
            console.log("value1 =", value1)
        })
        set.forEach(values => {
            
        });//箭头函数时的额写法

        // set 可以通过 es6 提出的 for of 进行遍历
        for (var a of set) {
            console.log("a ==== ", a);
        }

        console.log(set);

10 浅拷贝与深拷贝

 // 3.     ...  展开运算符
        // 浅拷贝 只拷贝指针  两个变量依然指向同一个对象   修改的是同一块内存地址  
        var array2 = ["a","b"];
        var array3 = array2;
        array2[0] = "c";//此时array2和array3都变为['c','b']
        console.log(array3 === array2);

        //  3.1 赋值数组 把数组的每一项 展开另外一个数组中  此处为深拷贝 ,但array2内部的引用类型,依然是浅拷贝
        var array3 = [...array2];
        console.log(array2 == array3); //false
        console.log(array2 === array3); //false
        //虽然两个的值相同数据类型相同但是地址不相同
        array2[0] = "c";
        console.log(array2); //['c','b']
        console.log(array3); //['a','b']

11. 展开运算符的作用

// 3.1合并数组
        var array4 = ["a", "c"];
        var array5 = ["e", "g"];
        var array6 = [...array4, ...array5];
        console.log(array6);
        // 3.2 传递多个参数时使用
        function test(a, b) {

            return a + b;
        }
       var arr=[1,2];

        console.log(test(...arr));//不用写成test(arr[0],arr[1]);

        // 3.3 把字符串转换为数组
        var str = "hello";
        var array7 = [...str];
        ["h", "e", "l", "l", "o"];

        console.log(array7);

11.合并数组的一些方法

//1.合并数组...展开运算符
        var array4 = ["a", "c"];
        var array5 = ["e", "g"];
        var array6 = [...array4, ...array5];
        console.log(array6);
//2..cancat( 不改变原数组。concat合并数组之后,返回值才是新数组,并且可以合并两个及其以上的数组)
    let temparr2 = temparr.concat([7,8])
    console.log(temparr)//[1,2,3,4]
    console.log(temparr2)//[ 1, 2, 3, 4, 7, 8 ]
//3.push.apply( 合并数组是把后一个数组的值依次push进前一个数组,使前一个数组发生改变,并且只能两个数组之间发生合并。)
    let arr1 = [1,2,3,4];
    let arr2 = ['a','b','c','d'];
    arr1.push.apply(arr1,arr2)
    console.log(arr1) //[ 1, 2, 3, 4, "a", "b", "c", "d" ]


11.数组去重的一些方法

1.第一种方式就是最简单的set去重
var arr = [1,2,2,4,3,4,1,3,2,7,5,6,1]
var newArr = new Set(arr)

2.第二种方式就是遍历数组,创建一个新数组,用indexOf来判断新数组中某个数字是否存在
function fn(arr){
   let newArr = []
   arr.forEach((val)=>{
         if(newArr.indexOf(val) == -1){
              newArr.push(val)
          }
    })    
   return newArr  
}    

3.遍历数组,用splice()方式普通去重
for(var i=0;i<arr.length;i++){
    for(var j=i+1;j<arr.length;j++){
         if(arr[i]==arr[j]){
              arr.splice(j,1)
         }
    }
}    

12. for of 是ES6 可以遍历可以迭代即(遍历)的对象 string array set map(字典),对于对象可以用for in遍历,不可以用for of也不可以用foreach

对于字符串用forin的方法得到的是索引号,不可用foreach方法。 而forin遍历数组时,变量为索引值因此遍历数组数尽量使用forof foreach for

 // 注意遍历数组时  变量为其值  
        var index = 0;
        for (const value of[1, 23, 34, 6]) {
            // 可以把index 做为索引值
            index++;
            console.log("iterator = ", value)
        }

        for (const value of "string") {
            console.log("iterator = ", value)

        }

        for (const value of new Set([2, 1, 4, 5])) {
            console.log("iterator = ", value)

        }

//对象遍历
//for in 变量是对象的key
for(var key in obj){
    console.log(obj[key]);
}
//而forin遍历数组时,变量为索引值因此遍历数组数尽量使用forof   foreach   for


13. 获取对象的属性

 // 获取对象的属性
        // 1.对象.property 
        // 2.通过key 获取对象中属性值 一般用于遍历中
        // 1.
        // var name = obj.name;
        // 2.
        // 获取对象中的某个属性的第二种写法
        // 这样的好处是  [key是可以变化的]
        var key = "name";
        var name = obj[key];
        //获取属性为name的值'张三’
        console.log("name = ", name);

        // 3.获取所有的key 和所有值
          //3.1.1
        var keys = Object.keys(obj);//Object.keys() 方法会返回一个由一个给定对象的自身属性组成的数组
        for (var i = 0; i < keys.length; i++) {
            console.log("key = ", keys[i]);
            let key = keys[i];

            console.log("value = ", obj[key])//打印出了所有的值
        }


          //3.1.2
        var val = Object.values(obj); //得到的是关于obj的属性值的数组
        for (var index in keys) {
            console.log(index);

        } //0 1 2 3 4 5 6
        for (var v of val) {
            console.log(v);
        } //数组的每一个值
        //对于数组forof可以获取里面的值,forin获取数组的索引
         

        //3.1.3
        //也可以直接遍历对象
        //for in 变量是对象的key即属性名
        for (var key in obj) {
            console.log(obj[key]);
        }


15.对象的扩充

1.assign方法
// assign 分配 // 把可以枚举的属性从一个对象中合并到目标对象中 返回的是目标对象(会覆盖,是浅拷贝引用数据类型的修改相互之间会影响,基本数据类型不会)
       var target = {
            name: "zs",
            age: 20
        }
        var source = {
            gf: 10,
            age: 10,
            address: "二七区嵩山路街道",
            box: {
                money: 1000,
                card: 5
            }
        }
        var obj = Object.assign(target, source); //注意返回的是改变之后的target
        console.log(target); //{name: 'zs', age: 10, gf: 10, address: '二七区嵩山路街道', box: {money:1000,card:5}}
        source.age = 5; //对于基本数据类型没有浅拷贝这一说。所以此时target里的age是不变的,还是10
        console.log(target); //{name: 'zs', age: 10, gf: 10, address: '二七区嵩山路街道', box: {…}}
        source.box.money = 50; //此时target的money值会改变
        console.log(target); //{name: 'zs', age: 10, gf: 10, address: '二七区嵩山路街道', box: {money:50,card:5}}
        console.log(obj === target);// true


       // 合并数组
        var array = [1, 2, 4, 5, 6];
        // 数组的替换(原因是有覆盖)
        console.log(Object.assign(array, [100, 200, 300]));//[ 100, 200,300, 5, 6]
        //对象之间的覆盖
        var o1 = { x: 1, y: 2, z: 3 };
        var o2 = { y: 4, z: 6 };
        var o3 = { z: 10 }
        var obj = Object.assign({}, o1, o2, o3);  //{x:1,y:4,z:10}
2.//entries  返回的是以键值对组成的数组
 var obj = {
            name:"zhangsna",
            age:20
        }
        var entries = Object.entries(obj);//该静态方法,使obj变为可便利的对象
        console.log(entries)//[[ "name", "zhangsna" ], ["age",20 ]]
3. // 判断是否为同一个对象
        // Object.is() 方法判断两个值是否为同一个对象(地址也要相等)
        console.log(Object.is([1],[1]))//false,因为这是两个[1],地址并不一样


16.创建对象的另一种方式(对象的扩充,密封与冻结)

 1. // 1.创建对象 并配置属性的选项
        // 参数1:指定的原型对象(指定你创建对象的原型)
        // 参数2:属性的配置项
        // Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。
        var obj = Object.create({}, {
            age: {
                value: 123, //值
                writable: false, // 可修改
                configurable: true, // configurable 可配置 删除  默认 false
                enumerable: true // 可枚举(是否可以被遍历出来  默认为 fasle)
            }
        })
        console.log(obj); //{age:123};
2.阻止对象的扩充
  Object.preventExtensions(obj1);
        // 判断一个是否被阻止扩充
        var res = Object.isExtensible(obj1);
3.
  // 3.对象的密封
        // seal 
        // 1.不能添加
        // 2.可以修改 但必须设置 writable true
        // 3.不能删除 (配置为configurable true  也不行)
        var obj2 = Object.create({}, {
            name: {
                value: "三哥",
                writable: true,
                configurable: true
            }
        })
        Object.seal(obj2); // 密封对象

 // 查看对象是否被密封 返回值为bool
        // Object.isSealed(obj2);
4. // 4.冻结
        // 不可以删除 不可以修改  不可增加
        var obj3 = Object.create({}, {
                name: {
                    value: "三哥",
                    writable: true,
                    configurable: true
                }
            })
            // freeze
        Object.freeze(obj3);
  console.log(Object.isFrozen(obj3)) //true

13.什么是深浅拷贝

1.浅拷贝:只是拷贝了源对象的地址,所以源对象的任何值发生改变时,拷贝对象的值也会随之而发生变化。
2.深拷贝:则是拷贝了源对象的所有值而不是地址,所以即使源对象的值发生任何变化时,拷贝对象的值也不会改变。

14. 二维数组

        var arr = [1,2,3];
        // 索引越界 得到的值为undefined  并不会报错
        console.log(arr[3]);//undefined

        // 二维数组 数组中嵌套数组对象
        var array = [[1,2,3],[4,5,6]];
        for (const arr of array) {//第一次遍历得到两个数组
            for (const value of arr) {
                console.log("value = ",value);
            }
        }
        // 从二维数组中取值 
        var num = array[1][2];
        console.log("num = ",num);//6

        // 设置
        array[0][2] = 10;
        console.log(array);

15.JSON 初探

JSON

​ javascript object notation js对象简谱

​ 轻量级的数据格式 一般服务端返回顶数据格式就是json (常用的)

​ xml 可扩展标记语言 也是服务端返回的数据格式

 // JSON数据的格式中不包含数 方法
        // key 必须是字符串
        // json对象如下
        // let jsonObj = "{"name":"三","age":20,"gfs":[{ "name": "lili", "age": 18, "height": 170 }]}"


        // "{"name":"三","age":20,"gfs":[{ "name": "lili", "age": 18, "height": 170 }]}"



        let jsobj = {
            name: '张胜男',
            age: 20,
            gfs: [
                { name: "lili", age: 18, height: 170 },
                { name: "shasha", age: 18, height: 170 },
            ]
        }

        // 1.
        // 把js对象转换为json对象 (字符串)
        // stringify 字符串化
        let jsonstr = JSON.stringify(jsobj);
        console.log(jsonstr);

        console.log(typeof jsonstr);


        // 2.把json 对象转换为 js对象   
        // 为什么要进行解析 ? js对象可以通过 打点调用属性  获取其值
        // parse 解析
        let obj = JSON.parse(jsonstr);
        console.log(obj);

        console.log(typeof obj);

        // 任意进行了一次取值的操作
        console.log(obj.gfs[0].name)


16.引用值之间的赋值与改变

····· //1.基本数据类型

        var a = 1;
        var b = a;
        a = 2;
        console.log(a, b);//2,1


        //2.当obj=obj1时  对象重新赋值对应的obj1的变化

        var obj = {
            name: 'mm',
            sex: 'll'
        }
        var obj1 = obj;
        obj = {
            name: 'll'
        };
        console.log(obj, obj1); //{name: 'll'} {name: 'mm', sex: 'll'}


        //当obj=obj1时  对象取里面属性值改变时对应的obj1的变化
        var obj = {
            name: 'mm',
            sex: 'll'
        }
        var obj1 = obj;
        obj.name = 'oo';
        console.log(obj, obj1); //{name: 'oo', sex: 'll'} {name: 'oo', sex: 'll'}




        //3.当arr=arr1时  数组重新赋值对应的1的变化
        var arr = [1, 2, 3];
        var arr2 = arr;
        arr = [1, 2]; //即重新开创一个空间
        console.log(arr, arr2); //[1,2],[1,2,3]



        //当arr=arr1时  数组取里面值改变值时对应的arr1的变化
        var arr = [1, 2, 3];
        var arr2 = arr; //引用值的赋值,也把地址空间赋值进去了,所以后面一个有改变的时候,另一个也改变,除非重新赋值
        arr2[0] = 4;
        console.log(arr, arr2); //[4,2,3],[4,2,3]
        // arr[0]=4;
        // console.log(arr, arr2); //[4,2,3],[4,2,3]




        //对于原型的改变,赋值时

        Person.prototype.name = 'kk';

        function Person() {

        }
        Person.prototype = {
            name: 'pp'
        }
        var person = new Person();

        console.log(person.name); //pp

        //2

        Person.prototype.name = 'kk';

        function Person() {

        }

        var person = new Person();
        Person.prototype = {
            name: 'pp'
        }

        console.log(person.name); //kk


16.闭包

   闭包: 有权访问另外一个作用域变量的函数 称为闭包(是一个过程,这个过程是 在内部函数访问外部函数变量)
   闭包的作用: 1.变量私有化   2.延长局部变量生命周期
   缺点: 内存泄漏(常驻内存  丢不了 )
 //3.
        function test1() {
            var a = 100;

            return function() {
                a++;
                console.log("a - == ", a);
            }
        }

        var fn2 = test1(); //大函数只执行一次,下面的是小函数执行,那也就产生了一个a后面小函数都是在这一个a操作
        fn2();//101
        fn2();//102

        // 4.
        for (var i = 0; i < btns.length; i++) {
            fn(i); //执行了四次大函数,每
        }
        function fn(a) {
            var num = 0; //每执行一次大函数,都会产生一个新的num,并给对应的 btns[a]的点击事件用,点击一次相应的num++一次
            btns[a].onclick = function() {
                // num++;
                // console.log(num);
                this.innerText = ++num;
            }
        }
        //5.
        var lis = document.querySelectorAll("li")
        for (var i = 0; i < 3; i++) {
            (function(i) {
                lis[i].onclick = function() { //因为点击事件里面用着i所以相应的外部函数的i,不能被释放,与对应的点击事件相对应 如果不写外面的立即执行函数,那么i为全局变量不会产生闭包,最终i为3,所以此时的立即执行函数的作用只是为了传参产生闭包
                    console.log(" i = = ", i);
                }
            })(i)
        }


15.一般用闭包做什么


1.延长局部变量的生命
2.将数据绑定在指令上运行,让指令不再依赖全局数据。一般出现在事件中,使用闭包和立即执行函数来完成
3.全局变量私有化
4.函数的节流
5.传递参数

16.闭包与立即执行函数的深度理解例题

1.for (var i = 0; i < 5; i++) {//for循环里的i是全局变量
  console.log(i);
}
//立即执行 0  1  2 3  4
2.for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000 * i);//注意一点这里1000后面的i是立即执行的
}
 //5  5 5 5 5 隔一秒
3.// 闭包实现
for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);//这里有i引用着外面的i
    }, i * 1000);
  })(i);
}  
//  0  1 2 3 4 5 隔一秒
4.
// 参数i 没得了
for (var i = 0; i < 5; i++) {
  (function() {//形参没有传递i则里面的函数就没有用到立即执行函数里的i,而是用的全局的i,则这里没有产生闭包
    setTimeout(function() {
      console.log(i);
    }, i * 1000);//1000前面的i时全局变量
  })(i);//这个地立即执行函数和没有时一样的
}
//每隔1s执行一次   5 5 5 5 5 

5.for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    console.log(i);
  })(i), i * 1000);//settimeout里的回调函数是立即执行地,且没有返回值则执行之后地结果为undefined,在settimeout里面第一个参数为一个常量不是一个函数地时候,后面设置地时间也无效了
}//此时的写法和上面的1类型差不多
//立即执行 0  1  2  3  4 

17.call/apply/bind

  //1.call的概念和初步理解
        function Person(name, age) {
            this.name = name;
            this.age = age
        } //构造函数如果不new的话,this指向window
        var person = new Person('deng', 100)

        var obj = {};
        Person.call(obj, 'deng', 300); //如果第一个传参为对象,做了一个改变this指向的问题,使Person构造函数的this指向obj,然后后面是传实参值,得到obj为{name: 'deng', age: 300}
        console.log(Person.call(obj, 'deng', 300)); //undefined,因为没有返回值
        console.log(obj); //{name: 'deng', age: 300}
        Person.call(obj);

        //函数执行的时候如果第一个参数不是对象,那么,有call和没有是一样的
        // 如test()和test.call()一样



        //2.call的应用
       
        function Person(name, age, sex) {
            this.mingzi = name;
            this.nl = age;
            this.xb = sex;
        }
        function Student(name, age, sex, tel, grade) {
            Person.call(this, name, age, sex); //相当于写了 this.name=name; this.age=age;this.sex=sex;利用call的作用,此时this指的是new的时候产生的this {}空对象;这样使代码效率提高许多
            this.dh = tel;
            this.jb = grade;
        }
        var student = new Student('sunny', 123, 'male', 139, 2019);
        console.log(student);
//call与apply的区别
1.改变(函数)this指向
2.后面传的参数形式不一样
call需要把实参按照形参的个数传进去
apply需要传一个arguments(一个实参列表,伪数组)
       1.call 立即调用  并传递多个参数  
        hello.call(btn,12,345);
        2. apply 应用   立即执行
        传递两个参数 并且第二个参数为数组对象
        hello.apply(btn,[1,2]);

        3.bind 
        返回一个新的函数   不是立即执行  必须调用才会执行
        var newFn = hello.bind(btn,1,2);

        newFn();




18.原型 原型链

//什么是原型
// JavaScript 中,如果把方法全部定义在构造器中 新建对象中都会包含构造函数中方法  浪费内存。所以在创建一个新的函数地时候,就会根据一种特定地规则为该函数创建一个prototype属性,这个属性指向函数地原型对象。可以说原型是一个对象,存放着新建对象的属性和方法
// 原型  本身就是一个对象   目的: 共享方法 节省内存 
原型之间的关系
以上三者的关系如下

①构造函数Star通过prototype指向Star的原型对象prototype

②Star原型对象prototype通过自身具有的construtor属性指回构造函数Star

③Star创建了对象实例ldh,ldh通过自身具有的__proto__属性指向其原型对象
//什么是原型链
8.//什么是原型链?
访问对象的某一个属性时 ,首先会在该对象本身内部进行查找, 如果没找到 ,会沿着 _proto_向上一层进行查找 一直找到 null 为止 

//原项链  每一个对象都有自己的原型,而原型也是对象,也有自己的原型,依次类推而形成的链式结构就叫做原型链
①拿ldh实例对象来说,//假如ldh需要用到一个方法,ldh会先现在自己的构造函数Star里面找是否有这个方法

②如果Star构造函数里面有这个方法就直接用,没有就根据通过ldh.__proto__找到Star.prototype,看里面有没有这个方法

③有直接用,没有继续往上找到,通过Star.prototype.__proto__找到Object的原型对象prototype,看里面有没有这个方法

④有直接用,没有继续往上找,通过Object.prototype.__proto__找到,发现结果是null,即没有这个方法

1.原型链的终点是什么
由于Object是构造函数,原型链终点是Object.prototype.__proto__,而Object.prototype.__proto__=== null // true,所以,原型链的终点是null
2.constructor是prototype上的属性,所以dog.constructor实际上就是指向Dog.prototype.constructor;constructor属性指向构造函数。constructor是prototype上的属性,这一点很容易被忽略掉。
3.function Person(name) {
    this.name = name
}
var p2 = new Person('king');
console.log(p2.__proto__) //Person.prototype
console.log(p2.__proto__.__proto__) //Object.prototype
console.log(p2.__proto__.__proto__.__proto__) // null
console.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错
console.log(p2.prototype)//undefined p2是实例,没有prototype属性
console.log(Person.constructor)//Function 一个空函数
4. dog instanceof Dog//true


19.在构造函数中,new关键字做了什么

1.创建了一个空对象;
2.将这个空对象的隐式原型_proto_\指向构造函数的显示原型prototype;如例,是将空对象的__proto__成员指向了Base函数对象prototype成员对象;
3.将构造函数的this指向空对象,并调用Base函数;		
var obj  = {}; 
obj.__proto__ = Base.prototype; 
Base.call(obj);  

20.继承发展史==>继承的几种模式


1.传统模式-->原型链//过多的继承了没用的属性
     Grand.prototype.lastName = 'ji';
        function Grand() {
        };
        Father.prototype = new Grand();

        function Father() {
            this.name = 'hehe';
        };
        Son.prototype = new Father();//即构成对象原型的原型,形成链式结构,即为原型链
        function Son() {
        }
        var son = new Son();
2.借用构造函数//1.不能继承和借用构造函数的原型 2.每次构造函数都要多走一个函数(每次都要走两个函数,Person和Student)
      function Person(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        function Student(name, age, sex, grade) {
            Person.call(this, name, age, sex);//利用call()方法,来借用其他构造函数所写的
            this, grade = grade;
        }
        var student = new Student();
3.共享原型//不能随便更改自己的原型
Father.prototype.lastName = 'deng';
        function Father() {
        }
        function Son() {
        }
        function inherit(Target, Origin) {
            Target.prototype = Origin.prototype;//直接让一个构造函数的原型,赋值给另一个构造函数的原型
        }
        inherit(Son, Father);

4. 继承模式---圣杯模式//最终的模式,既能继承父级的原型,又可以更改自己的原型 (使原型链模式和共享模式的结合,且有一个中间变量)

        function inherit(Target, Origin) {
            function F() {};//利用这个中间变量构造函数
            F.prototype = Origin.prototype;
            Target.prototype = new F();//利用原型链的方式,使Target继承F的原型 
            Target.prototype.constuctor = Target;//使 Target.prototype这个原型的构造器归位
        }
        Father.prototype.lastName = 'deng';

        function Father() {
        }
        function Son() {
        }
        inherit(Son, Father);
        var son = new Son;
        var father = new Father;

19.类

        // 类
        // 类具有相同属性和行为的集合 (抽象)
        // 属性 存 数据
        // 行为(方法) 操作  数据
1.  class Person {
            constructor(name, age) { // constructor   构造对象   初始化属性// 主要存放属性
                this.name = name;
                this.age = age;
            }
            play() {
                console.log("乒乓球  父类的方法")
            }
            static num = 0;
            static haHaHa() {
                console.log("父类的静态方法")
            }
        }
        // extends 继承 
        class Man extends Person {
            constructor(name, age, cool) {
                    // 在访问this之前必须调用super函数
                    super(name, age); //调用父类的constructor(name, age)
                    // 特有的属性
                    this.cool = cool; //如果不调用super()方法,子类就得不到自己的this对象。
                }
                //super()表示调用父类的构造方法constructor(),只是调用方法,不构造对象。 super.fun();表示调用父类的某方法 在继承的时候这个方法是肯定被继承下来的。//继承的时候而静态方法也可以从super.fn()上调
            smoke() {
                console.log("抽烟 ---- ");
            }
            play() {
                // super 超级的 指的是父类的对象
                // 用super调用的好处是   保留了父类的功能  又叠加了新功能
                super.play();
                console.log("打篮球  ==== ");
            }
        }
        var man = new Man("张三", 20, "cool");
        console.log(Man.num) //  静态方法只能在当前类上调用,不能被该类的实例对象调用。但是父类的静态方法可以被子类继承。(注意要区分子类和实例使不同的)
2.例子
定义一个类Point()
    数据属性:
        x, x坐标
        y, y坐标
    实例方法:
        moveRight:实现x加1
        moveLeft:实现x减1
        moveUp:实现y减1
        moveDown:实现y加1
    静态方法//静态方法只能在当前类上调用,不能被该类的实例对象调用。但是父类的静态方法可以被子类继承。(注意要区分子类和实例使不同的)如果静态方法包含this关键字,这个this指的是类,而不是实例。(注:静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。)
        计算两点间距离
            参数:两个点
            返回值:两点间距离距离    
 class Point{
            constructor(x,y){
                this.x = x;//this指向new时候的实例
                this.y = y;
            }
            moveRight(){
                this.x++;//谁调用了这个方法,this就指向谁
            }
            moveLeft(){
             this.x--;        
            }
            moveUp(){
                this.y--;        
            }
            moveDown(){
                this.y++;   
            }
            static distance(p1,p2){//属于静态方法,和上面的方法使不同的,不会出现在实例的原型上面,只会在父类上面
                // 逻辑省略
                return  Math.sqrt(Math.pow(Math.abs(p1.x - p2.x),2) + Math.pow(Math.abs(p1.y - p2.y),2));    
            }
        }
        var p1 = new Point(10,20);
        p1.moveUp();
        p1.moveRight();
        p1.moveDown();
        p1.moveLeft();
        var p2 = new Point(300,200);
        Point.distance(p1, p2);//调用父类静态方法的方法

20.手写call()函数 bind()函数

 1.手写call()
// Symbol (标志 )基本数据类型中的一种 是唯一标识  主要是用于对象让属性名不重复
        Function.prototype.mycall = function(obj, ...args) {//不确定传递多少个参数,可以使用展开运算符
            // 判断如果传递为空时 让ctx 等于window 或者 等于nodejs种的全局对象 global
            if (obj == null || ctx == undefined)
                obj = window || global;
            // 因为名称的问题 
            var key = Symbol();//使key是一个独一无二的值,防止和其他变量命名冲突
            ctx[key] = this;//使test()函数作为obj对象内部的一个方法添加进去,这时候该test()就指向ctx
            var result = obj[key](...args);
            delete obj[key];//在原对象中,并没有obj.fn属性,所以我们要将其进行删除。
            return result;// 将执行结果保存,并返回
        }
        var res = test.mycall({
            name: 123,
            key: "哈哈哈"
        }, 20, 40)
        console.log(res);
2.
 // 手写bind
        Function.prototype.mybind = function(ctx, ...abc) {
            console.log(this); // m2
            var _this = this; //bind()不是立即执行函数,需要返回一个函数,为了防止this发生改变
            var key = Symbol("temp")
            return function() {
                console.log("====", this)
                ctx[key] = _this; //改变test()函数的this指向,指向了ctx
                return ctx[key](...abc);
                // 简写
                // return _this.call(ctx,...abc);
            }
        }
        function method2(a, b) {
            console.log(this, a, b)
            return a + b;
        }
        var newFn = method2.mybind({}, 1, 2);

21.正则表达式

1. //用来检索或替换符合规则的文本
2.创建方式
  // 创建正则的对象的方式 
        // 1.字面量 (见名知意)
  var regExp = /abc/;
        // 2.通过new 关键字  
  var regExp = new RegExp(/abc/);// 参数为正则对象
  var regExp = new RegExp("abc");// 参数为正则字符串
  var regExp = new RegExp("abc","gi");// 参数为正则字符串
3.用法
3.1
 //  /abc/ 精确匹配 只要字符串中包含abc 就会匹配到,注意此时的abc是连在一起的如果为abacd也为false
        console.log("====== ", regExp.test("abc"));// true
        console.log("====== ", regExp.test("abcd"));// true
        console.log("====== ", regExp.test("abacd"));// false
3.2
 // 2.[] 模糊匹配  匹配 [...] 中的所有字符中的一个就是true,
        var regExp = /[abc]/;
        console.log("====== ", regExp.test("abc"));// true
        console.log("====== ", regExp.test("a234"));// true
3.3
 // 3  ^写在[]里面 匹配除了 [...] 中字符的所有字符
        var regExp = /[^abc]/;
        console.log("====== ", regExp.test("abc")); // false
        console.log("====== ", regExp.test("a234")); // true//注意检索是一个一个的检索的,此时只要有一个不是a,b,c中的数就是true
3.4
 // 4.
        // [A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母。
        // \d [0-9]  \D [^0-9]  \w [0-9A-Za-z_]  \W[^0-9a-zA-Z_]
        // 匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。
        // . 匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r]。
        var regExp = /[a-z]/;
        console.log("====== ", regExp.test("abc")); // true
        console.log("====== ", regExp.test("a234")); // true
3.5
//^ 边界符  开头   // $ 结尾
 var regExp = /^[a-z]$/;//注意此时匹配到的是a-z中的任意一个字母,不是多个
   console.log("====== ", regExp.test("abc")); // false
   console.log("====== ", regExp.test("a")); // false
3.6
   //  |  或 其中一个
        var regExp = /123|456|789/;
        console.log(" ====== ", regExp.test(123)) // true
        console.log(" ====== ", regExp.test(1234)) // true
        console.log(" ====== ", regExp.test(567)) // false
3.7 
 // 2.分组
        var regExp = /(123|456|789)7/;//有()先看()里面的
        console.log(" ====== ", regExp.test(1237)) // true
        console.log(" ====== ", regExp.test(1234)) // false
3.8  量词
 var str = "正则很麻烦但123需要坚持以456后用直接46464646百度1搜索"
  // + 匹配一次或多次{1,n}
        var regExp = /\d+/g;
        console.log("=============", regExp.test(str)); // true
        console.log("=============", str.match(regExp)); // 

        // * {0,n}//0次的含义是如果匹配的不符合,则返回为'';多次的意思是如果可以匹配会一直匹配,直到匹配不到
        var regExp = /\d*/g;
        console.log("=============", regExp.test(str)); // true
        console.log("=============", str.match(regExp)); // 

        // 一下匹配两次
        var regExp = /\d{2}/g;
        console.log("=============", regExp.test(str)); // true['12','45','46','46','46','46']
        console.log("=============", str.match(regExp)); // 

        var regExp = /\d?/g; //?匹配0次或1次
        var str = "天天下1雨";
        console.log("=============", regExp.test(str)); // true
        console.log("=============", str.match(regExp)); //[ "", "","", "1","",""]
4.正则的使用
  var str = "在哪个激情的夜晚,他和他走在漆黑的路边,吓他妈的我一跳";
        var array = ["激情", '他妈的', "傻逼", "卧槽", "TMD"];
        var regExp = new RegExp(array.join("|"), "gi");//多余多个敏感词的时候
        str = str.replace(regExp, function(value) {//replace方法第二个参数还可以是函数,遍历匹配到的值
            // value 匹配到的字符串
            // var x = "";
            // for (const s of value) {
            //     x += "*"
            // }
            // var str = "*".repeat(value.length);
            return "*".repeat(value.length);
        })

22.模块化


19.值类型与引用类型

  // 数据结构  栈和堆
        // https://blog.csdn.net/qq_44799466/article/details/106074212
        // 1.值类型 存储在栈的数据结构中的   速度快 效率高
        // string number bool null undefined 
        var a = 10;
        var b = "string";
        var c = true;

        // 2.引用类型 Array  Function Object
        // obj 称为对象的引用(指针)    引用是存放在栈中的  而对象本身是存放在堆中
        // 如果需要修改对象的值  通过指针找到对象的内容地址  进行修改其值
        var obj = {
            name: "张三",
            age: 20
        }

        var arr = [1, 2, 3];

        // 3.值传递 和 引用传递
        // 在赋值 或 传参时 把实参赋予形参的过程  称为值传递 引用传递

        // 3.1 值传递  把值copy一份赋值新的变量    a改变时  不影响b变量
        var a = 10;
        var b = a;
        a = 11;
        console.log(" b = ", b); // 10
        function test(num) {
            num = 100;
        }
        test(a);
        console.log("a  === ", a); // 11

        // 3.2 引用传递
        // 新老指针指向同一个对象   修改任何一个 两者的都时相同的
        // 只拷贝指针  不拷贝对象的值(这里可以说基本类型拷贝值,而引用类型拷贝指针不拷贝对象的值)
        var obj = {
            name: "lili",
            age: 18
        }
        var obj2 = obj;
        obj.name = '莎莎';
        console.log("obj2 == ", obj2.name); //莎莎

        ----------------------------

        function test2(obj) {
            obj.name = "四";
        }
        var obj3 = {
            name: "三"
        };
        test2(obj3); //对于形参与实参的引用传递,相当于把实参的指针赋值一份,给形参,此时形参与实参都指向同一个指针
        console.log("obj3 .name = ", obj3.name); // 四


        ------------------------------
        function test(person) {
            person.age = 18;
            person = {//让形参person重新指向一个新的地址
                name: "king",
                age: 45
            }
            return person;
        }
        var p1 = {
            name: "小明",
            age: 20
        }
        var p2 = test(p1);
        console.log(p1); // 小明 18
        console.log(p2); // king 45

20.this指向

 // 1. 全局作用域下  this指向window对象
        console.log(this);
        // 声明的全局变量 默认做为window的属性
        var a = 10;
        console.log(this.a);
        console.log(window.a);
        
        var obj={
            point:this//这个this也指向window
        }

        // 在全局作用域下 尽量避免使用name这个名称
        // this window 可以省略
        console.log(this.b);// undefined 没有给该属性赋值 为undefined的,注意如果不写this时会报错

        function test() {
            console.log("测试一下",this);// window
        }
        window.test();
        this.test();
        test();//直接这样写,前面没有谁调用这个函数时,函数里的this指向window


        // 2.
        // 指向当前方法的调用者
        var obj = {
            name:"张三",
            age:20,
            play(){
                console.log(this.name + "去打篮球");// this -> obj
            }
        }
        obj.play();

        // 3.this指向绑定事件
        var btn = document.querySelector('button');

        btn.onclick = function () {
            console.log(this);// this -> btn对象
        }
        //4.在对象中的this指向
         var obj1 = {
            name:"1111",
            play:function (){
                console.log(this);//指向obj1

                var test = function() {
                    console.log("this == ",this);//此时指向window,这个时候是window调用的这个函数
                }
                test();
            }
        }
        obj1.play();
        

21.箭头函数与箭头函数中的this指向(注意箭头函数的this指向不看是谁调用这个函数,和普通函数不一样)

它是看写这个箭头函数时,当前作用域的this指向谁

1.
// ES6  箭头函数
        // 结构 
        // (参数列表) => {函数体}//写的时候和函数表达式有点像,但没有function
        var test = (a) => {
            console.log(123)
        }
  // 可以简写
        // 一个参数 可以省略 括号,没有参数或者多个参数的时候不可以省略括号
        // 如果有返回值 并且业务逻辑简单 比如一个表达式 可以省略{} 和 return 关键字
        var test4 = a => a + 100;//a+100为箭头函数的返回值
        console.log(test4(19));       
 2.
  //重点: 在箭头函数中 this它总是指向其最近的外层函数作用域的 this 所指对象

  例子     2.1  var btn = document.querySelector('button');
        btn.onclick = () => {
            console.log("this ,", this); // window
        }

       2.2  var obj = {
            name: "zhagnsan",
            age: 20,
            play: function() {
                setTimeout(() => {
                    console.log("第一个this = ", this); // obj
                }, 1000);

                setTimeout(function() {
                    console.log("第二个this = ", this); // window
                }, 1000);
            }
        }
       obj.play();
        2.3 
         var obj1 = {
            name: "zhagnsan",
            that: this,
            age: 20,
            play: () => {
                setTimeout(() => {
                    console.log("第一个this = ", this); // window,  这个时候要看obj1里的this了,obj1里的this指向                                                                                                        window
                }, 1000);//注意一点obj里的this指向window,但是obj里的普通函数里的this指向这个对象

                setTimeout(function() {
                    console.log("第二个this = ", this); // window,他是一个独立的函数体,里面的this指向window
                }, 1000);
            }
        }

        obj1.play();//谁调用了这个函数,函数里面的this就指向谁
        console.log(obj1.that);


22.改变this指向

               // 1.箭头函数
                setTimeout(() => {
                    console.log("改变后的 = ", this); // obj
                }, 1000);
                // 2. 定义临时变量 that
                var that = this;
                setTimeout(function() {
                    console.log("改变后的that = ", that); // obj
                }, 1000);
                // 3. bind  call  apply
                setTimeout(function() {
                    console.log("bind后 = ", this);
                }.bind(this), 1000);

23.事件this的相关指向,对象里·的this

 allInput.onchange = function() {
            console.log(this);
            // 以后使用this之前 一定知道this目前指向的是
            liInputs.forEach(function(el) {
                console.log("this =", this);
               el.checked = this.checked;
            });//方法里面传函数为回调函数,这个函数里的this指向window  (foreach是一个方法,回调函数的this一般指向window   
     
     
     改变放法
            // 1.利用箭头函数改变
             liInputs.forEach((el) => {
                 el.checked = this.checked;//利用箭头函数这里的this指向allInput
            })
            // 2.点击事件中定义that   利用中间变量that
            var that = this;
            liInputs.forEach(function(el) {
                    el.checked = that.checked;
                })
            // 3.利用bind方法
                 liInputs.forEach(function(el) {
                    el.checked = this.checked;
               }.bind(this));//bind()里的this指向当前作用域的this
        }
           
                             
      // 注意:在对象里面有方法即函数,方法里的this指向这个对象,因为只有这个对象才能调用这个方法                            
           function test(obj) {
            console.log(obj.name);
            console.log(obj.age);
            obj.success(10);
        }
        test({
            name: 123,
            age: 20,
            success: function(response) {
                    console.log("this = ", this); //this指向 当前方法传递的对象
                } //在对象里面的函数,函数里面的this‘一般指向这个对象
        })                  
                                                   

24.深浅拷贝

 //深浅拷贝 只针对于引用类型
        // 1.浅拷贝  对内存的地址的复制
        var obj1 = {
            name: "张三",
            age: 20
        }
        var obj2 = obj1;//浅拷贝
        obj1.name = "李四";
        console.log("obj2 .name = ", obj2.name);
        console.log(obj1 === obj2);//true

        // 2.深拷贝 
        // 拷贝对象的具体内容,内存地址市自主分配的
        // 如何实现深拷贝 ?  
        var obj = {
            name: "张三",
            age: 20,
            gf: {
                name: "小绿"
            }
        }
        // 1.JSON中的方法
        // 可以实现多层的深拷贝 
        var jsonobj = JSON.stringify(obj);
        var obj2 = JSON.parse(jsonobj);
        console.log(obj === obj2);//false,因为深拷贝是不同的地址了
        console.log(obj.gf === obj2.gf);//false

        // 2.自定义函数来实现深拷贝 (只拷贝一层),用遍历的方法
        function deepObj(obj) {
            var nObj = {};
            for (const key in obj) {
                nObj[key] = obj[key];//这样可以给一个空对象同时添加了属性,与属性值
            }
            return nObj;
        }
        var obj1 = {
            name: "张三",
            age: 20
        }
        var newObj1 = deepObj(obj1)
        console.log("--------------");
        console.log(newObj1 === obj1);
        //   拷贝数组
        function deepArray(arr) {
            var nArr = [];
            for (const value of arr) {
                nArr.push(value);
            }
            return nArr;
        }
        var array = [1, 2, 3, 4, 5];
        var newArray = deepArray(array);
        console.log(newArray === array);//false
    //3.用递归的方式实现多层深拷贝
   var obj = {
            name: "zhangsna",
            age: 20,
            gfs: [
                { gfname: "lili", hobby: ["篮球", '乒乓球'] },
                { gfname: "shasha", hobby: ["篮球", '乒乓球'] },
            ]
        }

        function deepClone(newObj, oldObj) {
            // key gfs  value = [.....]

            // newObj  {gfs:[hobby:[]]}
            // deepclone([],[.....])
            // 
            for (const key in oldObj) {
                // 判断是不是数组
                if (Array.isArray(oldObj[key])) {//oldObj[key]是属性值并不是属性名
                    newObj[key] = [];
                    deepClone(newObj[key], oldObj[key]);
                }
                else if (oldObj[key] instanceof Object) {
                    newObj[key] = {};
                    deepClone(newObj[key], oldObj[key]);
                }
                else {
                    newObj[key] = oldObj[key];//同时给一个空的对象或数组,添加了属性名和属性值,也会给一个空数组添加                                                 了索引对应的值
                }
            }
            return newObj;
        }

        // 4,实现了深拷贝,lodash中的-clonedeep
        var newObj = deepClone({}, obj);

        console.log(newObj === obj);// false  

25.逻辑 || 与逻辑 &&

image-20220712204946318

26.cookie的理解,如何清除cookie

1.“Cookie是服务端在HTTP响应中附带给浏览器的一个小文本文件,一旦浏览器保存了某个Cookie,在之后的请求和响应中,会将此Cookie来回传递,可以通过Cookie跟踪用户状态,验证用户身份。”

可以手动清除cookie,或者设置cookie数据过期的时间

2.cookie的优点及缺点?
优点:
①.可配置到期时间

②持久性

③不需要任何服务器的资源

缺点:
①.不同浏览器 不能互相访问
②.可能会被用户禁用,删除 
③.不够安全
④.储存空间大概 4kB 左右 

27.常用的CSS3函数有?

1.var()用于插入自定义的属性值。 第一个参数必需,为自定义属性的名称,名称需以 -- 开头;第二个参数可选,为备用值,在属性不存在的时候使用。 
body {
  background-color: var(--main-bg-color, blue);
}

2.calc()用于动态计算长度值。
.box{
  width: calc(100% - 10px);
}

3.rgba()

4.linear-gradient 创造一个线性渐变的图像

28.如何改变一个函数a的上下文?

1.call
2.apply
3.bind

29.什么是回流和重绘及区别?

.回流:
页面中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流
每个页面至少需要一次回流,就是初始化页面
②.重绘
页面中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局
回流必将引起重绘,而重绘不一定会引起回流

30.浅拷贝的方法

1.直接赋值
2. ...展开运算符
3.Object.assign()方法

31.同步任务和异步任务的区别·

1. 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。

32.return

1.一个函数里面的语句,只要遇到了return,就结束该函数的执行语句,不执行后面的了,无论这个return写到了函数的哪里比如if语句里。也结束了该函数的执行语句

     function(valid){
             //console.log(vaild);
              if(!valid) return;                                      
              const {data: res}= await this.$http.post('login',this.loginForm);//对象的结构赋值
              console.log(res);
              if(res.meta.status!==200) return this.$message.error('登录失败');
              this.$message.success('登录成功');
    }

33.请描述js中同步执行的函数和异步执行的函数的区别

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行

34.http协议中请求报文分为?响应报文分为?

1.请求行 请求头 请求体  响应行 响应头 响应体

dom操作

1.获取与设置元素内容如innerHTML

        // 获取div中的内容
        // querySelector() 找到是文档流中第一个元素
       
        var div = document.querySelector("div");
       
        // 1.innerText 内部  获取标签的内容
        // 不包含空格和换行
        var text = div.innerText;
        console.log("text = ",text);

        // 2.textContent内容
        // 保留内容区域的空格和换行
        var text = div.textContent;
        console.log("text =",text);

        // 3.innerHTML 
        //保留内容区域的空格和换行
        // 在获取元素内容时把标签做为内容进行展示,在设置或者添加元素时可以解析标签
        var text = div.innerHTML;
        console.log("text =",text);

        // 4.outerHTML
        // 包含标签的整个文本
        var text = div.outerHTML;
        console.log("text =",text);


        // set
        // 1.
        div.innerText = "1245556 <h1>哈哈哈哈</h1>";
        section.innerHTML = "<input type='text'> <button class='del'> -- </button> <br/>";


        

2.通过 getElementsByClassName获取元素得到的是伪数组,不能使用foreach等方法,可以先转化为数组,但是利用querySelectorall()得到的伪数组可以用foreach遍历,但不能用数组的其他方法,因为不是一个真数组

  var lis = document.getElementsByClassName("li");

        console.log("===lis == ", lis);
        // getElementsByClassName 得到是 伪数组
        // 不能使用forEach
        // 强制转换为数组对象
        // 此处会报错
        // lis.forEach(function (v,i,array) {

        // })
        var colos = ["red", "blue", "yellow"]
        Array.from(lis).forEach(function (el, i) {
            console.log(el);
            el.style.background = colos[i];
        })

3.获取与修改元素自带的属性之className与classList的区别

 var divClass = div.className;
        console.log("clname =", divClass);

        // 通过classname 来修改元素的类名 会覆盖之前的
        // 如果要保留之前的  都拼接上去
        div.className = "green red blue";

        var divClass = div.classList;//classList获得的是类名的一个伪数组(新集和类型的实例),里面有许多方法和属性,比className方便许多
        console.log("clname =", divClass);
//classList的一些方法// add
       div.classList.add("yellow");
        // 删除
       div.classList.remove("red");
        // 删除多个
        div.classList.remove("yellow","green");//删除多个的写法
       div.classList.remove(...["yellow", "green"]);
        // replace 替换
       div.classList.replace("blue", "bigBlue");

        toggle()
        // 如果列表中已经存在给定的值,删除它,如果列表中没有给定的值,添加它


        //div.classList.contains("red");
        // 检查class列表中是否拥有某个值
        // true  or  false
        var contain = div.classList.contains("red");
        console.log(contain)

4.通过api中提供方法 往元素中添加元素(创建一个元素,添加内容·,追加到别的敌方)

  var hh = document.createElement("h2");//创建一个元素
        
        hh.innerText = "我是好男人 好男人就你";//写入内容

        // appendchild 方法只能方 元素节点
       
        document.querySelector("div").appendChild(hh);//注意appendChild里面写的是元素节点,不是字符串

        // append 可以追加多个  并且类型可以字符串  或者 是元素节点
         document.querySelector("div").append("123",hh);

        // 追加到开头的位置  prepend
         document.querySelector("div").prepend(hh);


      

5.占位符··和$占位符与转义符

  模板字符串 ``   ${} 占位符
            str += `
                <div class='box'>
                    <img src="${obj.imgsrc}">
                    <p>${obj.title}</p>
                </div>
            `
            //占位符利可以写变量,模块字符串可以放元素,且可以换行,任意嵌套
            
            
    1.对于字符串遵循外双内单,外单内双
    2.对于单引号 和双引号 都不可以换行 只能通过 + 进行拼接
    3. \ 转义符 把后边特殊符号做为一个普通字符串  或者 转义成换行 制表符健
        \n 换行  \t  4个空格 tab
        var str = "我要送你个\"惊喜\""; 
       // 第一个\ 把第二个\转义成字符串
        var path = "c:\\user\\desktop";
   
            

6.绑定事件的另一种写法

<!-- 绑定事件的另外一种写法    "方法名()"  一定要记得加() -->
    <button onclick="btnclick()">点我</button>

7.利用appendChild()方法,在追加同一个元素时,只能追加一次,解决方法

 //   解决办法1 利用函数的性质

        var box = document.querySelector(".box");
        function insertEl(el,content){
            var element = document.createElement(el);
            element.innerText = content;
            box.appendChild(element);
        }
        insertEl("h2","我是内容");
        insertEl("h2","我是内容");
        insertEl("h2","我是内容");


        // 解决2
        // clone 克隆  node 节点 
        // 参数为true时  才会拷贝一份新对元素对象
        var h3 = document.createElement("h3");
        h3.innerText = "我是h3 ===== ";
        box.appendChild(h3);
        box.appendChild(h3.cloneNode(true));
        box.appendChild(h3.cloneNode(true));

8.往父元素中添加子元素 通过innerHTML的方式 会导致子元素的所有绑定的事件被注销

 1.
        var btn = document.querySelector("button");//子

        var div = document.querySelector("div");//父
        btn.onclick = function() {
            // 往父元素中添加子元素 通过innerHTML的方式  会导致子元素的所有绑定的事件被注销
            div.innerHTML += "<input type='text'> <button> -- </button>"//只执行一次,因为当btn被点击的时候,此代码执行一次,然后点击事件被注销,之后再点击则无效
        }
2.因此在向父级添加元素的时候,可以先建一个子盒子把元素加到子盒子中,就不会有点击事件被注销这一说法了
        btn.onclick = function() {
            var section = document.createElement("section");
            section.innerHTML += "<input type='text'> <button class='del'> -- </button> <br/>"
            div.appendChild(section);
        }


9.添加事件监听

 // p1:触发事件的类型  不能添加on 
        // p2:事件处理函数
        // p3:true or false  如果第三个参数不传递  则默认为冒泡事件流
        // 如果为true 则为捕获事件流
        small.addEventListener("click", function () {
            console.log(" small ======= ");
        });

10.事件委托的本质就是利用事件的冒泡,把原本自己要做的事情交给父元素来处理

案例一
1.当没有利用事件委托的原理
 // var lis = document.querySelectorAll("li");
        var lis = document.getElementsByTagName("li");


        Array.from(lis).forEach(function(li) {
            li.onclick = function() {
                console.log(this.innerText);
            }
        });

        var ul = document.querySelector("ul");
        var four = document.createElement("li");
        four.innerText = "4444444444";
        ul.appendChild(four);
//此时会出出现,后面增加的第四个li则不会执行点击事件,因为绑定事件的时候,并没有第四个li,想要解决这个问题,可以利用事件委托原理吧,事件添加到父元素,因为父元素有这个点击事件,后面不管添加几个li也都属于父元素ul,则第四个li也会又点击事件

2.当有冒泡事件时
如下:  var lis = document.getElementsByTagName("li");
        var ul = document.querySelector("ul");

        ul.onclick = function(e) {
            event.target.style.color = "red"    
        }

        //ul.innerHTML += "<li>444444</li>"; // 会导致事件注销  
        // three.js 处理3D的 
        var four = document.createElement("li");
        four.innerText = "4444444444";
        ul.appendChild(four);//这里的第四个元素是绑定事件之后加地,但由于绑定的事件是冒泡事件,给其父级添加的事件,所以第四个点击的时候里面的元素也会变红

案例二:删除元素
 // 3.可以利用冒泡,给里面的每个子元素添加一些操作,这里不存在闭包什么的了,而且此时还可以避免代码执行顺序的弊端,因为是给父级添加地事件,所以此时子元素不存在也没关系
        main.onclick = function() {
            if (event.target.className === "del") {
                // 1
                // event.target.parentElement.remove();
                // 2.
                main.removeChild(event.target.parentElement);
            }
        }






11.自定义属性

 <!-- 在h5标准中  把自定义属性 以data-开头 -->
    <p myname="superwings">1235456778</p>
    <main data-name="xiaoai" data-my-test="test">hello dom</main>


  ----------获取元素自定义属性-----------------------
1.
        var p = document.querySelector("p");
        console.log(" p 的自定义属性 = ", p.myname); // undefined
        // Attribute 获取自定义属性
        var name = p.getAttribute("myname");//这种p的自定义属性前面没有加data-
        console.log("myname = ", name);
        // 设置自定义属性
        p.setAttribute("myname", "ledi");



2.用dataset方法获取
        var main = document.querySelector("main");
        // 相对麻烦一些
        // console.log(" 自定义属性 = ",main.getAttribute("data-name"));
        // main.setAttribute("data-name","xiaoaitongxue");


        // 获得自定义属性
        console.log(main.dataset.name);
        // 设置自定义属性
        main.dataset.name = "哈哈哈哈";
        //获得自定义属性
        console.log(main.dataset.myTest); // 如果使用多个横线分隔  则使用dataset取值时 采用小驼峰的形式
        console.log(" 自定义属性 = ", main.getAttribute("data-my-test"));


12. window.onload与DOMContentLoaded的区别

  // onload  等待 所有的资源文件 (音视频文件 图片) 和 dom结构加载完毕后执行 onload   
        window.onload = function () {
            var div = document.querySelector("div");
            console.log(div.innerText);
        }
        

        // 只等待dom结构加载完毕后执行
        document.addEventListener("DOMContentLoaded", function () {
            var div = document.querySelector("div");
            console.log(div.innerText);
        })

13.input事件

1.
       // 获取焦点
        // 同一个页面只有一个焦点
        input.onfocus = function () {
            console.log("获取焦点");
            this.style.background = "red";
        }
        // blur 模糊 
        input.onblur = function () {
            console.log("失去焦点");
            this.style.background = "";
        }

        // 获取实时输入的内容
        input.oninput = function (e) {
            // console.log(e.target.value);
        }
2.onchange事件,一般在表单事件中常用

2.1
 input.onchange = function () {
            console.log("内容发生变化 且  失去焦点时执行");//内容发生变化 且  失去焦点时执行
        }
2.2   checkbox.onchange = function() {
            console.log("checkbox  change", this.value); //被绑定的对象选中情况发生变化
        }
2.3  select.onchange = function() {
            console.log("select   === ", this.value); //选中的发生变化
        }

14.鼠标事件

  // 鼠标按下
        // down - up - click
        div.onmousedown = function (e) {
            // 可以进行区分 左右中健
            // 0 左  1 中 2 右
            console.log("鼠标按下", e.button);
        }

        div.onmouseup = function () {
            console.log("鼠标松开");
        }

        // 不会冒泡  enter + leave
        div.onmouseenter = function () {
            console.log("鼠标进入");
        }

        div.onmouseleave = function () {
            console.log("鼠标离开");
        }

        div.onmousemove = function () {
            console.log("移动----");
        }
         // over  + out 会冒泡
        div.onmouseover = function () {
            console.log('div over');
        }
        div.onmouseout = function () {
            console.log('div out');
        }

15.事件解绑的两种方式

1.置空
btn.onclick = null;
2.removeEventListener
 var fn = function () {
            console.log("124");
        }
       注意 // 添加监听器时的回调函数必须写成具名函数 否则无法进行解绑操作
 btn.addEventListener("click", fn);
 btn.removeEventListener("click", fn);

16.删除所有的子元素

 <div>
        <p>1</p>
        <p>2</p>
        <p>3</p>
        <p>4</p>
        <p>5</p>
    </div>
    <script>
        var div = document.querySelector('div')
        //1.动态的 children
        var ps = div.children;//因为·获得的children是动态的所以,后面应该i--,不然会漏删,会剩下2和4
        for(var i = 0;i < ps.length;i++){
            div.removeChild(ps[i]);
            i--;
        }
        //2.getElementsByTagName() 动态的

        var ps = div.getElementsByTagName("p");

        for (var i = 0; i < ps.length; i++) {
            div.removeChild(ps[i]);
             i--;  
        }
        // 3 querySelectorAll  静态的
        var ps = div.querySelectorAll("p");
        for (var i = 0; i < ps.length; i++) {
            div.removeChild(ps[i]);
        }//不需要i--了
        

17.元素的尺寸,元素的位置

 // 获取元素的宽高   不包含滚动条的    高度为可视区域的高 和  window.innerHeight
        // client 客户端
        console.log("html 的 宽 ",document.documentElement.clientWidth);
        console.log("html 的 高 ",document.documentElement.clientHeight);
        console.log("body 的 宽 ",document.body.clientWidth);
        console.log("body 的 高 ",document.body.clientHeight);

        var div = document.querySelector('div');
        // 不包含  border  包含padding   不包含滚动条
        // clientWidth = padding +  w|h - 滚动条
        console.log("div 的 宽 ",div.clientWidth);
        console.log("div 的 高 ",div.clientHeight);

        // offsetWidth = padding +  w|h + border (包含滚动条)
        var section = document.querySelector('section');
        console.log("section 的 宽 ",section.offsetWidth);
        console.log("section 的 高 ",section.offsetHeight);

        // 不包含边框 不包含滚动条  包含 内边距
        // 宽高都是 包含被隐藏的部分
        console.log("section scrollWidth的 宽 ",section.scrollWidth);
        console.log("section scrollHeight 高 ",section.scrollHeight);//包含隐藏部分·


        // !!!!!!!!!!!!
        // 获取元素滚动的距离      元素滚动距离的最大长度=section.scrollHeight(包含隐藏)-盒子的实体高度(可视区域)
        section.onscroll = function () {//元素的滚动条在发生滚动时的事件
             console.log(" =  ",this.scrollTop);
             console.log(" =  ",this.scrollLeft);
         } 
         // 默认 给根元素对象  document.docmentElement.scrollTop 是有值的  而document.body.scrollTop没有值
         // 如果body 和 html 都有滚动条  
         // 谁的滚动条位置发生变化 谁就有值

        window.onscroll = function () {// window即整个页面在滚动的时候发生的事件
            console.log("滑动的高度",window.scrollY);
            console.log("滑动的高度",document.documentElement.scrollTop);
        }
        // 一定要记得
        // 相对于距离它最近的定位为非static 的父元素  如果都没有则相对于 body
        console.log("偏移 量  左 ",section.offsetLeft)//算上滚动的
        console.log("偏移 量  上 ",section.offsetTop);

        

18. 元素的节点

   // children 所有的子元素
        var els = div.children;
        div.children[0] //第一个子元素
        console.log(els)

        var pEl = els[1];

        console.log(pEl.nodeName); // 大写
        console.log(pEl.tagName); // 大写

        // 常用 父元素
        var el = pEl.parentElement;
        var el = pEl.parentNode;

        console.log(el);

        // 获取兄弟节点
        // previous 上一个 Sibling 兄弟 
        // 
        var previous = pEl.previousElementSibling;
        var next = pEl.nextElementSibling;
        console.log(previous, next);


        // 获取的是文本节点 不常用
        var pNode = pEl.previousSibling;
        var nNode = pEl.nextSibling;
        console.log(pNode, nNode);


        // 移除指定的子元素
        // 参数必须为元素节点  
        div.removeChild(pEl);

        // 移除方法的调用者
        div.remove();

18.event对象的补充

 box.onclick = function() {
            // 点击点距离屏幕的位置(整个电脑屏幕)
            console.log('screenX', event.screenX);
            console.log('screenY', event.screenY);
            // // 距离页面的可视区域的,不包含滚动的
            console.log("c = ", event.clientX);
            console.log('clientY)', event.clientY);


            // offsetX 距离自身位置的
             console.log(event.offsetX);
             console.log(event.offsetY);

            // pageY = scrollTop + clientY
            // 当滚动时 位置结果会不相同 
            console.log("p = ", event.pageX);
            console.log(event.pageY);

19.事件的补充 选中和右键复制

       //控制用户是否能选中
        box.onselectstart = function() {
            return false;
        };
        //context 上下文
        //menu 菜单
        //禁止右键
        document.documentElement.oncontextmenu = function () {
            return false;
        }
        //禁止复制
        document.documentElement.onkeydown = function () {
            console.log(event.ctrlKey);

            if((event.ctrlKey &&  event.keyCode === 67)){
                event.preventDefault();
                // alert("禁止复制");
            }
        }

20.对于onscroll事件的兼容性

img
对与window对象几乎每个浏览器都可以使用,所以一般写onscroll事件都写window
document.documentElement对象好多浏览器都不可以使用,不建议用

21.history的用法·页面的跳转

1.History 浏览器的曾经在访问的会话历史记录。
1.1 History.back()
在浏览器历史记录里前往上一页,用户可点击浏览器左上角的返回 (译者注:←) 按钮模拟此方法。等价于 history.go(-1).

1.2 History.forward()
在浏览器历史记录里前往下一页,用户可点击浏览器左上角的前进 (译者注:→) 按钮模拟此方法。等价于 history.go(1).

2.  location.href = "url地址"  ,执行时使浏览跳转到对应的·页面

3.<a href="/delete?id" >删除 </a> 点击的时候使浏览器跳转到对应的页面

22. location.href = “url地址” ,执行时使浏览跳转到对应的·页面

关于优化浏览器性能的手段

1.防抖和节流

1.防抖  利用settimeout 降低事件的执行频率;简单的说,当一个动作连续触发,则只执行最后一次。
(搜索框搜索输入。只需用户最后一次输入完,再发送请求)1//先清除timer 再创建timer
        var timer = null;
        input.oninput = function () {
            clearTimeout(timer);
            // 会影响性能 每次都会执行发送网络请求
            // console.log("发起网络请求");
            timer = setTimeout(() => {
                console.log("发起网络请求");
            }, 1000);

        }2)封装一个函数
        var timer = null;
        input.oninput = function () {//利用这种方法,让里面的函数执行起来,并可以传参
            debounce(function () {
                console.log("发起网络请求")
            }, 1000);
        }
        function debounce(cb, wait) {
            clearTimeout(timer);//如果点击的特别快,不等到wait的时间,那每次都不会执行setTimeout里面的函数,除非你等到wait时间了还没点击就执行setTimeout里的
            timer = setTimeout(() => {
                if (typeof cb == "function") {
                    cb();
                }
            }, wait);
        }
2.函数节流(throttle) 限制一个函数在一定时间内只能执行一次。
(高频点击提交,表单重复提交)
 
// 定义全局变量  bool
        var isStart = true;
        input.oninput = function () {
            if (isStart) {
                isStart = false;
                setTimeout(() => {
                    console.log("发起网络请求");
                    isStart = true;//两秒之后才可以继续执行setTimeout里的,没有这个限制,持续输入内容的时候,持续有定时器触发,两秒之后会有好多定时器积累一起,持续触发
                }, 2000)
            }
        }


2.表格拖拽

  var trs = document.querySelectorAll("tr:not(:first-child)"); //一个选择器,
        var tbody = document.querySelector('tbody')

        trs.forEach((el, index) => {
            el.draggable = true; //要想实现拖拽每个元素都要加上这个属性为true
            el.className = "t" + index;
            el.ondragstart = function() {
                event.dataTransfer.setData("move", this.className); //为后面得到拖拽的元素
            }
        });

        document.documentElement.ondragover = function() {
            event.preventDefault(); //让.ondrop事件里的逻辑执行
        }

        tbody.ondrop = function() {

            // 1.获取拖动的元素
            var cname = event.dataTransfer.getData("move"); //得到被拖拽元素类的名字
            var dragEl = document.querySelector("." + cname); //获取被拖拽的元素
            console.log("dragEl  = ", dragEl);

            // 2.目标元素 (放在谁的身上)
            var targetEl = event.target.parentElement.nextElementSibling; //目标元素在发生.ondrop元素的下面
            console.log("targetEl  = ", targetEl);

            if (targetEl == dragEl) {
                targetEl = event.target.parentElement;
            }
            // 把a插入在b的前面
            // 如果b元素为空  则把a添加在 tbody的末尾
            tbody.insertBefore(dragEl, targetEl);
        }

3.懒加载

<div>
        图片在下面你慢慢往下翻就实现了懒加载
    </div>
    <img src="./img/loading.gif" alt="" data-src="./img/1.jpg">
    <script>
        var img = document.querySelector("img");

        var screenHeight = document.documentElement.clientHeight;
        var imgTop = img.offsetTop;
        window.onscroll = function () {
            var sTop = document.documentElement.scrollTop;
            if(sTop  + screenHeight > imgTop + 500){
                img.src = img.dataset.src;
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值