• js 高级


    1、函数回调

    // 回调的函数
    function callback(data) {}
    // 逻辑函数
    function func(callback) {
        // 函数回调
        if (callback) callback(data);
    }
    
    // 函数回调的本质:在一个函数中(调用函数),当满足一定条件,调用参数函数(回调函数)
    // 回调函数作为调用函数的参数传入
    // 回调函数通过参数将调用还是内部数据传出
    
    <script type="text/javascript">
    	// 函数回调
    	// 在一个函数(fn)中,满足条件情况下,调用另外一个函数(func)
    	// 注:func函数 是 fn函数 的参数(函数作为函数参数传入)
    
    	// 解决问题:
    	// 请求数据 => 数据(return | 函数回调) => 外界
        
    	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.形成了函数回调,回调的函数可以获取调用函数的局部变量(将数据携带出去)
    </script>
    
    //函数回调在系统中的使用 
    <script type="text/javascript">
    	// 通常情况下,我们的页面标签存不存在点击事件? => 存在
    	// 点击事件触发后,可不可以对外传送数据 => 可以,eg:点在页面的什么位置
    	// 系统已经书写好了这种函数回调,但是没有回调体,回调体(回调函数)由普通开发者提供
    
    	// 钩子:满足条件情况下被系统回调的函数(方法),称之为钩子函数(方法) <=> 回调函数
    	document.onclick = function (a, b , c) {
    		console.log("点击事件");
    		console.log(a, b , c);
    	}
    </script>
    

    2、闭包

    function outer() {
        var data = {}
        function inner() {
            return data;
        }
        return inner;
    }
    
    // 闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
    // 闭包本质:函数的嵌套,内层函数称之为闭包
    // 闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染
    
    <script type="text/javascript">
    	// 闭包: 函数的嵌套定义,内层函数就是闭包
    	// 闭包产生的原因: 
    	// 1.函数会产生局部作用域, 外部需要使用 -- 返回值 | 函数回调 | 闭包 | 提升作用域
    	// 2.在外部另一个函数中使用该局部变量 -- 函数回调 | 闭包
    	// 3.不能使用函数回调(函数已有固定参数,或不能拥有参数),只能将函数定义到拥有局部变量函数的内部 => 闭包
    	// 总结:一个函数要使用另外一个函数的局部变量
    
    	// 提升作用域
    	var a;  // 作用域被提升
    	function fn() {
    		a = 10;  // 局部变量 => 在外部定义
    	}
    	fn();
    	// 外部使用局部变量: 返回值 | 函数回调 | 闭包 | 提升作用域
    	console.log(a);
    
    	// 好处: 
    	// 1.外部函数a_fn不需要强制拥有参数以及返回值
    	// 2.外部函数的局部变量也无需提升作用域,可以保证参数的安全性
    	// 3.内部函数b_fn也不需要强制拥有参数与返回值,便可以直接使用外部函数a_fn的局部变量data
    	function a_fn() {
    		var data = [1, 2, 3, 4, 5];
    		// 闭包
    		function b_fn() {
    			console.log('>>>', data);
    		}
    		b_fn();
    	}
    	a_fn();
    	// 闭包使用:
    	// 外部函数在外部调用
    	// 内部函数在(外部函数)内部调用
    </script>
    
    //闭包解决局部变量生命周期
    <script type="text/javascript">
    	function outer() {
    		// eg: 请求得到的数据,如何不持久化,方法执行完毕后,数据就会被销毁
    		var data = [1, 2, 3, 4, 5];
    		console.log(data);
    		// 通过闭包解决该类问题,所以闭包所以代码均可以随意自定义
    		function inner() {
    			return data;
    		}
    		// 数据被inner操作返回,inner属于outer,属于需要outer将inner返回出去(跟外界建立起联系)
    		return inner;
    	}
    	// 将局部变量生命周期提升于inner函数相同,inner存在,局部变量data就一直存在
    	var inner = outer();
    	console.log(inner());
    </script>
    
    //闭包解决变量污染
    <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>
    

    二、循环绑定

    .html文件
    <ul>
    	<li>列表项</li>
        <li>列表项</li>
        <li>列表项</li>
    </ul>
    
    .js文件
    var lis = document.querySelector('li');
    for (var i = 0; i < lis.length; i++) {
        lis[i].onclick = function () {
            // 打印列表项的索引
    		console.log(i);
    	}
    }
    // 变量污染
    // 获取局部作用域解决
    // 闭包解决
    // 对象属性解决
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<meta charset="UTF-8">
    	<title>属性解决变量污染</title>
    	<style type="text/css">
    		ul {
    			margin: 0;
    			padding: 0;
    			list-style: none;
    		}
    		li {
    			 80px;
    			height: 35px;
    			background-color: pink;
    			border-radius: 5px;
    			float: left;
    			margin-left: 3px;
    		}
    	</style>
    </head>
    <body>
    	<ul>
    		<!-- 通过html方式给标签添加全局属性 -->
    		<li arg="10"></li>
    		<li></li>
    		<li></li>
    		<li></li>
    		<li></li>
    	</ul>
    </body>
    <script type="text/javascript">
    	// 学习目的:对象的(临时)属性可以帮助存储临时数据,因为临时数据的生命周期往往很短.需要提示临时数据的生命周期
    	// 临时数据会随属性的消亡而消亡 | 被主动移除(delete)
    	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(索引)
    		}
    	}
    	// 属性的使用:****
    </script>
    <script type="text/javascript">
    	var lis = document.querySelectorAll('li');
    
    	console.log(lis); // 页面元素集合
    	console.log(lis[0]); // 页面元素
    	// 对象可以添加属性与方法 | 万物皆对象
    	
    	lis.name = "元素集合";
    	console.log(lis.name);  // lis => 是对象,页面元素集合对象
    
    	lis[0].fn = function () {
    		console.log('li fn');
    	}
    	lis[0].fn();  // 每一个页面元素都是对象
    
    	// 通过html方式给第一个li添加了一个全局属性arg
    	console.log(lis[0].arg);  // js无法直接获取
    	// 总结:
    	// 1.js要使用页面元素属性,需要通过js手段给页面对象手动添加属性,添加的属性不会渲染到html标签中
    	// 2.通过html手动主动给标签添加的全局属性,js无法访问,但是可以参与css布局
    </script>
    <style type="text/css">
    	li[arg="10"] {
    		background-color: orange;
    	}
    </style>
    </html>
    

    三、面向对象JS

    1、属性与方法

    var obj = {}; | var obj = new Object();
    // 属性
    obj.prop = "";
    // 方法
    obj.func = function () {}
    // 删除属性与方法
    delete obj.prop
    delete obj.func
    
    <script type="text/javascript">
    	// 创建一个对象
    	var obj = {}
    
    	// 对象一定拥有属性与方法
    
    	// 属性
    	obj.name = "大毛";
    	obj["age"] = 18;
    	// 打印对象
    	console.log(obj);
    	// 使用属性
    	console.log(obj["name"]);
    	console.log(obj.age);
    
    	// 方法
    	obj.eat = function () {
    		console.log("吃吃吃!!!");
    	}
    	// 方法的使用
    	obj.eat();
    
    	// 注:可以对对象任意添加属性和方法
    
    	// 属性|方法的移除
    	delete obj.name
    
    	console.log(obj);
    
    </script>
    

    2、类字典结构使用

    • 结构
    var dict = {name: "zero", age: 18}
    
    • 拓展
    var dict = {"my-name": "zero", fn: function () {}, fun () {}}
    
    • 使用
    dict.name | dict["my-name"] | dict.fn()
    
    //对象类字典结构使用
    <script type="text/javascript">
    	// 为什么要学对象?
    	// js获取页面元素,操作页面元素内容与样式
    	// 数据,面向对象思想让操作数据更加便捷与容易
    
    	// js中没有字典(键值对存储数据的方式),但可以通过对象实现字典方式存储数据,并使用数据
    	var dict = {
    		key1: "value1",
    		key2: 18,
    		"my-key3": [1, 2, 3, 4, 5]
    	}
    	// 总结:
    	// 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"]);
    
    </script>
    

    3、构造函数(ES5)

    function People(name, age) {
        this.name = name;
        this.age = age;
        this.eat = function () {
            return 'eat';
        }
    }
    
    <script type="text/javascript">
    	// 万物皆对象
    	// var num = 3.14;
    	// console.log(num.toFixed(1));
    
    	// 普通函数
    	function fn() {
    		var num = 10;
    		console.log('普通函数');
    	}
    	fn();
    	// 构造函数其实就是普通函数
    	// 特定的语法与规定:
    	// 1.一般采用首字母大写(大驼峰)
    	// 2.内部可以构建属性与方法,通过this关键词
    	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");
    	// 使用属性
    	console.log(p1.name);
    	console.log(p2.name);
    	// 使用方法
    	p2.eat("霸王餐");
    	// p1,p2就是People构造函数创建出来的对象
    	console.log(p1);
    </script>
    <!-- 
    	总结:
    	1.构造函数可以创建多个对象,{}构建出的对象是唯一的
    	2.属性与变量的语法规则不一样
     -->
    <script type="text/javascript">
    	var obj = {
    		index: "obj对象",
    		fn: function () {
    			console.log("obj方法");
    		}
    	};
    	// 使用属性与方法
    	console.log(obj.index);
    	obj.fn();
    

    4、继承(ES5)

    // 父级
    function Sup(name) {
        this.name = name;
        this.fn = function () {
            console.log('fn class');
        }
    }
    // 原型
    console.log(Sup.prototype);
    console.log(sup.__proto__);
    // 子级
    function Sub(name) {
        // 继承属性
        Sup.call(this, name);
    }
    // 继承方法
    Sub.prototype = new Sup;
    // 创建子级对象
    var sub = new Sub("subClass");
    // 使用属性
    console.log(sub.name);
    // 使用方法
    sub.fn();
    
    // 指向自身构造函数
    Sub.prototype.constructor = Sub;
    
    <script type="text/javascript">
    	// ***
    	// 面向对象的三大特性: 继承 封装 多态
    
    	// js重点:继承
    
    	// 1.完成继承,必须拥有两个构造函数
    	// 2.一个函数要使用另外一个函数的属性与方法,需要对其进行继承(属性与方法的复用)
    	// 3.属性的继承call方法,在继承函数中由被继承函数调用,传入继承函数的this与被继承函数创建属性对属性进行赋值的所有需要的数据,eg:如Sup有name属性,那么可以通过call将Sub的name传给Sup
    	// 4.方法的继承prototype原型,将new Sup赋值给Sub.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);
    	}
    	// 方法的继承
    	Sub.prototype = new Sup;
    
    	var sub = new Sub("subClass");
    	console.log(sub.name);
    	sub.func();
    
    	// 原型
    	console.log(sup.__proto__);
    
    </script>
    

    5、类及继承(ES6)

    // 父类
    class People {
        // 构造器
        constructor (name, age) {
            this.name = name;
            this.age = age;
        }
        // 实例方法
        eat () {
            console.log('吃吃吃');
        }
        // 类方法
        static create () {
            console.log('诞生');
        }
    }
    // 子类
    class Student extends People {
        constructor (name, age) {
            // super关键词
            super(name, age)
        }
    }
    
    <script type="text/javascript">
    	// 单一对象
    	let obj = {
    		name: "ooooobj",
    		// 方法
    		fn () {
    			console.log("fnnnnnnnn");
    		}
    	}
    	console.log(obj.name);
    	obj.fn();
    	// 函数
    	let f = () => {
    	}
    </script>
    <script type="text/javascript">
    	// 多对象 => 创建类
    	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();
    </script>
    

    四、定时器

    setInterval(持续性定时器)

    setInterval(函数, 毫秒数, 函数所需参数(可以省略));
    var timer = setInterval(function() {console.log("呵呵");}, 1000)
      
    

    setTimeout(一次性定时器)

    setTimeout(函数, 毫秒数, 函数所需参数(可以省略));
    setTimeout(function (data) {console.log(data);}, 1000, "数据");
     
    
    // 清除定时器
    	// 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)
    	}
    
    <script type="text/javascript">
    	// 应用场景
    	// 1.完成js自启(不需要手动触发)动画
    	// 2.css完成不了的动画
    
    	// 一次性定时器
    	// 1.语法 2.参数列表 3.同步异步
    
    	/* 异步执行
    		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.允许清除不存在的定时器编号
    </script>
    
  • 相关阅读:
    一起谈.NET技术,SharePoint开发笔记SharePoint2010添加ASP.NET应用程序 狼人:
    一起谈.NET技术,系统架构技能之设计模式—代理模式 狼人:
    一起谈.NET技术,.NET中的异步编程(一)为什么需要异步 狼人:
    一起谈.NET技术,Microsoft NLayerApp案例理论与实践 项目简介与环境搭建 狼人:
    一起谈.NET技术,构建高性能ASP.NET站点之减少不必要的请求 狼人:
    一起谈.NET技术,分享在MVC3.0中使用jQuery DataTable 插件 狼人:
    一起谈.NET技术,ASP.NET 4的Demo实践:URL路由改进支持 狼人:
    一起谈.NET技术,构建高性能ASP.NET站点之优化HTTP请求 狼人:
    一起谈.NET技术,Silverlight 游戏开发小技巧:传说中的透视跑马灯 狼人:
    paip.Winista HTMLParser文本结点的获取
  • 原文地址:https://www.cnblogs.com/layerluo/p/9800753.html
Copyright © 2020-2023  润新知