var scope = 'top';
var f1 = function() {
console.log(scope);
};
f1(); // 輸出 top
var f2 = function() {
var scope = 'f2';
f1();
};
f2(); // 輸出 top
複製代碼
當一個函數返回它內部定義的一個函數時,就產生了一個閉包, 閉包不但包括被返回的函數,還包括這個函數的定義環境node
var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter1 = generateClosure();
var counter2 = generateClosure();
console.log(counter1()); // 輸出 1
console.log(counter2()); // 輸出 1
console.log(counter1()); // 輸出 2
console.log(counter1()); // 輸出 3
console.log(counter2()); // 輸出 2
複製代碼
上面這個例子解釋了閉包是如何產生的:counter1 和 counter2 分別調用了 generate- Closure() 函數,生成了兩個閉包的實例,它們內部引用的 count 變量分別屬於各自的 運行環境。咱們能夠理解爲,在 generateClosure() 返回 get 函數時,私下將 get 可 能引用到的 generateClosure() 函數的內部變量(也就是 count 變量)也返回了,並在內存中生成了一個副本,以後 generateClosure() 返回的函數的兩個實例 counter1 和 counter2 就是相互獨立的了。數組
var generateClosure = function() {
var count = 0; //私有變量
var get = function() {
count ++;
return count;
};
return get;
};
var counter = generateClosure();
console.log(counter()); // 輸出 1
console.log(counter()); // 輸出 2
console.log(counter()); // 輸出 3
複製代碼
在函數中經過返回一個子函數,對外部暴露一個訪問和更新內部變量的接口,外部不能直接訪問函數做用域內的變量,完成了對變量私有化的隱藏瀏覽器
上下文對象就是 this 指針,即被調用函數所處的環境閉包
JavaScript 的任何函數都是被某個對象調用的,在最外部全局做用域中,調用它的是全局對象app
this 指針不屬於某個函數,而是函數調用時所屬的對象。也就是說誰調用的函數,this就指向誰函數
var someuser = {
name: 'Tom',
func: function() {
console.log(this.name);
}
};
var foo = {
name: 'foobar'
};
someuser.func(); // 輸出 Tom
foo.func = someuser.func;
foo.func(); // 輸出 foobar
name = 'global';
func = someuser.func;
func(); // 輸出 global
複製代碼
在 JavaScript 中,本質上,函數類型的變量是指向這個函數實體的一個引用,在引用之間賦值不會對對象產生複製行爲。咱們能夠經過函數的任何一個引用調用這個函數,不一樣之處僅僅在於上下文ui
使用原型和構造函數初始化對象屬性的區別:this
//原型方式
function Person() {
}
Person.prototype.name = 'Tom';
Person.prototype.showName = function () {
console.log(this.name);
};
var person = new Person();
person.showName();
//構造函數方式
function Person(){
this.name = 'Tom';
this.showNmae = function(){
console.log(this.name);
}
}
var person = new Person();
person.showName();
複製代碼
function Foo() {
}
Object.prototype.name = 'My Object'; Foo.prototype.name = 'Bar';
var obj = new Object();
var foo = new Foo();
console.log(obj.name); // 輸出 My Object
console.log(foo.name); // 輸出 Bar
console.log(foo.__proto__.name); // 輸出 Bar
console.log(foo.__proto__.__proto__.name); // 輸出 My Object
console.log(foo. __proto__.constructor.prototype.name); // 輸出 Bar
複製代碼
平常開發中,若是隻須要複製基本的屬性時(基本類型、對象、數組等,不包含函數與特殊對象new Date()、正則等),使用JSON序列化再反序列化的方法是最便捷的方式spa
JSON.parse(JSON.stringify(obj))
複製代碼
Object.prototype.clone = function() {
var newObj = {};
for (var i in this) {
if (typeof(this[i]) == 'object' || typeof(this[i]) == 'function') {
newObj[i] = this[i].clone();
} else {
newObj[i] = this[i];
} }
return newObj;
};
Array.prototype.clone = function() {
var newArray = [];
for (var i = 0; i < this.length; i++) {
if (typeof(this[i]) == 'object' || typeof(this[i]) == 'function') {
newArray[i] = this[i].clone();
} else {
newArray[i] = this[i];
} }
return newArray;
}
Function.prototype.clone = function () {
var that = this;
var newFun = function newFun() {
return that.apply(this, arguments); //這裏構成了閉包
};
for (var i in this) {
newFun[i] = this[i];
}
return newFun;
}
複製代碼
WeakMap對象是一組鍵/值對的集合,其中的鍵是弱引用的。其鍵必須是對象,而值能夠是任意的 遍歷對象時使用WeakMap結構存儲,遇到循環引用的對象,經過WeakMap.prototype.has(key)與WeakMap.prototype.get(key)來終止循環遍歷問題prototype
function isObj(obj) {
return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
}
function deepCopy(obj, mapObj = new WeakMap()) {
if(mapObj.has(obj)) return mapObj.get(obj)
let cloneObj = Array.isArray(obj) ? [] : {}
mapObj.set(obj, cloneObj)
for (let key in obj) {
cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], mapObj) : obj[key];
}
return cloneObj
}
複製代碼