1.作用域
局部作用域:函数内部就是局部作用域。
①在局部作用域申明的变量称为局部变量,局部变量只能在当前函数内部使用
②形参也就相对于局部变量
③函数在执行的时候先在内存中开辟新的作用域空间
④当执行完毕函数之后,会关闭作用域空间同时销毁局部变量
⑤ let申明的变量具有块级作用域,var申明的变量不具有块级作用域
全局作用域:函数外部就是全局作用域
① 全局变量:在全局作用域申明的变量成为全局变量,这个变量可以在任何地方使用
②因为全局变量可以在任何地方使用,所以我们只需要特别关注局部变量既可
块级作用域:大括号包裹的代码块就是块级, 类似于局部作用域
2.var、let、const申明变量
var和let
①var申明的变量相当于给window添加了个属性,let不会
②var申明的变量不具有块级作用域,let具有块级作用域
③var申明的变量可以重复申明定义,let申明的变量不可以重复申明定义
const和let
①const:用来定义常量,不可以改值,let可以改值
②const:定义的常量必须初始化有值,let可以不设置值
③建议:常量用于定义固定不变的值,所以常量名建议用大写
3.作用域链
作用域所串联起来的链状结构,提供我们查找变量的机制
4.闭包
一个作用域有权访问另外一个作用域的局部变量,称为闭包,让一个变量的作用范围延伸
5.预解析
预解析从上往下执行,代码执行之前要预解析。
在代码执行之前把变量和函数会提前解析到当前作用域最前面,任何一个作用域在执行代码之前都要先预解析
① 变量:申明的变量会解析,把变量的申明语法提升到当前作用域的最前面,只定义不赋值
变量提升案例:
函数执行完毕会销毁!!!!
② 函数:有名字的函数会解析,把函数的申明语法提升到当前作用域最前面,只定义不调用
③表达式函数,相当于把函数赋值给变量,之后才能调用
函数提升案例:
首先有名字的函数会被提升到表达式函数的前面,然后进行执行,但是值得注意的点是两个函数名字相同,后面的函数会覆盖掉前面的,所以打印结果为 '我是真的'
④预解析时,函数要优于变量
6.函数参数
如果某个参数不想传参,想用默认值,就传undefined
如果函数的参数不固定,那么就不要写形参接收
在函数中,有一个特殊的对象,arguments,用于接收所有的实参
剩余参数
...剩余参数写法,只能写在最后的位置
function fn (a, b, ...c) {}
7.箭头函数
1、如果函数的形参只有一个,那么可以省略小括号
2.如果函数的函数体只有一行代码,那么可以省略大括号
let fn = x => x * x;
通过箭头函数遍历:
[1, 2, 3].forEach( item => console.log(item) );
注意点:
①如果涉及到this的情况,不建议使用箭头函数,因为箭头函数中认为没有this,使用的是上级this(函数所在区域的this)
②箭头函数不存在提升,所有一定要先声明再使用
③箭头函数中没有arguments对象,所以不可以使用arguments,用...代替arguments
8.解构赋值----数组(一一对应,不取的位置空出来,用逗号占位)
let arr = ['张三丰', '阿飞', '带土'];
let [a, b, c] = arr;
等同于:
// let a = arr[0];
// let b = arr[1];
// let c = arr[2];
①剩余值的方式,...出来的数值都会被数组存起来
②多出来的变量打印结果为undefined
③变量少值多,多出来的值不会被选到
④复杂形式---也是遵循一一对应原则
9.对象的解构赋值
可能在解构赋值之前已经申明了这个变量,这个情况用冒号改变量名(以下aaa因为没有对应变量,所以打印结果为undefined)
10.对象:一类中具体的某个实例,属性和方法的集合体(类:泛泛的概念)
11.编程思想
①面向过程:按照步骤一步一步的完成功能
②面向对象:按照对象方式考虑问题完成功能,让对象互相调用属性和方法配合完成
12.字面量
13.构造函数
①构造函数也是函数,只不过通常和new一起使用,用来创建对象
实例化对象:例 let o=new Object(),o为实例,Object()为构造函数,由 实例.属性/方法 方式添加的数据是私有的
②建议:构造函数的所有单词的首字母大写
14.自定义构造函数
this指向当前实例对象(调用者)
15.constructor
任何一个对象都可以使用一个属性,constructor,可以指回构造函数本身
16.简单数据类型和引用类型
传递
①简单类型:值传递:把数据复制一份进行传递,产生两份数据
②引用类型:引用传递: 把数据地址复制一份进行传递,两个地址指向同一份数据
17.数组的方法
①push、pop、shift、unshif、splice、reverse用于 数组的基本操作
②concat:连接数组成为新数组,返回拼接之后的新数组
③indexOf、lastIndexOf,根据数据找索引
④join:用于连接数组的每个元素成为字符串
⑤sort:数组排序
arr.sort( function (a, b) {return a - b;} )
//升序排列
arr.sort( function (a, b) {return b - a;} )
//降序排列
数组练习:
案例1:把这个数组不为a的值取出放到新数组里面
第一步:声明一个新的空数组 let newArr=[ ]
第二步:for循环遍历原有数组并对每一项进行判断
案例2:数组去重
将arr中每个元素遍历一遍,在newArr中查找,如果没有这个元素,就添加到newArr里面
18.数组的静态方法---Array.from()
通过document.querySelectorAll()
得到的数据是NodeList,只是一个节点列表并不是真正的数组,所以也不能使用数组的方法,这时就需要通过数组的Array.from()方法将其转换成真数组
19.数组的遍历---forEach方法
(小提示):遍历数组多用forEach和for循环,而遍历对象通常用for in循环
20.数组转换
①获取节点列表
let lis = document.querySelectorAll('li');
②将DOM对象转换成真正的数组
let newLis = $.makeArray(lis); // 这里利用的是jQuery方法
③这时就可以使用数组的方法了
newLis.pop();
21.正则的创建
①字面量:let reg=/ abc /;
②构造函数:let reg=new RegExp( / abc / );
22. 原型
①每个构造函数都有一个prototype属性,实例.prototype指向了一个对象,我们把这个对象称为原型,原型对象,它的作用是保存方法,节省内存
②在原型对象中,都有一个construtor,这个属性用于指回构造函数本身
③每个实例对象都有一个_proto_属性,非标准属性,用于指向原型对象,当对象查找成员找不到的时候,就会沿着_proto_的指向继续找
// 实例对象继承给原型对象
Chinese.prototype = new Person();
// 指回构造函数
Chinese.prototype.constructor = Chinese;
23.this指向
①普通函数------this指向调用者
function fn () {
console.log( this) ;}
window.fn();
②构造函数------指向当前实例对象
function Person (uname, age) {
this.uname = uname;
this.age = age;
console.log(this);
}
③方法------指向调用者(非严格模式)
看方法名前面是否有“.”,有的话,“.”前面是谁this就是谁,没有的话this是undefined
④事件处理程序------调用者(定时器)
window.setInterval(function () {
console.log(this); //window
}, 1000);
④自执行函数------window、调用者(非严格模式下)
自执行函数中的this永远是undefined(在严格模式下)
(function () {
console.log(this);
})();
24.改变this指向
call、apply、bind:都是函数的方法
call和apply:都会使函数执行,但是参数不同
bind:不会使函数执行,参数同call
call:函数.call(this, arg1, arg2......);
①call 方法能够在调用函数的同时指定 this 的值
②使用 call 方法调用函数时,第1个参数为 this 指定的值
③call 方法的其余参数会依次自动传入函数做为函数的参数
apply:函数.apply(this, [arg1, arg2......]);
①apply 方法能够在调用函数的同时指定 this 的值
②使用 apply 方法调用函数时,第1个参数为 this 指定的值
③apply 方法第2个参数为数组,数组的单元值依次自动传入函数作为函数的参数
bind:函数.bind(this, arg1, arg2......);
bind,用于既想要改变this的指向,但是又不希望立刻执行函数
25.类(class)------ 类的本质就是构造函数
创建类 class Person{ //属性和方法 }
实例化 let o1=new Person();
①实例成员:属性=值
关键字 class 封装了所有的实例属性和方法,类中封装的并不是变量和函数,因此不能使用关键字 let、const或var
②静态成员:static 属性=值
static 关键字用于声明静态属性和方法, 静态属性和方法直接通过类名进行访问
Person.eat();
③创建类时在类的内部有一个特定的方法 constructor ,该方法会在类被实例化时自动被调用,常被用于处理一些初始化的操作。
26.继承
①extends 是专门用于实现继承的语法关键字
extends:把一个类申明为子类,如果子类自己除了继承还有自己的constructor,只能通过super调用父类方法
②super 在继承的过程中子类中 constructor 中必须调 super 函数,否则会有语法错误
子类构造函数中的 super 函数的作用是可以将子类实例化时获得的参数传入父类的构造函数之中。 Super用于调用父类的方法
27.拷贝------拷贝不是直接赋值
①浅拷贝------只拷贝最外层,拷贝的不彻底
方法一:利用Object.assign()方法,参数一为目标结果,参数二为拷贝对象
Object.assign(newObj, obj);
方法二:遍历
方法三:展开运算符
②深拷贝------所有层都可以拷贝下来
方法一:序列化和反序列化
toJSONString、stringify是序列化------将Object转换成JSON字符串
使用parse、parseJSON、eval是反序列化------JSON字符串转化为Object
方法二:遍历+递归
如果遍历的数据为对象或者数组类型,那么就同理在函数内部自己调用自己(递归),进行进一步的拷贝
28.继承给原型
①把实例对象赋值给原型对象
② 指回构造函数本身
已知
继承之前 console.log(Chinese.prototype);
在constructor.prototype
继承之后console.log(Chinese.prototype);
Chinese.prototype = people; // 把实例对象赋值给原型对象
// 指回构造函数本身
Chinese.prototype.constructor = Chinese;
29.原型链
原型串联起来的链状结构,提供查找成员的机制
30.js给dom添加事件的方式