JS / JQ 学习记录

《一起学前端 之 JS 篇》是记录从 2020.4.29 开始,学习 JS 的收获与感悟。


2020.4.29

数据存储单位

JavaScript介绍

JS是什么

运行在客户端的脚本语言,不是服务器端语言。

JS的组成

JS的作用

浏览器执行JS

JS书写位置

1 行内式JS

2 内嵌JS

3 外部JS

JS常用输入输出语句

注意 prompt 返回的是字符串!

  var name = prompt('请输入您的名字');
  alert(name);

JS变量命名规范

注意 name 虽然不是关键字,也不是保留字,但是一般在浏览器里面有特殊含义,所以最好不要使用它作为变量名。

弱类型语言 & 动态语言

解释型语言 &  编译型语言

概述

执行过程

 

数据类型的分类

JS把数据类型分类两类 基本数据类型( 简单数据类型 / 值类型 ) 复杂数据类型 (引用类型)。

其中简单数据类型包括:Number、String、Boolean、Undefined、Null。

复杂数据类型包括: object(自定义对象、内置对象、浏览器对象)

基本数据类型 在存储时,变量中存储的是值本身;而 复杂数据类型 在存储时,变量中存储的是地址(引用)

基本数据类型

还有一个 symbol

基本数据类型 之 Number

数字型进制

数字型范围

数字型三个特殊值

判断是否是NaN

用方法 isNaN() 判断

基本数据类型 之 String

字符串引号嵌套

字符串的转义

字符串的长度

 var str="my name is andy";
 console.log(str.length);//15

字符串的拼接

var myName='牛牛';
alert('hello' + ' ' + 'world'); //hello world
alert('100' + '100'); //100100
alert('11' + 12); //1112
alert(11 + 11) //22
alert('我的名字叫'+myName);//我的名字叫牛牛
alert('我的名字叫myName');//我的名字叫myName

字符串的不可变性

指的是字符串里面的值不可变,虽然看上去内容可以改变,但其实地址变了,内存中新开辟了一个空间。

如果不断给一个字符串变量赋值,会占用很大的内存

基本数据类型 之 Boolean

console.log(true+1);//2
console.log(false+1);//1

基本数据类型 之 Undefined 和 Null

一个声明后没有被赋值的变量会有一个默认值 undefined

var variable;
console.log(variable);//undefined
console.log('你好'+variable);//你好undefined
console.log(11+variable);//NAN

一个变量声明后给nulll值,里面存的值为空

var vari =null;
console.log('你好'+vari);//你好null
console.log(11+vari);11
console.log(true+vari);//1

2020.4.30

检测变量的数据类型 typeof

typeof 可以用来检测变量的数据类型

var name = '小蜜';
var age = 18;
console.log(typeof name);//string
console.log(typeof age);//number

数据类型转换

转换为字符串型

转换为数字型

console.log(parseInt('3.14'));//3 取整
console.log(parseInt('3.94'));//3 取整
console.log(parseInt('120px'));// 120 
console.log(parseInt('rem120px'));// NaN

console.log(parseFloat('3.14'));//3.14
console.log(parseFloat('120px'));//120
console.log(parseFloat('rem120px'));//NaN

var str='123';
console.log(Number(str));
console.log(Number('12'));

console.log('12'-0);//12
console.log('123'-'120')//3
console.log('123'*1);//123

转换为布尔型

浮点数的精度问题

浮点数的最高精度是17位小数,但在进行算术计算时其精度远远不如整数,因为它会先转为二进制再计算。

console.log(0.1 + 0.2);//0.30000000000000004
console.log(0.07 * 100);//7.000000000000001

此外不要直接判断两个浮点数是否相等,容易出错。

var num = 0.3;
console.log(num == 0.3); //true
num = 0.1 + 0.2; //误差产生
console.log(num == 0.3); //false

递增运算符

注意前置与后置的区别,还有注意 表达式中同时出现一个变量的前置与后置递增 时的情况

        var a = 10;
        ++a;//11
        var b = ++a + 2;//++a 先对a自加1,再返回a
        console.log(b); //14

        var c = 10;
        c++;//11
        var d = c++ + 2;//c++ 先返回c,再对c进行自加1
        console.log(d); //13

        var e = 10;
        //从左往右。先返回e,为10,然后对e进行自加1,得到11;先对e进行自加1,得到12,返回e;实际上等于 10+12=22
        var f = e++ + ++e;
        console.log(f); //22

比较运算符

逻辑运算符

短路运算

运算符优先级

分支流程控制语句 switch

注意 表达式num中的内容 需要跟 case 里面的内容全等(‘===’),才会进入该case执行代码。 

    var num = 1;
        switch (num) {
            case '1':
                console.log(1);
                break;
            case '2':
                console.log(2);
                break;
            case 1:
                console.log('匹配数字1');
                break;
            default:
                console.log('不匹配');
        }

switch 和 if else 的区别

2020.5.2

断点调试

 

1 F12 - sources - 选择文件进行调试

2 单击行号即可为该行设置断点,再次点击可以取消

3 通过右侧工具栏可以在断点之后一步步运行,通过watch可以观察变量变化。

                    

数组

创建数组

1 利用 new 创建数组

        var arr = new Array(); //创建一个空数组
        var arr1 = new Array(2); //创建一个长度为2的空数组
        var arr2 = new Array(2, 3); //等价于数组[2,3]。创建一个数组,它有两个元素,分别为2和3

 2 利用数组字面量创建数组

var arr1 = [];
//数组元素的类型不限
var arr2 = ['小白', 1, true, 28.4];

新增数组元素的最基本方法

1 修改length长度

var arr = [1, 2, 3];
arr.length = 5;//把数组长度改为5
console.log(arr[3]);//undefined
console.log(arr[4]);//undefined

2 新增索引号,追加数组元素

var arr = [1, 2, 3];
arr[3] = 4;
console.log(arr.length); //4
console.log(arr); //1,2,3,4

应用:挑选一个数组中大于等于10的元素出来,放入一个新的数组中

      //方法1 用一个计数变量
        var arr = [2, 0, 6, 1, 77, 0, 52, 10, 25, 7];
        var newArr = [];
        var count=0;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] >= 10) {
                newArr[count] = arr[i];
                count++;
            }
        }
        console.log(newArr);

        //方法2 用 newArr.length 作为索引
        var arr = [2, 0, 6, 1, 77, 0, 52, 10, 25, 7];
        var newArr = [];
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] >= 10) {
                newArr[newArr.length] = arr[i];
            }
        }
        console.log(newArr);

        //方法3 push

新增或删除数组元素的其他方法

var arr = [1, 2, 3];
        arr.push(4);
        console.log(arr); //[1,2,3,4]
        arr.push(5, 6, 7);
        console.log(arr); //[1,2,3,4,5,6,7]
        console.log(arr.pop()); //7
        arr.shift();
        console.log(arr); //[2,3,4,5,6]
        arr.unshift(0);
        console.log(arr); //[0,2,3,4,5,6]

翻转数组 reverse

 var arr = [1, 2, 3, 4, 5];
        arr.reverse();
        console.log(arr);//[5,4,3,2,1]

数组排序 sort

普通的 sort 会按位并按大小进行比较。

带有 比较函数 的sort能按照一定规律进行比较。

  //普通 sort
        var arr = [1, 2, 33, 32, 23];
        console.log(arr.sort()); //[1,2,23,32,33]

        //带有比较函数的sort
        var arr1 = [1, 2, 33, 32, 23];
        arr1.sort(function (a, b) {
            // return a-b;//升序
            return b - a; //降序
        })
        console.log(arr1); //[33, 32, 23, 2, 1]

检测是否为数组

可以使用 instanceof  Array.isArray()。instanceof 与 typeof 的区别是,typeof 最多只能判别变量为对象,但不能判别出具体是什么对象,所以需要用 instanceof 来判别。

 var arr = [1, 2];
        var num = 10;
        console.log(arr instanceof Array); //true
        console.log(Array.isArray(arr)); //true
        console.log(num instanceof Array); //false
        console.log(Array.isArray(num)); //false

数组索引方法

获得数组中元素的索引

 var arr = ['blue', 'pink', 'orange', 'white', 'pink'];
        // 只返回最先匹配的那一个的位置
        console.log(arr.indexOf('pink')); //1
        //只返回最先匹配的那一个,但并不会改变索引的顺序
        console.log(arr.lastIndexOf('pink')); //4 
        //如果元素不在该数组中 则返回 -1
        console.log(arr.lastIndexOf('green')); //-1

 应用案例:数组去重

  var arr = [2, 3, 6, 7, 8, 2, 4, 9, 221, 3];
        var newArr = [];
        for (var i = 0; i < arr.length; i++) {
            if (newArr.indexOf(arr[i]) == -1) {
                newArr.push(arr[i]);
            }
        }
        console.log(newArr); // [2, 3, 6, 7, 8, 4, 9, 221]

数组转换为字符串


 var arr = ['I', 'Love', 'You'];
        console.log(arr.toString()); //I,Love,You
        console.log(arr.join('-')); //I-Love-You
        console.log(arr.join(' ')); //I Love You

2020.5.4

函数参数匹配问题

        function getSum(num1, num2) {
            console.log(num1 + num2);
        }
        //如果实参形参个数匹配,则正常输出结果
        getSum(1, 2); //3
        //如果实参个数>形参个数,则会对号入座,直到取到形参个数为止
        getSum(1, 2, 3); //3
        //如果实参个数<形参个数,则多出的形参会定义为undefined,形参可以看做是不用声明的变量
        getSum(1); //NaN

函数 return 注意事项

1 函数 return 只能返回一个值。如果 return 多个由逗号分隔的值,则只返回最后一个值。

        function fn(num1, num2) {
            return num1, num2;
        }
        console.log(fn(1, 2)); //2

2 如果没有 return 则返回 undefined

        function fn(num1, num2) {

        }
        console.log(fn(1, 2)); //undefined

break continue return 的区别

break 结束当前循环体

continue 跳出本次循环,继续执行当前循环体的下次循环

return 退出循环,并返回值

arguments的使用

arguments 是 伪数组,它具有 length 属性,可按照 索引 的方式进行存储,但它没有真正数组的一些方法,比如 pop()、push()等。

        function fn() {
            console.log(arguments); //[1,2,3,4,5]
            console.log(arguments.length); //5
            console.log(arguments[2]); //3
        }
        fn(1, 2, 3, 4, 5);

应用:

        function getMax() {
            var max = arguments[0];
            for (var i = 1; i < arguments.length; i++) {
                if (arguments[i] > max) {
                    max = arguments[i];
                }
            }
            return max;
        }
        console.log(getMax(1, 2, 3, 4, 6, 7, 8, 9, 111, 110)); //111

2020.5.5

定义函数的三种方式

函数式声明

function fun() {
    console.log("函数式声明");
}

函数表达式

var fun2 = function() {
    console.log("函数表达式");    
}

new Function()

    var fn = new Function('a', 'b', 'console.log(a+b)');
    fn(1, 2);//3

全局变量 & 局部变量

1 在函数内部没有声明直接赋值的变量,属于全局变量(但是函数必须被调用,该变量才能创建)

2 函数的形参可以看做是局部变量

        function fun(aru) {
            var num1 = aru;
            num2 = 20;
        }
        fun(29);//调用fun,才有全局变量num2
        // console.log(aru); //error
        console.log(num2); //20

作用域链

内部函数访问外部变量时,采取链式查找的方式来决定取哪个值,类似于就近原则

        var num = 10;

        function fun1() {
            var num = 20;

            function fun2() {
                console.log(num);//20
            }
            fun2();
        }
        fun1();

JS 预解析

js引擎运行js分为两步:预解析 代码执行 。

预解析 分为 变量提升变量预解析) 和 函数提升函数预解析)

变量提升,就是把所有的变量声明提升到当前作用域最前面,不提升赋值操作

函数提升,就是把所有函数声明提升到当前作用域最前面,不调用函数

预解析 时,js引擎会把js里面的所有 var function 声明,提到当前作用域的最前面。

而 代码执行 时,按照代码书写顺序从上往下执行。

        //案例1
        console.log(num); //undefined
        var num = 10;
        
        //案例2
        fn(); //11
        function fn() {
            console.log(11);
        }
        
        //案例3
        fun(); //报错,fun is not a function
        var fun = function () {
            console.log(22);
        }
        
        //案例4
        var num = 10;
        fun();

        function fun() {
            console.log(num);
            var num = 20;
        }
        //--------相当于执行了以下代码
        var num;

        function fun() {
            var num;
            console.log(num);
            num = 20;
        }
        num = 10;
        fun(); //undefined

创建对象的三种方式

用对象字面量创建对象

属性 或 方法 采用 键值对 的形式,即 属性名: 属性值 

使用对象属性有两种方法:

1 对象名.属性名

2 对象名['属性名']

删除对象属性的方法:

delete 对象名.属性名;

var obj = {
            name: 'Json',
            age: 18,
            sex: 'man',
            sayHi: function () {
                console.log('hi');
            }
        }

    <script>
        const name = 'lily';
        const age = 18;
        const sex = 'man';
        const obj = {
            name,
            age,
            sex,
            say() {
                console.log('hello');
            },
        }
        console.log(obj);
        obj.say();
    </script>

用 new Object 创建对象

   var obj = new Object();
        obj.name = '张三疯';
        obj.age = '18';
        obj.sex = '男';
        obj.sayHi = function () {
            console.log('hi~');
        }

用 构造函数 创建对象

使用 构造函数 可以减少重复的代码

1 构造函数的首字母要大写

2 调用构造函数必须要用 new

3 构造函数的属性和方法前面必须添加 this

    function Star(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.sing = function (song) {
                console.log(song);
            }
        }
        var Json = new Star('Json', 17, 'man');
        console.log(Json.name); //Json
        console.log(Json.age); //17
        console.log(Json.sex); //man
        Json.sing('happy'); //happy

new 关键字

new 在执行时会做四件事情:

1 在内存中创建一个新的空对象

2 让构造函数的this指向这个新对象

3 执行构造函数里面的代码,给这个新对象添加属性和方法

4 返回这个新对象(所以构造函数里面不需要 return )

for in 遍历对象

语法 for(变量 in 对象){}

 var obj = {
            name: 'JSON',
            age: 29,
            sex: 'man',
            fn: function () {
                console.log('hello');
            }
        }
        for (var k in obj) {
            console.log(k);//k 输出得到的是属性名
            console.log(obj[k]);//obj[K] 输出得到的是属性值
        }

总结 :

for in 得到对象的key 或 数组、字符串的索引 ,

而 for of 和 forEach 一样,是直接得到值,但是 for of 不能对象用。

内置对象

内置对象 是 js 自带的一些对象,供开发者使用,提供了一些常用的功能。比如 MathDateArrayString 等。

Math 对象

Math 对象不是构造函数,它具有数学常数和函数的属性与方法。

        //绝对值方法
        console.log(Math.abs(1)); //1
        console.log(Math.abs(-1)); //1
        console.log(Math.abs('-1')); //隐式转换 1
        console.log(Math.abs('Json')); //NaN

        //取整方法 floor 向下取整
        console.log(Math.floor(1.1)); //1
        console.log(Math.floor(1.9)); //1

        //取整方法 ceil 向上取整
        console.log(Math.ceil(1.1)); //2
        console.log(Math.ceil(1.9)); //2

        //取整方法 round 四舍五入取整 但是.5特殊,会往“大”的方向取整
        console.log(Math.round(1.5)); //2
        console.log(Math.round(1.1)); //1
        console.log(Math.round(1.9)); //2
        console.log(Math.round(-1.1)); //-1
        console.log(Math.round(-1.5)); //-1

Math.random() 随机数

该函数返回一个伪随机浮点数,范围在 [ 0 ,1),即大于等于0,小于1(不包括1),我们可以将随机数的范围缩放到所需要的范围。

//返回一个 [ 0,1 ) 之间的随机数
 function getRandom() {
            return Math.random();
        }
        console.log(getRandom());
//返回一个 [min,max) 之间的随机数
function getRandom(min, max) {
            return Math.random() * (max - min) + min;
        }
        console.log(getRandom(10, 20));
  //得到一个两数之间的随机整数,包括两个数在内 
function getRandomInt(min, max) {
            min = Math.ceil(min);
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }

为什么计算机时间要从1970年1月1日开始算起 

最初计算机操作系统是32位,而时间也是用32位表示。

System.out.println(Integer.MAX_VALUE);//2147483647

Integer 在JAVA内用32位表示,因此32位能表示的最大值是2147483647。另外1年365天的总秒数是 31536000,2147483647/31536000 = 68.1,也就是说32位能表示的最长时间是68年,从1970年开始的话,加上68.1,实际最终到2038年01月19日03时14分07秒,便会到 达最大时间,过了这个时间点,所有32位操作系统时间便会变为10000000 00000000 00000000 00000000,算下来也就是1901年12月13日20时45分52秒,这样便会出现时间回归的现象,很多软件便会运行异常了。

到这里,我想问题的答案已经显现出来了,那就是:因为用32位来表示时间的最大间隔是68年,而最早出现的UNIX操作系统考虑到计算机产生的年代和应用的 时限综合取了1970年1月1日作为UNIX TIME的纪元时间(开始时间),至于时间回归的现象相信随着64为操作系统的产生逐渐得到解决,因为用64位操作系统可以表示到 292,277,026,596年12月4日15时30分08秒,相信我们的N代子孙,哪怕地球毁灭那天都不用愁不够用了,因为这个时间已经是千亿年以后了。

Date 对象

Date对象 用来处理日期时间。它和Math对象不一样,它是一个构造函数,需要实例化后才能使用。

获取当前时间

//Date 获取当前时间
var now = new Date();
console.log(now); //Wed May 06 2020 18:03:17 GMT+0800 (中国标准时间)

获取特定时间 

 //获取特定时间
var now = new Date('2019-5-6');
console.log(now); //Mon May 06 2019 00:00:00 GMT+0800 (中国标准时间)

获取时间的指定部分

可以通过获取时间的指定部分,拼接成自己想要的日期格式

案例:返回当前时间 格式 xx:xx:xx

 function getTimer() {
            var date = new Date();
            var hour = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
            var min = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
            var sec = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
            return hour + ':' + min + ':' + sec;
        }
        console.log(getTimer());

获取日期的总毫秒数 形式

Date对象 是基于1970年1月1日(世界标准时间)开始算的,可以通过 valueOf()getTime() 方法获取距今的总毫秒数,所得到的时间戳是独一无二的。

        //通过 valueOf() getTime()
        var date = new Date();
        console.log(date.valueOf());
        console.log(date.getTime());

        //简单写法
        var date1 = +new Date(); //+new Date() 返回总毫秒数
        console.log(date1);

        //H5 新增写法
        console.log(Date.now());

案例:倒计时写法

因为得到的 date 不能直接进行相加减,所以需要用到时间戳。预设时间 减去 当前时间,得到相差毫秒数,将相差毫秒数除以1000得到相差秒数,然后分别进行除法求余运算得到各个单位的数值。

 function countDown(time) {
            var nowTime = +new Date(); //获取当前时间
            var inputTime = +new Date(time); //获取预设时间
            var times = (inputTime - nowTime) / 1000; //换算单位 ms -> s
            var d = parseInt(times / 60 / 60 / 24); //得到天数
            d = d < 10 ? '0' + d : d;
            var h = parseInt(times / 60 / 60 % 24); //得到时
            h = h < 10 ? '0' + h : h;
            var m = parseInt(times / 60 % 60); //得到分
            m = m < 10 ? '0' + m : m;
            var s = parseInt(times % 60); //得到秒
            s = s < 10 ? '0' + s : s;
            return d + '天' + h + '时' + m + '分' + s + '秒';
        }
        console.log(countDown('2020-5-6 21:19:00')); //00天00时00分51秒

2020.5.7

基本包装类型

基本包装类型 就是把简单数据类型包装为复杂数据类型,这样基本数据类型就有了属性和方法。

为了方便操作基本数据类型,JS提供了三个特殊的引用类型:StringNumber Boolean

字符串对象

字符串所有的方法都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。

根据字符返回位置

  var str = '改革春风吹满地,春天到啦';
        console.log(str.indexOf('春')); //2
        console.log(str.indexOf('春', 3)); //8

案例:查找字符串中某个字符出现的次数

   var str = 'oabcoefoxyozzopp';
        var count = 0;
        var i = 0;
        for (var j = 0; j < str.length; j++) {
            if (str.indexOf('o', i) != -1) {
                i = str.indexOf('o', i);
                console.log(i);//0 4 7 10 13
                i++;
                count++;
            }
        }
        console.log(count);//5

根据位置返回字符

  var str = 'andy';
        console.log(str.charAt(0)); //a
        console.log(str.charCodeAt(1));//110
        console.log(str[2]);//d

案例:统计字符串中出现次数最多的字符及其出现次数

这是一道经典的算法题,2020年3月初面试字节跳动日常实习生时被问到。

  var str = 'abjfkfsdfdmfpiptroqmx';
        var obj = {};
        var max = 0;
        var ch = '';
        //先统计各个字符出现的次数存于obj中
        for (var i = 0; i < str.length; i++) {
            var chars = str.charAt(i);
            if (obj[chars]) {
                obj[chars]++;
            } else {
                obj[chars] = 1;
            }
        }
        //找出最大的出现次数及相应字符
        for (var k in obj) {
            if (obj[k] > max) {
                max = obj[k];
                ch = k;
            }
        }
        console.log(max);//4
        console.log(ch);//f

其他字符串操作方法

concat substr slice substring 都会返回一个字符串

 var str = 'abc';
        str = str.concat('efg');
        console.log(str); //abcefg

        str = str.substr(0, 3);
        console.log(str); //abc

        str = 'abcdefg';
        str = str.slice(1, 3);
        console.log(str); //bc

 replace 替换字符

语法 replace('被替换的字符','替换为的字符') ,且它只会替换 第一个字符 , 该方法会返回一个字符串。

案例:替换一个字符串 'ahbjfhldiiiddsalomkkkal' 中所有的 'a' 为 '*' 。

var str = 'ahbjfhldiiiddsalomkkkal';
        while (str.indexOf('a') != -1) {
            str = str.replace('a', '*');
        }
        console.log(str);//*hbjfhldiiidds*lomkkk*l

split 将字符串分割为数组

语法 split(' 分隔符 ') ,它会返回一个数组

var str = 'a&b&c&d';
        var arr = str.split('&');
        console.log(arr); //["a", "b", "c", "d"]

API 与 Web API

通俗讲,其实 API 就是接口

2020.5.8

DOM

DOM简介

DOM树

获取页面元素节点 之 利用DOM提供的方法获取

获取页面元素,进而可以操作元素。主要有以下几种方式:

getElementById 根据ID获取页面元素

1 因为文档页面从上往下加载,先要有标签,故script写在标签后面

2 返回的是一个元素对象。

3 需要 console.dir 才能输出详细信息。

<div id="time">2020-5-8</div>

    <script>
        var time = document.getElementById('time');
        console.log(time); //打印Element标签
        console.dir(time); //该Element对象的详细信息
    </script>

getElementsByTagName 根据标签名获取

1 返回带有指定标签名的对象的集合

2 不需要 console.dir 也能输出详细信息。

    <ul>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
    </ul>
    <ul id="nav">
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
    </ul>

    <script>
        var list = document.getElementsByTagName('li');
        console.log(list); //页面中的全部li标签对象
        console.dir(list);


        var nav = document.getElementById('nav');
        var navList = nav.getElementsByTagName('li');
        console.log(navList); //#nav中的li标签对象
    </script>

通过 H5 新增方法获取

这一些方法会存在兼容问题。

document.getElementsByClassName('类名') 根据类名返回元素对象集合

document.querySelector('选择器') 根据指定选择器返回第一个元素对象

document.querySelectorAll('选择器') 根据指定选择器返回所有符合的元素对象

   <ul class="title">
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
        <li>知否知否,应是绿肥红瘦</li>
    </ul>
    <ul id="nav">
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
        <li>生僻字</li>
    </ul>

    <script>
        var title = document.getElementsByClassName('title');
        console.log(title);
        var firstBox = document.querySelector('li');
        console.log(firstBox);
        var li = document.querySelectorAll('li');
        console.log(li);
    </script>

document.body 获取body元素

当然,通过其他方法也可以获取。

 var body = document.body;
        console.log(body);

doucument.documentElement 获取html元素

当然,通过其他方法也可以获取。

   var box = document.documentElement;
        console.log(box);

获取页面元素节点 之 利用节点层级关系获取

节点概述

获取父级节点

获取子节点伪数组

获取子节点数组有两种方法,一种是用childNode属性,另一种是用children属性。

获取某个子节点

firstchild 和 lastchild 会返回一个子节点,但不一定是元素节点。

firstElementChild 会返回第一个元素子节点,lastElementChild 会返回最后一个一个元素子节点,但是它们会有兼容性问题。

方便且兼顾兼容性的 获取第一个元素子节点 和 最后一个元素子节点 的方法

获取兄弟节点

获取兄弟元素节点

方便且兼顾兼容性的 获取下一个元素兄弟节点 的方法

事件基础

事件类型

补充

禁止鼠标右键菜单 contextmenu 、禁止鼠标选中 selectstart

mouseenter mouseleave 事件

注册事件概述(绑定事件)

给元素添加事件,称为 注册事件 或者 绑定事件

注册事件有两种方式:传统方式方法监听注册方式

addEventListener 事件监听方式

attachEvent 事件监听方式(了解)

这种方式是用于兼容ie8及更低版本的,并且该方法是ie专有的,不推荐使用。

删除事件

   <button id="btn">按钮</button>
    <script>
        var button = document.getElementById('btn');
        //1 传统注册方式
        button.onclick = function () {
            alert('Hello');
            button.onclick = null;
        };
        //2 方法监听注册方式 ,如果需要删除注册,则不能用匿名函数
        button.addEventListener('click', fn);

        function fn() {
            alert('Hello');
            button.removeEventListener('click', fn);
        }
    </script>

执行事件的步骤

给元素添加事件:1 获取事件源 2 绑定事件 3 添加事件处理程序

  <button id="btn">按钮</button>
    <script>
        var button = document.getElementById('btn');
        //1 传统注册方式
        button.onclick = function () {
            alert('Hello');
        };
        //2 方法监听注册方式 addEventListener
        button.addEventListener('click', function () {
            alert('Hello');
        });
    </script>

页面元素 之 常用元素的属性操作

js 可以通过DOM操作改变网页内容、结构和样式等。

element.innerText 和 element.innerHTML 

区别:innerText 不能识别html标签,W3C标准,会去除空格和换行。

案例:

  <button id="btn">按钮</button>
    <p id="text">我是文字</p>
    <script>
        var text = document.getElementById('text');
        var btn = document.getElementById('btn');
        text.onclick = function () {
            text.innerText = '使用<strong>innerText</strong>进行修改';
        }
        btn.onclick = function () {
            text.innerHTML = '使用<strong>innerHTML</strong>进行修改';
        }
    </script>

效果:

           

其他常见元素属性

通过修改这些元素属性可以动态修改页面,srchrefidalt 和 title

操作页面元素 之 表单元素的属性操作

通过修改这些表单元素属性可以动态修改页面,typevalue 、checkedselected 和 disabled

案例:

   <button id="btn">按钮</button>
    <input type="text" id="text" value="我是文字"></input>
    <script>
        var input = document.getElementById('text');
        var btn = document.getElementById('btn');
        btn.onclick = function () {
            input.value = '我被点击了';
            this.disabled = true;
        }
    </script>

效果图:

       

操作页面元素 之 样式属性操作

JS 修改页面样式时,如果修改少量可以通过设置style的方式,否则可以通过设置class的方式。

案例:

<!-- 使用style修改样式 -->
   <style>
        #box {
            width: 100px;
            height: 100px;
            background-color: blue;
        }
    </style>


<body>
    <div id="box"></div>
    <script>
        var box = document.getElementById('box');
        box.onclick = function () {
            this.style.backgroundColor = 'red';
        }
    </script>
</body>
<!-- 使用className修改样式 -->
   <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: blue;
        }

        .change {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>

<body>
    <div id="box" class="box"></div>
    <script>
        var box = document.getElementById('box');
        box.onclick = function () {
            this.className = 'change';
        }
    </script>
</body>
 <!-- 使用className修改样式,且保留原class -->
   <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: blue;
        }

        .change {
            border-radius: 50px;
        }
    </style>

<body>
    <div id="box" class="box"></div>
    <script>
        var box = document.getElementById('box');
        box.onclick = function () {
            // 或者 this.className += ' change'; ← 这种不好,因为频繁触发字符串会一直加下去
            this.className = 'change box';
            console.log(this.className);
        }
    </script>

2020.5.15

自定义属性

H5设置自定义属性

H5获取自定义属性

操作页面元素 之 获取属性

获取属性有两种方法:

1 element.属性 

2 element.getAttribute('属性');

区别:

element.属性  用于获取内置属性值,即元素本身自带的属性

element.getAttribute('属性');  主要获得自定义的属性,即程序员自定义的属性

2020.6.1

创建元素节点

document.write 、element.innerHTML 、document.createElement

添加节点

添加节点有两种形式:

第一种是 node.appendChild 添加到父节点的子节点列表末尾;

第二种是 node.insertBefore 添加到父节点的指定子元素的前面

删除节点

复制节点

复制节点可分为 深拷贝浅拷贝

2020.6.2

DOM事件流

捕获阶段 & 冒泡阶段

事件对象概念

事件对象的兼容性方案

事件对象常用属性和方法

e.target 指向的是触发的对象,比如点击对象;而,回调函数内this指向的是绑定事件的对象,两者不一定相同。

阻止事件冒泡用 e.stopPropagation()

事件委托(代理、委派)

鼠标事件对象

坐标属性

常用键盘事件

键盘事件对象

BOM

BOM概述

BOM的构成

一般我们是不能直接访问 global 对象的。故在浏览器上,它提供的 window 对象扮演了 global 的角色。

window对象的常见事件

窗口加载事件 load & DOMContentLoaded

一种是window的 load 事件,另一种是window的 DOMContentLoaded 事件。

窗口调整大小事件 resize

定时器1 setTimeout

var time1 =setTimeout(fn1,3000);
var time2 =setTimeout(fn2,5000);

定时器2 setInterval

清除定时器1 clearTimeout

清除定时器 2 clearInterval

2020.6.3

this 指向

1、全局作用域或者普通函数中 this 指向全局对象window (注意定时器里面的this指向window)

   <script>
        var num = 2;
        function fn() {
            var num = 33;
            console.log(this.num);
        }
        fn();//2
    </script>

2、方法调用中谁调用 this 指向谁

3、构造函数中 this 指向构造函数的实例

JS 执行队列(执行机制)

同步和异步

JS 语言的一大特点就是单线程

同步和异步的本质区别:这条流水线上各个流程执行顺序不同。

 

事件循环

URL

location 对象

应用:点击按钮跳转页面

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    </style>
</head>

<body>
    <button>点击</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        var num = 5;
        btn.addEventListener('click', function () {
            div.innerHTML = num + 's后将跳转页面';
            setInterval(function () {
                if (num == 0) {
                    location.href = 'http://www.baidu.com';
                } else {
                    num--;
                    div.innerHTML = num + 's后将跳转页面';
                }
            }, 1000);
        })
    </script>
</body>

</html>

应用:页面之间传递参数

//页面a.html
    <input type="text">
    <button>登陆</button>
    <script>
        var btn = document.querySelector('button');
        var ipt = document.querySelector('input');
        btn.addEventListener('click', function () {
            window.location.href = 'b.html?username=' + ipt.value;
        })
    </script>

// 页面b.html
   <div></div>
    <script>
        var div = document.querySelector('div');
        var string = window.location.search.substr(1);
        var arr = string.split('=');
        console.log(arr);
        div.innerHTML = '欢迎您,' + arr[1];
    </script>

navigator 对象

history 对象

元素偏移量 offset 系列 

offset 与 style 的区别

在 js 里面获取元素的宽高等属性,只能通过 element.style.width element.offsetWidth ,而不能用 element.width。前者只能获取行内样式的属性,后者可以获取内嵌样式等表的属性。

应用:获取鼠标在盒子内的坐标

e.pageX 和 e.pageY 是鼠标相对于DOM窗口的坐标,而 offsetTop 和 offsetLeft 是元素距离页面窗口的距离。两者相减,就能得到鼠标在元素内的坐标。

效果:

代码:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            margin: 100px 0 0 100px;
            background-color: palegoldenrod;
        }
    </style>
</head>

<body>
    <div></div>
    <script>
        var div = document.querySelector('div');
        document.addEventListener('mousemove', function (e) {
            div.innerHTML = 'x坐标为' + (e.pageX - div.offsetLeft) + 'y坐标为' + (e.pageY - div.offsetTop);
        })
    </script>
</body>

</html>

2020.6.5

元素可视区 client 系列

立即执行函数

可以加函数名

(function fn() {})()
(function fn() {}())

元素 scroll 系列

页面被卷去的头部部分

元素被卷去的头部 element.scrollTop页面被卷去的头部 window.pageYOffset。

DTD 指的是 <!DOCTYPE html>

offset client scroll 三大系列属性总结比较 

JavaScript 动画

动画实现原理

通过定时器 setInterval 不断使元素发生变化

缓动动画实现原理

案例:浏览器右边弹出选框

<!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>
    <style>
        .sliderbar {
            position: fixed;
            right: 0;
            bottom: 100px;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            cursor: pointer;
            color: #fff;
        }

        .con {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 40px;
            background-color: purple;
            z-index: -1;
        }
    </style>
</head>

<body>
    <div class="sliderbar">
        <span>←</span>
        <div class="con">问题反馈</div>
    </div>

    <script>
        // 1. 获取元素
        var sliderbar = document.querySelector('.sliderbar');
        var con = document.querySelector('.con');
        // 当我们鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧
        // 当我们鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧
        sliderbar.addEventListener('mouseenter', function () {
            // animate(obj, target, callback);
            animate(con, -160, function () {
                // 当我们动画执行完毕,就把 ← 改为 →
                sliderbar.children[0].innerHTML = '→';
            });

        })
        sliderbar.addEventListener('mouseleave', function () {
            // animate(obj, target, callback);
            animate(con, 0, function () {
                sliderbar.children[0].innerHTML = '←';
            });

        })

        function animate(obj, target, callback) {
            // console.log(callback);  callback = function() {}  调用的时候 callback()

            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                // 步长值写到定时器的里面
                // 把我们步长值改为整数 不要出现小数的问题
                // var step = Math.ceil((target - obj.offsetLeft) / 10);
                var step = (target - obj.offsetLeft) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (obj.offsetLeft == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                    callback && callback();
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';

            }, 15);
        }
    </script>
</body>

</html>

轮播图思路

节流阀

滚动窗口至文档中的特定位置

使用 window.scroll( x , y ) 即可。

2020.6.6

touch 移动端触摸事件

TouchEvent 触摸事件对象

移动端拖动元素

移动端 click 延时解决方案

有 三种 解决方案

移动端常用开发插件

Swiper 轮播图插件

https://www.swiper.com.cn/

其他特效插件

superslideiscroll 、 zy.media.js

插件使用小结

框架与插件的区别

本地存储 

sessionStorage

特点:单页面内使用(共享),关掉页面就没了

使用方式

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" name="" id="">
    <button>存储数据</button>
    <button>获取数据</button>
    <button>删除数据</button>
    <button>删除所有数据</button>
    <script>
        var ipt = document.querySelector('input');
        var btns = document.querySelectorAll('button');
        btns[0].addEventListener('click', function () {
            sessionStorage.setItem('uname', ipt.value);
        })
        btns[1].addEventListener('click', function () {
            console.log(sessionStorage.getItem('uname'));
        })
        btns[2].addEventListener('click', function () {
            sessionStorage.removeItem('uname');
        })
        btns[3].addEventListener('click', function () {
            sessionStorage.clear();
        })
    </script>
</body>

</html>

查看方式

 localStorage

特点: 同一浏览器内通源页面共享,不删除则永久存在

使用方式

与 sessionStorage 类似

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" id="ipt">
    <input type="checkbox" id="remember">
    <label for="remember">记住用户名</label>
    <script>
        var ipt = document.querySelector('#ipt');
        var remember = document.querySelector('#remember');

        if (localStorage.getItem('username')) {
            ipt.value = localStorage.getItem('username');
            remember.checked = true;
        }
        ipt.addEventListener('change',function(){
            if (remember.checked) {
                localStorage.setItem('username', ipt.value);
            } 
        })
        remember.addEventListener('change', function () {
            if (remember.checked) {
                localStorage.setItem('username', ipt.value);
            } else {
                localStorage.removeItem('username');
            }
        })
    </script>
</body>

</html>

查看方式

与 sessionStorage 类似

2020.6.7

JavaScript 库

jQuery 概念

jQuery的入口函数

jQuery的顶级对象 $

jQuery对象 和 DOM对象

注意 jQuery对象只能使用jQuery对象属性方法;DOM对象只能使用原生的JS属性和方法

jQuery对象 和 DOM对象 的相互转换

补充: DOM对象 转换为 jQuery对象还有一种方式:

        var myDiv = document.querySelector('div');
        $(myDiv).hide();

jQuery 基础选择器

jQuery 隐式迭代

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="jquery-3.4.1.js"></script>
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>

<body>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <script>
        $(function () {
            $('div').css('background-color', 'yellow');
        });
    </script>
</body>

</html>

jQuery 筛选选择器

jQuery 筛选方法

方便书写链式编程

如果需要返回所有父级元素,可用 .parents().parents(selector)

取返回的伪数组中的某个元素,用 eq(index) 得到 jq对象;若用 [index] 得到 dom对象

2020.6.8 

jQuery 操作css

            // 2
            $('.wrapper').css('height', 240); //√
            $('.wrapper').css('height', '240px'); //√
            $('.wrapper').css('height', 240 px); //×

            // 3
            $('.wrapper').css({
                'color': 'red',
                'font-size': '20px',
                'height': 280
            }); //√
            $('.wrapper').css({
                color: 'red',
                fontSize: '20px',
                height: 280
            }); //√

 jQuery 设置类样式方法

jQuery 链式编程

jQuery 元素动画

显示隐藏效果

 



 


 

滑动效果


 


 


淡出淡入效果 





自定义动画 animate

animate 是元素动画,不能给document对象设置动画。

   $('button').eq(3).click(function () {
                $('div').animate({
                    width: 500,
                    height: 400
                }, 100);
            });

jQuery 动画队列及停止排队的方法

jQuery 属性操作

prop() 设置或获取固有属性值

attr() 设置或获取元素自定义属性值

data() 数据缓存

读取自定义属性值时,不需要加"data-"前缀

jQuery 内容文本值操作

文本框的值用 val()

保留指定小数位 toFixed()

把 Number 四舍五入为指定小数位数的数字

//规定小数的位数,是 0 ~ 20 之间的值,包括 0 和 20,有些实现可以支持更大的数值范围。如果省略了该参数,将用 0 代替。
NumberObject.toFixed(num)

jQuery 元素操作

 遍历元素 each

创建元素

添加元素 之 在内部添加

注意prepend 可以追加在内部的 前面

添加元素 之 在外部添加

删除元素

jQuery 获取元素尺寸

jQuery 位置操作

offset 设置或获取元素偏移

position 获取元素偏移

只能获取,不能设置

scrollTop / scrollLeft 设置或获取元素被卷去的头部和左侧

2020.6.9

jQuery 事件注册

单个事件的注册

单个或多个事件的注册 on

优势3的本质是事件委托,把事件绑定到动态生成的元素的父元素上。如此一来无论新建多少元素,这些元素都能触发相应事件。

一次性事件的注册 one

绑定方式与 on 相似。

jQuery 解绑事件 off( )

jQuery 自动触发事件 trigger( )

只是不需要特定的触发方式便能调用,如果要实现“自动”,仍然需要定时器

jQuery 阻止默认行为 及 阻止事件冒泡

jQuery 对象拷贝

语法解释:把 object 复制(合并)到 target 里去。

如果是浅拷贝,对于复杂数据类型,相当于是复制了引用,并且会复制完成后会覆盖冲突的数据。

如果是深拷贝,对于复杂数据类型,相当于是复制了相同数据,而复制完成后对于冲突数据,会合并而非覆盖。

jQuery 多库共存

方法1:使用  jQuery 代替 $

方法2释放 jQuery 对 $ 的控制权,让用户自定义

jQuery 插件

jQuery 插件 之 懒加载

jQuery 获取元素索引号

index() 方法返回指定元素相对于其他指定元素的 index 位置,如果未找到元素,index() 将返回 -1

$("li").click(function(){
  alert($(this).index());
});

2020.6.10

面向对象 与 面向过程 对比

 ES6中的类和对象

class 创建类

类名一般大写,且类名后面加小括号。

constructor 类构造函数

    class Star {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
    }
    var ldh = new Star('liudehua', 18);
    var zxy = new Star('zhangxueyou', 20);

类添加方法

多个方法之间不用写逗号

使用类的注意事项

1 ES6的类中没有变量提升,必须先要定义类,才能实例化类

2 类里面的共有属性和方法一定要加 this 才能使用

3 constructor 里面的 this 指向实例对象,方法里面的 this 一般指向这个方法的调用者

ES6 类的继承

就近原则:实例化子类调用方法时,会先查找子类中有无该方法,如果没有再去父类中查找。

super 关键字

super (parameter) 调用父类构造函数

super.xxx (parameter) 调用父类普通函数

注意 构造函数内使用super,必须把super放到最前面

    class Father {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }
        sum() {
            console.log(this.x + this.y);

        }
    }

    class Son extends Father {
        constructor(x, y) {
            super(x, y)
        }
    }
    var son = new Son(1, 2);//3,因为子类对象里面没有x,y只能去父类对象中取
    son.sum();
    class Father {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }
        sum() {
            console.log(this.x + this.y);

        }
    }

    class Son extends Father {
        constructor(x, y) {
            super(x, y);
            this.x = 2;
            this.y = 5;
        }
    }
    var son = new Son(1, 2);//7
    son.sum();

 

    //情形 1 输出 hello!
    class Father {
        say() {
            console.log('hello!');
        }
    }

    class Son extends Father {

    }
    var son = new Son();
    son.say();

    //情形2 输出 hi~
    class Father {
        say() {
            console.log('hello!');
        }
    }

    class Son extends Father {
        say() {
            console.log('hi~');

        }
    }
    var son = new Son();
    son.say();

    //情形3 输出 hello! hi~
    class Father {
        say() {
            console.log('hello!');
        }
    }

    class Son extends Father {
        say() {
            super.say();
            console.log('hi~');
        }
    }
    var son = new Son();
    son.say();

ES6继承小结

ES5是通过原型来模拟继承的操作的,然后ES6大概就是将ES5的这些操作封装起来。

ES6 子类 extends 父类 时,如果子类有 constructor(构造函数) ,则一定要在子类 constructor 内使用 super 调用父类的 constructor,否则会报错。

成功创建子类对象实例之后,调用某一个方法的查找顺序是这样的,看子类对象中有无该方法,若有则执行,若无则再查找父类,以此类推。属性的查找同理。

ES5 构造函数

静态成员 与 实例成员

    //实例成员就是构造函数内部通过this添加的成员,只能通过实例化的对象来访问
    function Star(name) {
        this.name = name;
    }
    var star = new Star('lili');
    console.log(star.name); //lili
    //静态成员就是在构造函数本身添加的成员,只能通过构造函数来访问。
    Star.sex = 'man';
    console.log(Star.sex); //man

构造函数存在的问题

浪费内存。因为对于相同的方法,实例之间是各自拥有,而不是共享。

构造函数原型对象 prototype

    function Star(name) {
        this.name = name;
    }
    Star.prototype.sing = function () {
        console.log('我会唱歌');
    }
    var star1 = new Star('lili');
    var star2 = new Star('dudu');
    console.log(star1.sing === star2.sing); //true

对象原型 __proto__

构造函数 constructor

如果覆盖了构造函数的原型对象,需要让原型对象内的 constuctor 重新指向原来的构造函数。

    function Star(name) {
        this.name = name;
    }
    Star.prototype = {
        constructor: Star,
        sing: function () {
            console.log('sing');
        },
        movie: function () {
            console.log('moveie');
        }
    }
    var star1 = new Star('lili');
    var star2 = new Star('dudu');

构造函数 、实例对象 和 原型对象 三者的关系

原型链

JS的成员查找机制

原型对象中 this 的指向问题

1 构造函数里面的 this 指向的是实例化所得到的实例对象

2 原型对象 prototype 函数里面的 this 指向的是调用者,即实例对象

扩展内置对象

ES5 继承

ES5并没有提供ES6的 extends 继承,所以我们通过 构造函数 + 原型对象 来模拟实现继承,称为组合继承

call ( ) 调用函数

如果没有参数,则直接像普通函数一样运行。

    var name = 'lolo';
    var star = {
        name: 'Jane'
    }

    function fn() {
        var name = 'sony';
        console.log(this.name);
    }
    fn(); //lolo
    fn.call(star); //Jane

借用构造函数继承父类型属性

公有方法写在父类构造函数中即可

    function People(name, age) {
        this.name = name;
        this.age = age;
    }

    function Newpeople(name, age, sex) {
        //在父类属性基础上,增加一个sex
        this.sex = sex;
        People.call(this, name, age);
    }
    var newpeople = new Newpeople('sony', 18, 'man');
    console.log(newpeople); //{age: 18,name: "sony",sex: "man"}

借用原型对象继承父类方法

不直接通过修改 Son.prototype.__proto__属性 进行继承,可能是因为__proto__属性是非标准属性,不能随意赋值。

    function Father() {
    }
    //父类原型对象中的共有方法
    Father.prototype.money = function () {
        console.log(10000);
    }

    function Son() {
    }
    Son.prototype = new Father();
    Son.prototype.constructor = Son;
    var son = new Son();
    son.money();

ES5新增遍历数组方法

array.forEach 循环数组

函数内遇到 return true 不会终止迭代。

    var arr = ['a', 'b', 'c', 'd'];
    arr.forEach(function (value, index, arr) {
        console.log(value, index); //a 0 、 b 1 、 c 2 、 d 4
    })

array.filter 过滤数据

函数内遇到 return true 不会终止迭代。主要用于过滤数据,当然也可以遍历。

    var arr = [12, 34, 56, 78, 90];
    var newArr = arr.filter(function (value, index, arr) {
        return value >= 40;
    })
    console.log(newArr); //56,78,90

array.some 检查符合某条件的元素是否存在 / 查找唯一元素

函数内遇到 return true 会终止迭代,也可用于遍历。

    var arr = [12, 34, 56, 78, 90];
    var flag = arr.some(function (value, index, arr) {
        return value >= 40;
    })
    console.log(flag); //true

ES5 新增字符串方法

trim 去除字符串两侧空格

ES5 新增对象方法

object.keys 获取对象属性名

    var obj = {
        name: 'liya',
        age: 18,
        sex: 'man'
    };
    var arr = Object.keys(obj);
    console.log(arr); //["name", "age", "sex"]

object.defineProperty 定义或修改属性

函数内的this指向

改变函数内的 this 指向

call 方法

    var name = 'sandy';
    var o = {
        name: 'andy'
    };

    function fn() {
        console.log(this.name);
    }
    fn.call(o); //andy
    fn(); //sandy

 

apply 方法

传参方式特别,apply 常搭配 Math 方法使用。

    //因为Math对象的一些方法只能接收一个个的参数,而不是接收一整个的数组。
    //而apply方法接收一个参数数组,并可以将数组元素作为参数一个个传给调用的方法。
    //apply与Math配合起来,就能将一个个数字传给Math方法,从而可以达到数组也能使用Math方法的效果
    function fn2(num1, num2, num3) {
        console.log(num1 + num2 + num3);

    }
    fn2.apply(window, [2, 6, 3]);

bind 方法

不调用函数,但会改变函数 this 的指向。

    var o = {
        name: 'soso'
    }

    function fn(a, b) {
        console.log(this);
        console.log(a + b);
    }
    var f = fn.bind(o, 1, 3);
    f(); //{name: "soso"} & 4
<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
</body>
<script>
    //给三个按钮添加点击事件,点击后失效,2s后复原
    //这里如果用apply或call修改this,则会使定时器内函数立刻执行
    var btns = document.querySelectorAll('button');
    btns.forEach(function (val, index) {
        val.onclick = function () {
            this.disabled = true;
            setTimeout(function () {
                this.disabled = false;
            }.bind(this), 2000);
        }
    })
</script>

三种方法的比较

2020.6.12

严格模式概念

开启严格模式

严格模式导致的变化

高阶函数

闭包

1 延伸了变量的作用范围。

2 利用闭包可以解决一些同步异步产生的问题,详情看案例。

    //闭包指向fn
    function fn() {
        var num = 10;
        return function () {
            console.log(num);
        }
    }
    var f = fn();
    f();

案例1:用闭包的形式完成点击 li 输出当前 li 的索引号

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        <li>第一个</li>
        <li>第二个</li>
        <li>第三个</li>
        <li>第四个</li>
    </ul>
</body>
<script>
    //利用闭包方式得到当前li的索引号
    var lis = document.querySelectorAll('li');
    for (var i = 0; i < lis.length; i++) {
        (function (i) {
            lis[i].onclick = function () {
                console.log(i);
            }
        })(i);
    }
</script>

</html>

案例2:利用闭包方式,通过定时器在3s后打印所以li的内容

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        <li>第一个</li>
        <li>第二个</li>
        <li>第三个</li>
        <li>第四个</li>
    </ul>
</body>
<script>
    //利用闭包方式,通过定时器在3s后打印所以li的内容
    var lis = document.querySelectorAll('li');
    for (var i = 0; i < lis.length; i++) {
        (function (i) {
            setTimeout(function () {
                console.log(lis[i].innerHTML);
            }, 3000)
        })(i)
    }
</script>

</html>

思考题:

    //本题不存在闭包
    var name = 'the windows';
    var object = {
        name: 'my object',
        getNameFunc: function () {
            var name = 'inner';
            return function () {
                return this.name;
            };
        }
    };
    console.log(object.getNameFunc()()); //the windows

    //本题存在闭包
    var name = 'the windows';
    var object = {
        name: 'my object',
        getNameFunc: function () {
            var that = this;
            return function () {
                return that.name;
            };
        }
    };
    console.log(object.getNameFunc()()); //my object

递归

    var n = 1;

    function fn() {
        console.log('第' + n + '次打印');
        if (n === 6) {
            return false;
        }
        n++;
        fn();
    }
    fn();

递归数学题一 之 求n的阶乘

    //利用递归函数求 n 的阶乘
    function fn(n) {
        if (n == 1) {
            return 1;
        }
        return n * fn(n - 1);

    }
    console.log(fn(3));

递归数学题二 之 求斐波那契数列的第n项

    //利用递归函数求斐波那契数列第 n 项
    // 1 1 2 3 5 8 13 21....
    //我们只需要知道用户输入的n的前两项(n-1) 和 (n-2) 即可算出第n项
    function fn(n) {
        if (n === 1 || n === 2) {
            return 1;
        }
        return fn(n - 1) + fn(n - 2);

    }
    console.log(fn(8));//21

递归遍历数据 之 查找某 id 的数据

    //data如下,从大类到细类,各个类都有对应的id
    //查找某id对应的类别
    var data = [{
        id: 1,
        name: '家电',
        goods: [{
            id: 11,
            gname: '冰箱'
        }, {
            id: 12,
            gname: '洗衣机'
        }]
    }, {
        id: 2,
        name: '服饰'
    }];

    function getId(data, id) {
        data.forEach(function (item) {
            if (item.id == id) {
                console.log(item);
            } else if (item.goods && item.goods.length > 0) {
                getId(item.goods, id)
            }
        })
    }
    getId(data, 12); //{id: 12, gname: "洗衣机"}

JS 对象拷贝

ES6以前 实现浅拷贝

利用 for in ( for in 得到的是属性名)。但是对于复杂数据,比如 own,复制的是地址,所以 o 修改了 own obj 中的 own 也会变化。

    var obj = {
        id: 1,
        name: 'lily',
        own: {
            money: 100
        }
    };
    var o = {};
    for (var k in obj) {
        //k是属性名
        o[k] = obj[k];
    }

ES6 实现浅拷贝的语法糖

不需要再用 for in

    var obj = {
        id: 1,
        name: 'lily',
        own: {
            money: 100
        }
    };
    var o = {};
    Object.assign(o, obj);

 ES6 实现浅拷贝的扩展运算符

    let a = {
      age: 1
    }
    let b = {
      ...a
    }
    a.age = 2
    console.log(b.age) // 1 

JS 实现深拷贝的两种方法

用 for in 递归遍历,注意 array 复杂数据类型并且也是对象类型

    var obj = {
        id: 1,
        name: 'lily',
        own: {
            money: 100
        }
    };
    var o = {};

    function deepCopy(newobj, oldobj) {
        for (var k in oldobj) {
            //需要判断属性属于哪种数据类型
            //先把属性赋值给item
            var item = oldobj[k];
            //如果item是数组类型(数组也是复杂数据类型),需要遍历复制
            if (item instanceof Array) {
                newobj[k] = [];
                deepCopy(newobj[k], item);
                //如果item是数组外的对象类型,需要遍历复制
            } else if (item instanceof Object) {
                newobj[k] = {};
                deepCopy(newobj[k], item);
                //其他基本类型直接赋值
            } else {
                newobj[k] = item;
            }
        }
    }
    deepCopy(o, obj);

另外,还可以借用 JSON.parseJSON.stringify 来实现深拷贝。

2020.6.13

正则表达式

创建正则表达式 

测试正则表达式

正则表达式特殊字符 之 ^ $

    var reg2 = /^123$/;
    console.log(reg2.test(123)); //true
    console.log(reg2.test(123123)); //false

正则表达式特殊字符 之 [ ]  、 ^[ ]$  、 ^[^ ]$  

    // [] 表示有一系列字符可供选择,只要匹配其中一个即可
    var reg = /[abc]/; //内容只要包含abc其中一个即可
    console.log(reg.test('andy')); //true
    console.log(reg.test('red')); //false

    var reg = /^[abc]$/; //三选一,内容只能是a 或 b 或 c
    var reg = /^[a-z]$/; //内容只能是26个字母中的一个
    var reg = /^[a-zA-Z0-9-_]$/; //内容只能是其中一个
    var reg = /^[^a-zA-Z0-9-_]$/; //一个内容,但不能包含其中的任何一个字符/数字

正则表达式量词符

设定前面模式的出现次数

    var reg1 = /^a*$/;
    console.log(reg1.test('aaaa')); //true
    var reg2 = /^a+$/;
    console.log(reg2.test('aaaa')); //true
    var reg3 = /^a?$/;
    console.log(reg3.test('aaaa')); //false
    var reg4 = /^a{2}$/;
    console.log(reg4.test('aaaa')); //false
    var reg5 = /^a{2,}$/;
    console.log(reg5.test('aaaa')); //true
    var reg6 = /^ab{2,4}$/;
    console.log(reg6.test('abbb')); //true
    var reg7 = /^(ab){2,4}$/;
    console.log(reg7.test('abababab')); //true
    var reg8 = /^[a-zA-Z0-9-_]{2,8}$/;
    console.log(reg8.test('abb-_bb')); //true

预定义类

 正则表达式参数

    //把所有的开心或快乐替换成兴奋
    var newString = oldString.replace(/开心|快乐/g, '兴奋');

ES6 关键字 let

    if (true) {
        let a = 10;
        var b = 20;
    }
    console.log(b); //20
    console.log(a); //报错

特点

1 let 不存在变量提升,需要先声明,才能使用。

2 let 会产生暂时性死区。

    //let 会产生暂时性死区。
    //在块级作用域内部,只要有let声明某个变量,这个变量就不同于外面的变量,是属于块级作用域的,与块级作用域绑定了。
    //所以在这个if里面,有一个块级作用域的num。
    //然后这里先使用num再声明num,而let没有变量提升,故报错。
    var num = 10;
    if (true) {
        console.log(num);//报错
        let num = 20;
    }

相关面试题一

这里因为是使用 var 来声明 i,所以 for 产生的两个作用域都属于全局作用域。因此当函数要打印 i 的时候,所用到的是全局作用域的 i,且 i=2

相关面试题二

这里因为是使用 let 来声明 i,所以for产生的两个作用域都属于块级作用域。第一个块级作用域里面的 i=0,第二个 i=1。当函数打印 i 时,会去自己对应的上级作用域寻找 i,所以就输出了相应的块级作用域里面的

ES6 关键字 const

对于复杂数据类型,可以修改其属性或者内部的某个值,但是依然不可更改其地址。

var 、let 、const 的区别

一般定义不会更改的函数以及常数可以使用 const ,这样JS解析不需要实时监控变化,效率更高。

用 const 的时候,对于复杂数据类型,可以修改其属性或者内部的某个值,但是依然不可更改其地址。

ES6 解构赋值

数组解构

方便从数组中取值。平时我们从数组取值,可能需要多个声明,一个个地进行赋值,现在一句话就可以搞定。

    var arr = [1, 2, 3, 4];
    //这里相当于 a b c d e 都是用var声明的
    var [a, b, c, d, e] = arr;
    console.log(a); //1
    console.log(b); //2
    console.log(c); //3
    console.log(d); //4
    console.log(e); //undefined

 对象解构

解构时的变量名,一定要与对象中的属性名相匹配,才可以解构成功。

    var obj = {
        name: 'lily',
        age: 18,
        sex: 'man'
    };
    //这里相当于花括号内的属性都是用var声明的
    var {name, age, sex, money} = obj;
    console.log(name); //lily
    console.log(age); //18
    console.log(sex); //man
    console.log(money); //undefined

    //如果用 xx:xx 的形式,则左边的是所匹配的属性,右边的是变量名(属性别名)
    var {name:myname, age:myage, sex:mysex, money:mymoney} = obj;
    console.log(myname); //lily
    console.log(myage); //18
    console.log(mysex); //man
    console.log(mymoney); //undefined

 箭头函数

注:

1 => 右边只有一句代码即可省略 {} ,而一定需是返回值。(maybe)

箭头函数内是用不了 arguments 的,只能用 剩余参数 的方法获取全部形参。

//上面图片的代码输出的是两个obj对象
//下面这段代码输出的是两个window对象
//因为箭头函数本身不绑定this,所以它所在的区域this指向的是谁,它里面的this就指向谁
//图片案例里面,this指向obj;下面代码中,this指向window

    function fn() {
        console.log(this);
        return () => {
            console.log(this);
        }
    }
    const obj = {
        name: 'zhangsan'
    };
    const resFn = fn();
    resFn();

箭头函数面试题

    //因为箭头函数没有自己的this,所以要看它所处的区域的this指向谁。
    //它所处的区域为obj,obj是对象,不能自己构建一个作用域,obj本身也属于全局作用域
    //所以say方法中的this指向window
    var age = 100;
    var obj = {
        age: 20,
        say: () => {
            alert(this.age);
        }
    }
    obj.say(); //100

剩余参数

    const sum = (...args) => {
        let total = 0;
        args.forEach(item => total += item);
        return total;
    }
    console.log(sum(10, 20, 50));//80

 剩余参数和解构配合使用

    let students = ['张三', '王五', '李四'];
    let [s1, ...s2] = students;
    console.log(s1); //'张三'
    console.log(s2); //['王五','李四']

ES6 Array的扩展方法(△)

    let arr = [1, 2, 3, 4];
    console.log(...arr); // 1 2 3 4 ,等价于下面的写法。
    console.log(1, 2, 3, 4);

 扩展运算符用于合并数组

    var arr1 = [1, 2, 3];
    var arr2 = [4, 5, 6];
    console.log([...arr1, ...arr2]);
    arr1.push(...arr2);
    console.log(arr1);

 扩展运算符用于将伪数组转换为数组

 

<body>
    <div>
        a
    </div>
    <div>
        b
    </div>
</body>
<script>
    var divs = document.querySelectorAll('div');
    var divarr = [...divs];
    console.log(divs); //NodeList(2) [div, div]
    console.log(divarr); //(2) [div, div]
</script>

ES6 Array扩展方法

将伪数组转换为数组 Array.from

除了用扩展运算符的方法(上面代码),还可以使用 Array 构造函数 中的 from 方法。

<body>
    <div>
        a
    </div>
    <div>
        b
    </div>
</body>
<script>
    var divs = document.querySelectorAll('div');
    var divarr = Array.from(divs);
    console.log(divs); //NodeList(2) [div, div]
    console.log(divarr); //(2) [div, div]
</script>

    let arrayLike = {
        '0': 1,
        '1': 2,
        'length': 2
    }
    let newArr = Array.from(arrayLike, item => item * 2);
    console.log(newArr);

 找出第一个符合条件的数组成员 find

找出第一个符合条件的数组成员的位置 findIndex

判断数组是否包含某个值 includes

2020.6.14

ES6 String扩展方法

模板字符串

有了模板字符串(反引号字符串),在拼接字符串的时候就不需要再用 + + 了。

    //变量没有要求必须为反引号字符串,当然反引号字符串也可以
    var str = 'lily';
    //反引号字符串才能解析变量,普通字符串内部不会解析${}
    var sayHello = `hello,my name is ${str}`;
    console.log(sayHello); //hello,my name is lily

判断字符串开头结尾 StartsWidth & endsWidth

重复字符串 repeat

数据结构Set 

应用:巧用set完成数组去重

    const s = new Set(['a', 'a', 'b', 'b']);
    console.log(s.size); //2
    const arr = [...s];
    console.log(arr); //(2) ["a", "b"]

实例方法

遍历

2020.7.7 

判断空对象

object.keys(obj).length === 0

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值