《一起学前端 之 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'));// NaNconsole.log(parseFloat('3.14'));//3.14
console.log(parseFloat('120px'));//120
console.log(parseFloat('rem120px'));//NaNvar 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;//11var b = ++a + 2;//++a 先对a自加1,再返回aconsole.log(b); //14var c = 10;c++;//11var d = c++ + 2;//c++ 先返回c,再对c进行自加1console.log(d); //13var e = 10;//从左往右。先返回e,为10,然后对e进行自加1,得到11;先对e进行自加1,得到12,返回e;实际上等于 10+12=22var 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()); //7arr.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能按照一定规律进行比较。

  //普通 sortvar arr = [1, 2, 33, 32, 23];console.log(arr.sort()); //[1,2,23,32,33]//带有比较函数的sortvar 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); //trueconsole.log(Array.isArray(arr)); //trueconsole.log(num instanceof Array); //falseconsole.log(Array.isArray(num)); //false

数组索引方法

获得数组中元素的索引

 var arr = ['blue', 'pink', 'orange', 'white', 'pink'];// 只返回最先匹配的那一个的位置console.log(arr.indexOf('pink')); //1//只返回最先匹配的那一个,但并不会改变索引的顺序console.log(arr.lastIndexOf('pink')); //4 //如果元素不在该数组中 则返回 -1console.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,Youconsole.log(arr.join('-')); //I-Love-Youconsole.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); //5console.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); //errorconsole.log(num2); //20

作用域链

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

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

JS 预解析

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

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

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

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

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

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

        //案例1console.log(num); //undefinedvar num = 10;//案例2fn(); //11function fn() {console.log(11);}//案例3fun(); //报错,fun is not a functionvar fun = function () {console.log(22);}//案例4var 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); //Jsonconsole.log(Json.age); //17console.log(Json.sex); //manJson.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)); //1console.log(Math.abs(-1)); //1console.log(Math.abs('-1')); //隐式转换 1console.log(Math.abs('Json')); //NaN//取整方法 floor 向下取整console.log(Math.floor(1.1)); //1console.log(Math.floor(1.9)); //1//取整方法 ceil 向上取整console.log(Math.ceil(1.1)); //2console.log(Math.ceil(1.9)); //2//取整方法 round 四舍五入取整 但是.5特殊,会往“大”的方向取整console.log(Math.round(1.5)); //2console.log(Math.round(1.1)); //1console.log(Math.round(1.9)); //2console.log(Math.round(-1.1)); //-1console.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 -> svar 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提供了三个特殊的引用类型:StringNumberBoolean

字符串对象

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

根据字符返回位置

  var str = '改革春风吹满地,春天到啦';console.log(str.indexOf('春')); //2console.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 13i++;count++;}}console.log(count);//5

根据位置返回字符

  var str = 'andy';console.log(str.charAt(0)); //aconsole.log(str.charCodeAt(1));//110console.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);//4console.log(ch);//f

其他字符串操作方法

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

 var str = 'abc';str = str.concat('efg');console.log(str); //abcefgstr = str.substr(0, 3);console.log(str); //abcstr = '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

mouseentermouseleave 事件

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

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

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

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 方法监听注册方式 addEventListenerbutton.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.widthelement.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 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10obj.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);//7son.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(); //lolofn.call(star); //Jane

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

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

    function People(name, age) {this.name = name;this.age = age;}function Newpeople(name, age, sex) {//在父类属性基础上,增加一个sexthis.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); //andyfn(); //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 利用闭包可以解决一些同步异步产生的问题,详情看案例。

    //闭包指向fnfunction 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 修改了 ownobj 中的 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 = 2console.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) {//需要判断属性属于哪种数据类型//先把属性赋值给itemvar 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)); //trueconsole.log(reg2.test(123123)); //false

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

    // [] 表示有一系列字符可供选择,只要匹配其中一个即可var reg = /[abc]/; //内容只要包含abc其中一个即可console.log(reg.test('andy')); //trueconsole.log(reg.test('red')); //falsevar reg = /^[abc]$/; //三选一,内容只能是a 或 b 或 cvar reg = /^[a-z]$/; //内容只能是26个字母中的一个var reg = /^[a-zA-Z0-9-_]$/; //内容只能是其中一个var reg = /^[^a-zA-Z0-9-_]$/; //一个内容,但不能包含其中的任何一个字符/数字

正则表达式量词符

设定前面模式的出现次数

    var reg1 = /^a*$/;console.log(reg1.test('aaaa')); //truevar reg2 = /^a+$/;console.log(reg2.test('aaaa')); //truevar reg3 = /^a?$/;console.log(reg3.test('aaaa')); //falsevar reg4 = /^a{2}$/;console.log(reg4.test('aaaa')); //falsevar reg5 = /^a{2,}$/;console.log(reg5.test('aaaa')); //truevar reg6 = /^ab{2,4}$/;console.log(reg6.test('abbb')); //truevar reg7 = /^(ab){2,4}$/;console.log(reg7.test('abababab')); //truevar 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); //20console.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); //1console.log(b); //2console.log(c); //3console.log(d); //4console.log(e); //undefined

对象解构

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

    var obj = {name: 'lily',age: 18,sex: 'man'};//这里相当于花括号内的属性都是用var声明的var {name, age, sex, money} = obj;console.log(name); //lilyconsole.log(age); //18console.log(sex); //manconsole.log(money); //undefined//如果用 xx:xx 的形式,则左边的是所匹配的属性,右边的是变量名(属性别名)var {name:myname, age:myage, sex:mysex, money:mymoney} = obj;console.log(myname); //lilyconsole.log(myage); //18console.log(mysex); //manconsole.log(mymoney); //undefined

箭头函数

注:

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

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

//上面图片的代码输出的是两个obj对象
//下面这段代码输出的是两个window对象
//因为箭头函数本身不绑定this,所以它所在的区域this指向的是谁,它里面的this就指向谁
//图片案例里面,this指向obj;下面代码中,this指向windowfunction fn() {console.log(this);return () => {console.log(this);}}const obj = {name: 'zhangsan'};const resFn = fn();resFn();

箭头函数面试题

    //因为箭头函数没有自己的this,所以要看它所处的区域的this指向谁。//它所处的区域为obj,obj是对象,不能自己构建一个作用域,obj本身也属于全局作用域//所以say方法中的this指向windowvar 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); //2const arr = [...s];console.log(arr); //(2) ["a", "b"]

实例方法

遍历

2020.7.7

判断空对象

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

JS / JQ 学习记录相关推荐

  1. html +css +js+jq学习

    html 1 标签的使用 和属性 https://blog.csdn.net/weixin_41530824/article/details/82261561 具体可以参考这个 css 选择器 关于浮 ...

  2. 【JS】学习记录【页面打印】

    [JS]记录一下今天遇到的问题和解决方法 需求:所有的已发布的工单和标准要能打印,打印时隐藏页面所有按钮,效果如下. 问题一:隐藏按钮. 解决办法: 获取按钮,设置样式display=none: fu ...

  3. js逆向学习记录某真气网

    项目场景: 第一次写不知道能否表达清楚 在B站上学习JS逆向,结果学到最后一个练习项目时.因为之前学习得人把人家网站搞崩了.到了我来爬取得时候,这个网站反爬已经大幅度升级了,爬取难度急据升高. 声明: ...

  4. 我的前端笔记【附 JS JQ学习】

    点击checkbox前面的文字选中checkbox复选框 <p><label for="check">爱好</label><input t ...

  5. 廖雪峰JS教程学习记录---字符串

    1.由于多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,用'...'表示`这是一个 多行 字符串`; 2.字符串常见的操作如下: s.length; // 13 要 ...

  6. 廖雪峰JS教程学习记录----Map和Set

    Map和Set Map Map是一组键值对的结构,具有极快的查找速度. 1.解决问题: JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值 ...

  7. JS 正则表达式学习记录

    表严肃讲正则表达式:https://www.bilibili.com/video/av18182693/?p=1 在线练习地址:https://regexr.com/ 正则语法:/正则表达式主体/修饰 ...

  8. 小程序js+django+服务器后台搭建流程总结(第五周学习记录)

    学习记录 这周的工作依然是做一些服务器的调试工作,但是为了方便这周末的展示,我打算把这段时间的所有后台搭建工作和对所有服务器的操作流程做一个系统的总结和归纳,方便学习记录与交流 一.微信小程序js部分 ...

  9. Auto.js学习记录

    软件选择:通过在CSDN的查找发现了几款手机自动化脚本软件,例如:按键精灵.Auto.js等等.最后我选择了Auto.js .Auto.js共有三个版本:4.1.1版本.7.0.0版本和8.0.0版本 ...

最新文章

  1. DDD 领域驱动设计:贫血模型、充血模型的深入解读!
  2. python搭建环境是什么_python虚拟环境是什么?python虚拟环境的介绍
  3. linux c openssl rsa 加解密
  4. 【原创】完美实现GetProcAddress [文字模式]
  5. HDU - 5790 Prefix(主席树+字典树)
  6. CGCKD2021大会报告整理(3)--贝叶斯深度网络
  7. 【Python爬虫】BeautifulSoup4 库的一些用法
  8. Android 应用开发(20)--- 定义自定义应用程序权限
  9. 为什么rocketmq的queue分为读写?_分布式发布订阅消息系统Kafka 为什么快
  10. washer和shell有什么区别_disk or washer method?
  11. 驱动模块的安装与卸载指令
  12. 批处理创建快捷方式【简单好用详解】
  13. 【第二节】HTML5小实例
  14. DotaMax网站”获取“自己与职业选手(知名玩家)对战记录
  15. 队列的应用--火车车厢重排列
  16. PowerShell_零基础自学课程_1_初识PowerShell
  17. 猿创征文 | DevOps运维的10个日常使用工具分享
  18. 坦然的面对一切都已经发生的事实
  19. Chains (链 )
  20. VR购物为实体零售开启科技助力

热门文章

  1. 《潮流时装设计——世界顶级时装CAD制板技巧》——1.1 什么是服装CAD
  2. java生成word报告echart_Java这几个用 Pyecharts 做出来的交互图表,领导说叼爆了!...
  3. 被告没车没房没存款,起诉还有用吗
  4. 灌篮高手微信登录是什么服务器,灌篮高手手游应用宝版
  5. latex参考文献中修改指定作者的格式来突出显示
  6. 纯C++实现24位bmp格式图片的读取和修饰
  7. 高德地图发布2017上半年度公共交通报告
  8. Python 修改AD账号密码(一)- 启用域控LDAPS
  9. gpu训练cnn人脸识别准确率_opencv+mtcnn+facenet+python+tensorflow 实现实时人脸识别
  10. 基于Vivado MIG IP核的DDR3读写实验(top_rom_ddr/ddr_top)