闭包是什么?
-
犀牛书:函数变量可以保存在函数作用域内,从技术角度讲,所有函数都是闭包 function bar(){
let n = 0;
}
-
高级程序设计:闭包是指有权访问另一个函数作用域中变量的函数(函数没导出) function foo(){
let n = 0;
function bar(){
console.log(n)
};
bar();
}
foo()
-
你不造的js: 当函数可以记住并访问所在的词法作用城时,就产生了闭包,即使函数是在当前词法作用域之外执行。 function foo(){
let n = 0;
return function bar(){
console.log(n);
};
}
foo()();
-
MDN:一个函数和对其周围状态(词法环境) 的引用捆绑在一起(或者说函数被引用包围) ,这样的组合就叫闭包。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
总结 参考常见形式便于理解
-
函数的执行,导致函数被定义;(被定义的函数可以拿到父函数的变量) -
闭包和函数的定义有关 -
this和函数的执行方式有关
不是闭包的例子:
function foo(fn){
let n = 0;
fun();
}
function text(){
console.log(n);
}
foo(test);
闭包常见形式:
-
函数的返回值是函数 function foo(){
let n = function(){
}
return n;
}
-
函数内全局定义函数 let func;
function foo(){
let n = 1;
func = function(){console.log(n)};
}
-
函数参数 let func = function(fn){
console.log(fn())
};
function foo(){
let a = 'aaa';
let n = function(){return a};
func(n)
}
foo();
(function(){
let a = 'aaa';
let n = function(){return a};
func(n)
})()
-
循环赋值 function foo(){
let arr = [];
for(var i =0; i<10; i++){
arr[i] = function(){
console.log(i);
}
}
return arr;
}
let bar = foo();
bar[0]()
this指向
默认全局变量为 window
优先级:new>显示绑定>隐式绑定>默认绑定
function函数
-
默认绑定
独立调用,指向window
console.log(this===window)
-
隐式绑定
谁调用就指向谁
函数执行才会有this,每个函数都有自己的this,this指向是否相等由函数执行方式决定 let obj = { foo : function(){ console.log(this);
-
显示绑定
call,apply,bind
-
new绑定
指向实例化对象
function obj(){ let this = {}; .................... return this;}
如果构造函数return this之外的东西,生成的对象和this指向: function foo(){ this.a = 2; console.log(this);
function foo(){ this.a = 2; console.log(this);
function foo(){ this.a = 2; console.log(this);
箭头函数
本身没有this,不受绑定影响,this指向由外层函数作用域决定
function foo(){ console.log(this); let test = ()=>{ console.log(this); } return test;} let obj1 = { foo : foo}let obj2 = { foo : ()=>{ console.log(this); }}let o = obj1.foo();
做做题把~~
function foo(s){ this.a = s;}let obj = {};let bar = foo.bind(obj);bar(2);console.log(obj.a);let baz = new bar(3);console.log(obj.a);console.log(baz.a);
let name = 'window'let obj1 = { name : '1', fn1 : function () { console.log(this.name); }, fn2 : ()=> console.log(this.name), fn3 : function(){ return function(){ console.log(this.name); } }, fn4 : function(){ return ()=> console.log(this.name); }}let obj2 = { name : '2'}obj1.fn1(); obj1.fn1.call(obj2);obj1.fn2();obj1.fn2.call(obj2);obj1.fn3()();obj1.fn3().call(obj2);obj1.fn3.call(obj2)();obj1.fn4()();obj1.fn4().call(obj2);obj1.fn4.call(obj2)();
拷贝
定义
-
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。 -
深拷贝是将一个对象从内存中完整的拷贝份出来 ,从堆内存中开辟一 个新的区域存放新对象,且修改新对象不会影响原对象。
区别
- 赋值:当我们把一个对象赋值给个新的变量时, 赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
- 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
- 深拷贝:从堆内存中开辟一个新的区域存放新对象, 对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
|