一、函数高级
1.函数回调
函数回调的本质:在一个函数中,满足特定条件下,调用另一个函数
// 回调的函数function callback(data) {}// 逻辑函数function func(callback) { ???// 函数回调 ???if (callback) callback(data);}
function a_fn(data) { ???????console.log(‘a_fn‘); ???????// 如果要使用数据,那么定义形参接收参数 ???????console.log(data); ???} ???function b_fn(a_fn) { ???????var data = "b_fn 的 数据"; ???????console.log(‘b_fn‘); ???????// 条件: a_fn有值(有函数实现体) ???????if (a_fn) { ???????????// 调用参数函数 ???????????a_fn(data); ???????} ???} ???b_fn(a_fn);
总结:
1.一个函数(函数名)作为另外一个函数的参数
2.满足一定的条件,调用参数函数
3.形成了函数回调,回调的函数可以获取调用函数的局部变量(将数据携带出去)
2.闭包
闭包本质:函数的嵌套定义,内层函数称之为闭包
闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染
function outer() { ???var data = {} ???//闭包 ???function inner() { ???????return data; ???} ???return inner;}
注:外部使用局部变量的方法: 返回值 | 函数回调 | 闭包 | 提升作用域
2.1局部变量持久化
function outer() { ???????//eg:请求得到的数据,如果不持久化,方法执行完毕后,数据就会被销毁 ???????var data=[1,2,3,4,5]; ???????console.log(data); ???????//通过闭包解决该类问题,所以闭包所有代码均可以随意自定义 ???????function inner(){ ???????????return data; ???????} ???????//数据被inner操作返回,inner属于outer,所以需要将inner返回出去(跟外界建立联系) ???????return inner; ???} ???//将局部变量生命周期提升于inner函数相同,inner存在,局部变量data就一直存在 ???var inner = outer();
2.2闭包解决变量污染
现有一个列表,点击某个时,弹出下标
<script type="text/javascript"> ???// 需求:点击li,打印li在ul中的索引 => 0, 1, 2, 3, 4 ???// 1.lis ????var lis = document.querySelectorAll(‘ul li‘); ???// 2.循环绑定 ???for (var i = 0; i < lis.length; i++) { ???????// 解决的原理:一共产生了5个外层函数,存储的形参i的值分别是0, 1, 2, 3, 4 ???????// 内层函数也产生了5个,且和外层函数一一对应,打印的i就是外层函数的形参i ???????// 外层函数 ???????(function (i) { ???????????// 内层函数:闭包 ???????????lis[i].onclick = function () { ???????????????alert(i) ???????????} ???????})(i) ???????} ???console.log(i); ?// 点击事件触发一定晚于该逻辑语句 ???// 所以再去触发点击,弹出i的值,永远是5 ???// 该类问题就称之为变量污染</script>
ES6的块级作用域的语法也可以解决循环绑定变量污染的问题
let lis = document.querySelectorAll(‘li‘); ???for (let i = 0; i < lis.length; i++) { ???????lis[i].onclick = function () { ???????????alert(i) ???????} ???}
二、JS的面向对象
1.面向对象初始
var obj = {}; | var obj = new Object();// 属性obj.prop = "";|obj[‘name‘]="";// 方法obj.func = function () {}// 删除属性与方法delete obj.propdelete obj.func
2.类字典结构使用
js中没有字典(键值对存储数据的方式),但可以通过对象实现字典方式存储数据,并使用数据
var dict = {name: "zero", age: 18}var dict = {"my-name": "zero", fn: function () {}, fun () {}}//使用dict.name | dict["my-name"] | dict.fn()
总结:
1.key全为字符串形式,但存在两种书写方式
2.key在js语法标识符支持情况下,可以省略引号,但key为js非法标识符的情况下,必须添加引号。
3.value可以为任意类型
4.访问值可以通过字典名(对象名).key语法与[“key”]语法来访问value
5.可以随意添加key与value完成增删改查
// 增dict.key4 = true;console.log(dict);// 删delete dict.key4;console.log(dict);// 改dict["my-key3"] = [5, 4, 3, 2, 1];console.log(dict);// 查console.log(dict.key1);console.log(dict["key1"]);
3.构造函数
构造函数其实就是普通函数
特定的语法与规定:
1.一般采用首字母大写(大驼峰)
2.内部可以构建属性与方法,通过this关键词
// 普通函数function fn() { ???var num = 10; ???console.log(‘普通函数‘);}fn();//构造函数function People(name) { ???this.name = name; ???this.eat = function (agr) { ???????console.log(this.name + "吃" + agr); ???}}
构造函数可以创建多个对象,使用{}构建出的对象是唯一的
var p1 = new People("zero"); ?// new关键词, 创建对象并实例化var p2 = new People("seven");var obj = {} //对象唯一
构造函数的属性变量与{}的语法规则不一样,构造函数内部通过this,二普通对象直接通过对象名.的方式
function People(name) { ???this.name = name; ???this.eat = function (agr) { ???????console.log(this.name + "吃" + agr); ???}}//普通对象var obj = { ???index: "obj对象", ???fn: function () { ???????console.log("obj方法"); ???}};// 使用属性与方法console.log(obj.index);obj.fn();
4.继承
1.完成继承,必须拥有两个构造函数
2.一个函数要使用另外一个函数的属性与方法,需要对其进行继承(属性与方法的复用)
4.1 ES5的继承
属性的继承用call方法,在继承函数中由被继承函数调用,传入继承函数的this与被继承函数创建属性对属性进行赋值的所有需要的数据
方法的继承prototype原型
???// 类似于父级 ???function Sup(name) { ???????// 属性存放某个值 ???????this.name = name; ???????// 方法完成某项功能 ???????this.func = function () { ???????????console.log("func"); ???????} ???} ???var sup = new Sup("supClass"); ???console.log(sup.name); ???sup.func(); ???// 类似于子级 ???function Sub(name) { ???????// 属性的继承 ???????Sup.call(this, name);//Sup有name属性,那么可以通过call将Sub的name传给Sup ???} ???// 方法的继承 ???Sub.prototype = new Sup; //将new Sup赋值给Sub.prototype ???var sub = new Sub("subClass"); ???console.log(sub.name); ???sub.func(); ???// 原型 ???console.log(sup.__proto__);
4.2 ES6继承
// 多对象 => 创建类 ???class Person { ???????// 构造器:创建对象完成初始化操作 ???????constructor (name, age) { ???????????this.name = name; ???????????this.age = age; ???????} ???????// 实例方法:只能由对象调用 ???????eat () { ???????????console.log(this.name + ‘吃吃吃‘); ???????} ???????// 类方法:只能由类调用 ???????static create () { ???????????console.log(‘诞生‘); ???????} ???} ???let p1 = new Person(‘zero‘, 8); ???let p2 = new Person(‘seven‘, 58); ???console.log(p1.age); ???p2.eat(); ???// Person.eat(); ???Person.create(); ???// p2.create(); ???// 继承 ???class Student extends Person { ???????constructor (name, age, sex) { ???????????// super指向父级 ???????????super(name, age); ???????????this.sex = sex; ???????} ???} ???let s1 = new Student("张三", 18, "男"); ???// 属性的继承 ???console.log(s1.name, s1.age, s1.sex); ???console.log(); ???// 方法的继承 ???s1.eat(); ???// 继承为全继承 ???Student.create();
补:ES6用箭头语法表示函数
// 函数let f = () => {}
5.属性解决循环绑定变量污染
还是用之前的变量污染的例子,js代码看下面
???var lis = document.querySelectorAll(‘li‘); ???for (var i = 0; i < lis.length; i++) { ???????// lis[i]依次代表五个li页面元素对象 ???????// 给每一个li设置一个(临时)属性 ???????lis[i].index = i; ?// 第一个li的index属性存储的就是索引0,以此类推,最后一个存储的是索引4 ???????lis[i].onclick = function () { ???????????// var temp = lis[i].index; // lis[i]中的i一样存在变量污染 ???????????var temp = this.index; ?// 当前被点击的li ???????????alert(temp) ?// temp => this.index(lis[i].index) => i(索引) ???????} ???}
三、定时器
应用场景:
1.完成js自启(不需要手动触发)动画
2.css完成不了的动画
setInterval 一次性定时器
setTimeout 持续性定时器
// 一次性定时器 ???/* 异步执行 ???????setTimeout(函数, 毫秒数, 函数所需参数(可以省略)); ???*/ ???console.log("开始"); ???setTimeout(function (data) { ???????console.log(data); ???}, 1000, "数据"); ???console.log("结束"); ???// 持续性定时器 ???/*异步执行 ???????setInterval(函数, 毫秒数, 函数所需参数(可以省略)); ???*/ ???console.log("又开始"); ???var timer = setInterval(function() { ???????console.log("呵呵"); ???}, 1000) ???console.log(timer); ???console.log("又结束");
清除定时器
1.持续性与一次性定时器通常都应该有清除定时器操作
2.清除定时器操作可以混用 clearTimeout() | clearInterval()
3.定时器的返回值就是定时器编号,就是普普通通的数字类型
???document.onclick = function () { ???????console.log("定时器清除了"); ???????clearInterval(timer); ???????// clearTimeout(timer); ???} ???// 清除所有定时器 ???// 如果上方创建过n个定时器,那么timeout值为n+1 ???var timeout = setTimeout(function(){}, 1); ???for (var i = 0; i < timeout; i++) { ???????// 循环将编号[0, n]所有定时器都清除一次 ???????clearTimeout(i) ???} ???// 1.允许重复清除 ???// 2.允许清除不存在的定时器编号
JS高级
原文地址:https://www.cnblogs.com/mangM/p/9807237.html