目录
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>
//js
const 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); // undefined
var 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 结果:undefined
console.log("a.prototype:" , a.prototype)//undefined
console.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选择器');
break
case '.':
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>