目录
1.闭包概念
1.1简单demo1:
1.2简单demo2
1.3使用let代替var解决这个问题
2.函数对象和原型链
编辑
2.1函数对象demo
2.2.原型链demo
3.使用闭包完成JQuery的一个小demo
1.闭包概念
1.当函数声明时,函数会通过内部属性[scope]来创建范围 2.闭包一个函数包着一个函数,闭包是一个函数加上创建函数的作用域的连接,闭包"关闭"了函数的自由变量理解:1.2个函数 2个函数作用域[scope]还要连接上;2.关闭函数的变量自由,暂时不会销毁(有时会导致内存泄露) 3.无意间共享环境(可以通过闭包解决)
ps:js跟java有一个很大的区别就是,事件函数会延时执行,比如在一个for循环中,里面再执行一个内部方法,java中的内部方法是及时响应并执行完整。但是再js由于事件还未触发会导致,再循环中变量已经被多次执行结束已经被修改,点击的时候需要返回到,在这方法刚被赋予的时候的状态。所以就就需要有一个变量在整个周期中去存储当前执行状态,来保证再次被执行的时候正确。
1.1简单demo1:
问题:
使用闭包解决
特点
function fun(n) {
//此时这个匿名函数就叫做闭包return function (m) {n += m;return n;}
}
//会导致内存泄露,一直不回注销
const f = fun(1)
console.log(f(1))
1.2简单demo2
//标签
<ul><li>1</li><li>2</li><li>3</li>
</ul>
//jsconst lis = document.getElementsByTagName("li")for (var i = 0; i < lis.length; i++) {function () {lis[i].onclick = function () {console.log(i)}}
//点击li展示为,因为每次输出i的时候找上级
3 3 3
解决方法
const lis = document.getElementsByTagName("li")for (var i = 0; i < lis.length; i++) {//function匿名函数就是一个闭包函数(function () {//使用访问函数记住它运行的环境var idx = i;lis[i].onclick = function () {console.log(idx)}})()
//输出1,2,3
1.3使用let代替var解决这个问题
因为var的做用户是函数的作用域,所以共享会导致该问题,但入伏哦使用块级就可以解决该问题
/*1.块级作用域,而而不是函数作用域,此时let变量的作用域被限制在最近的一次花括号内,不会提升到整个函数作用域2.暂时性死区console.log(x); // 会报错let x = 5;//------console.log(y); // undefinedvar y = 5;3.不允许重复声明4.更好的循环,避免常见作用域错误*/for (let i = 0; i < lis.length; i++) {lis[i].onclick = function () {// alert(i)console.log(i)}}
2.函数对象和原型链
函数也是一种特殊的对象,都是继承object,但是在es6之前,没有引用class这个概念,使用prototype(原型对象)和__proto__(实例对象)来进行关联
在Person.prototype之上是object
2.1函数对象demo
class A {constructor(id) {this.id = id}method1() {console.log(this.id)}}A.prototype.bbb=function (){}A.prototype.ccc=function (){}const a = new A(1);a.method1()// a.prototype 结果:undefinedconsole.log("a.prototype:" , a.prototype)//undefinedconsole.log("A.prototype:" , A.prototype)//{ bbb: [Function (anonymous)], ccc: [Function (anonymous)] }console.log("a.__proto__:" , a.__proto__)//{ bbb: [Function (anonymous)], ccc: [Function (anonymous)] }console.log("a.__proto__.constructor:" , a.__proto__.constructor)//[class A]console.log("a.__proto__.constructor.constructor" , a.__proto__.constructor.constructor)//[Function: Function]console.log("A.__proto__:" , A.__proto__)//{}
2.2.原型链demo
例子fun.name,当前先找实例对象new -> 原型对象prototype -> 最后object
<script>// 原型链 :每一个对象都有一个原型(__proto__),// 这个原型还可以拥有自己的原型,形成最终的原型链// 查找一个对象特定的属性或方法,// 先去:当前对象中找->没有找到则取对象中原型查找->如果没有则去对象的对象中->返回null// 函数/类:prototype// 对象:_proto_//原型链做的是继承const Fun = function () {//先从当前对象找this.name="张三"}const fun = new Fun()Fun.prototype.name="李四"// Fun.prototype.prototype.name="王五"// Object.prototype.name="王五"// console.log(fun.__proto__)// console.log(Fun.__proto__)// console.log(Fun.prototype)console.log(fun.name)
</script>
3.使用闭包完成JQuery的一个小demo
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.box1 {}</style>
</head>
<body>
<div class="box1"></div>
<div class="box1"></div>
<div></div>
</body>
<script>function $(str) {//1.先获取对应结点function leo(str) {this.element = []if (str == null) {return false;}const pex = str[0]switch (pex) {case null:return false;case '#':console.log('id选择器');breakcase '.':const elm = str.split('.').at(-1)const elm_doc = document.getElementsByClassName(elm)for (let i = 0; i < elm_doc.length; i++) {this.element.push(elm_doc[i])}break;default:console.log("'#' === str.at(0)", '#' === str.at(0))break;}}//2.添加对应事件leo.prototype = {"css": function (opt) {for (let i = 0; i < this.element.length; i++) {for (let j in opt) {this.element[i].style[j] = opt[j]}}return this;},"click": function (fn) {for (let i = 0; i < this.element.length; i++) {this.element[i].onclick = fn}return this;}}return new leo(str)}let i = 0;$(".box1").css({width: "100px",height: "100px",background: "#FCF9DF",border: "1px solid black "}).click(() => {alert(i++)})
</script>
</html>