一、闭包
闭包:"利用作用域的嵌套,将原本的局部变量,进化成自由(私有)变量的环境"
闭包的原理:
局部作用域,局部变量的生命周期,朝生暮死
利用作用域的嵌套,触发计算机的垃圾回收机制,将原本要删除的变量,暂时保存起来,可以继续使用
垃圾回收机制:将要删除的数据,先暂时存放在一个临时空间内,不立即删除,如果需要再次使用,可以直接找到该数据,继续使用,直到真正不用了,再被删除
- 1、(for)循环中的异步
for循环之中的i变量会因为for的循环次数被覆盖,所以在for循环内部存在函数时,而且这个函数内会调用i变量,这种情况下就需要用到闭包。
for(var i=0;i<10;i++){
console.log(i); //可以访问到每次的i
}
" 必须满足两个条件:
1.在for循环内存在函数
2.函数内会调用这个变量"
var ali = document.getElementsByTagName("li");
for(var i=0;i<10;i++){
ali[i].onclick = function(){
console.log(i); //在函数内部就无法访问到外部变量
}
}
如何形成闭包
var ali = document.querySelectorAll("li");
// 用法一: 用法一和用法二都是通过匿名函数形成作用域
for(var i=0;i<ali.length;i++){
(function(index){
ali[index].onclick = function(){
console.log(index);
}
})(i)
}
// 用法二:
for(var i=0;i<ali.length;i++){
ali[i].onclick = (function(index){
return function(){
console.log(index);
}
})(i);
}
// 用法三:借助 let/cont 触发之后形成块级作用域,形成闭包,把i的值传到内部的作用域中
for(let i=0;i<ali.length;i++){
ali[i].onclick = function(){
console.log(i);
}
}
利用匿名函数将i保存起来了
"一旦内部函数调用外部函数的局部变量,那么这个时候,这个局部变量就会变成内部函数的私有变量"
- 2、计时器(setTimeout)的回调函数的传参时(还有事件委托的封装也是闭包--day14):
setTimeout(function (a){
console.log(a); //两秒后,undefined 函数被放到setTimeout内部里,内部只有执行,没有传参进去
}, 2000);
或
setTimeout(fn("hello"), 5000);
function fn(str{
console.log(str); //没有延迟,立即打印hello 任何情况下函数名+()都是立即执行
}
使用闭包:
function fn(a){
return function(){
console.log(a); // 三秒后,打印10
}
}
// function(){console.log(a);} // 作为fn内部的一个小函数,是一个独立的作用域,可以拿到外面的fn(str)的参数str,将其临时保存起来,等setTimeout到时间了就执行这个小函数
var f = fn(10); // fn做参数,把10传入a中
setTimeout(f, 3000);
优点:可以将要删除的数据,保存起来,继续使用,方便
可以在函数外部操作内部的数据
缺点:因为要删除的数据,没有被删除,继续存起来,那么占内存,耗性能
在外部有可能改变内部的数据
"闭包就是将作用域内部和外部连接起来的桥梁"
闭包
var a = 10;
function fn(){
var a = 20;
return function(){
console.log(a++);
}
}
var f = fn();
f();
"函数:定义上下文,执行上下文(this)"
"函数执行时,在函数的内部可以拿到自身的定义作用域中的变量"
作用域链----查资料,理解写法原理
代码是在运行状态下被执行的,运行在内存中(内存:运行结束后立即删除,硬盘里的东西不会删)
二、趣味性方法:eval
eval();
参数:(只能是)字符
功能:将字符解析成js代码
var str = "1+1";
console.log(str); // 1+1
console.log(eval(str)); // 2
var str = "hello";
console.log(eval(str)); // 报错,把str解析成js代码就报错
var str = "console.log(123)";
var str = '[{"name":"admin"},]';
var str = '[{name:"admin"}]';
var str = '{"name":"admin"}';
console.log(str);
console.log(eval(str));
console.log(JSON.parse(str));
三、继承
继承:子承父业;一个原本没有某些方法或属性的对象,统一写方法,拿到了另外一个对象的属性和方法
改变this指向继承(构造函数继承):继承构造函数中的属性和方法
优点:简单方便易操作,可以多继承
缺点:只能继承构造函数,不能继承原型
构造函数创建对象
function Fn(){
this.name = "admin";
}
Fn.prototype.init = function(){
console.log(this.name)
}
var f1 = new Fn();
var f2 = new Fn();
console.log(f1);
console.log(f2);
console.log(f1 == f2); // false;
bind()
call()
apply()
var obj = {
name:"admin",
show:function(){
console.log(this.name)
}
}
var obj2 = {
name:"root"
}
obj.show(); // admin
// obj2.show();
obj.show.bind(obj2)(); // root
obj.show.call(obj2); // root
obj.show.apply(obj2); // root
原型对象继承:继承原型
优点:简单,方便,可以继承原型身上的方式和属性
缺单:只能继承原型,不方便传参
原型对象继承:继承原型
优点:简单,方便,可以继承原型身上的方式和属性
缺单:只能继承原型,不方便传参