閉包復習
- 閉包概念:
封閉空間鲤桥,包裹 - 閉包的作用:
延長變量的聲明周期
保護內部的數(shù)據,代碼更安全
為我們提供一種間接訪問函數(shù)內部私有數(shù)據的方法 - 函數(shù)內部私有數(shù)據的訪問
函數(shù)內部聲明的變量在函數(shù)外部無法訪問
但是有的時候忽匈,我們有訪問(讀取數(shù)據 + 修改數(shù)據)函數(shù)內部私有數(shù)據的需求 - 在函數(shù)內部直接返回數(shù)據
- return
只能獲取值,無法修改值
這種方法獲得的數(shù)據是一次性的數(shù)據蹋绽,多次獲取得到的數(shù)據不是同一份 - 閉包(全世界所有描述 js 的技術文章 32% 在討論閉包)
閉包是持有了本來不屬于自己數(shù)據的函數(shù)
<script>
function demo() {
var a = 10;
return a;
}
var x = demo();
var y = demo();
console.log(x,y);
</script>
<script>
function demo() {
var obj = {name:"張三"};
return obj;
}
var o1 = demo();
var o2 = demo();
console.log(o1 == o2);
</script>
閉包的基本寫法
<script>
function demo() {
var n = 10;
var func = function () {
return n;
}
return func;
}
var f1 = demo();
var x = f1()
var y = f1();
</script>
<script>
function demo() {
var n = {};
var func = function () {
return n;
}
return func;
}
var f1 = demo();
var x = f1()
var y = f1();
console.log(x == y); //true
</script>
# 閉包的寫法01
<script>
function demo() {
var n = {};
var func = function () {
return n;
}
return func;
}
</script>
# 閉包的寫法02
<script>
function demo() {
var n = {};
return function () {
return n;
};
}
var foo = demo();
console.log(foo());
</script>
# 閉包的寫法03
<script>
var foo = (function() {
var n = {};
return function () {
return n;
};
})();
var obj1 = foo();
var obj2 = foo();
console.log(obj1 == obj2);
</script>
# 訪問私有數(shù)據(讀寫)
<script>
function demo() {
var a = 10;
return function (value) {
if (value != undefined)
{
a = value;
}
return a;
}
}
var func = demo();
console.log(func(20));
console.log(func("這是一個字符串"));
console.log(func());
console.log(func(1));
console.log(func());
</script>
# 返回多個數(shù)據 方式一
<script>
function person() {
var name = "張三";
var age = 20;
return function () {
return [name,age];
}
}
var foo = person();
console.log(foo()[0]);
console.log(foo()[1]);
</script>
# 返回多個數(shù)據 方式二
<script>
function person() {
var name = "張三";
var age = 20;
return [function () {
return name;
},function () {
return age;
}]
}
var foo = person();
console.log(foo[0]());
console.log(foo[1]());
</script>
# 返回多個數(shù)據 方式三
<script>
function person() {
var name = "張三";
var age = 20;
return {
getName:function () {
return name;
},
getAge:function () {
return age;
}
}
}
var foo = person();
console.log(foo.getName());
console.log(foo.getAge());
</script>
筆試題練習
<script>
getName(); //3
function getName() {
console.log("1");
}
getName(); //3
function Foo() {
this.getName = function () {
console.log("2");
}
}
function getName() {
console.log("3");
}
new Foo().getName();
</script>
<script>
f2(); //報錯
f1();
f2(); //哈哈
function f1() {
function f2() {
console.log("f2");
}
}
function f2() {
console.log("哈哈");
}
</script>
閉包獲取和設置數(shù)據
<script>
function demo() {
var name = "變形記";
var author = "卡夫卡";
var price = 12.23;
var des = "我是一本書";
function getDes() {
return des;
}
function setDes(value) {
des = value;
}
return {
getName:function () {
return name;
},
getAuthor:function () {
return author;
},
getPrice:function () {
return price;
},
setName:function (value) {
if (value != undefined)
{
name = value;
}
},
setAuthor:function (value) {
if (value != undefined)
{
author = value;
}
},
setPrice:function (value) {
if (value != undefined)
{
price = value;
}
},
getDes:getDes,
setDes:setDes
}
}
var func = demo();
console.log(func.getName());
console.log(func.getAuthor());
console.log(func.getPrice());
// console.log(func.getName("城堡")); //設置
// console.log(func.getName());
func.setName("城堡");
console.log(func.getName());
func.setPrice(30.00);
console.log(func.getPrice());
console.log(func.getDes());
</script>
閉包的作用
- 延長變量的聲明周期
- 保護內部的數(shù)據甥郑,代碼更安全逃魄,做一些數(shù)據檢驗處理
- 為我們提供一種間接訪問函數(shù)內部私有數(shù)據的方法
<script>
var foo = (function () {
var name = "張三";
var age = 20;
return {
getName:function () {
return name;
},
getAge:function () {
return age;
},
setName:function (value) {
name = value;
},
setAge:function (value) {
//檢驗
if (value < 0)
{
value = 0;
}
age = value
}
}
})();
console.log(foo.getName());
foo.setName("李四");
console.log(foo.getName());
// var name = "sss";
// var name = "123";
console.log(foo.getAge());
foo.setAge(-2);
console.log(foo.getAge());
</script>
<script>
function demo() {
var a = 10;
}
demo();
demo();
</script>
setTimeOut 和閉包的執(zhí)行
- 定時器
setTimeOut(只執(zhí)行一次)
setInterval(每個一段時間執(zhí)行一次)
<script>
var date = new Date();
console.log(date);
setTimeout(function () {
console.log("定時器" + new Date);
},2000)
</script>
思考
js 代碼的執(zhí)行頁面渲染任務
js 主要代碼 (for,語句)
事件型的任務(點擊事件,定時器事件)
js 本身是單線程的
進程:系統(tǒng)中正在運行的運行程序澜搅,是 cpu 調度的單位嗅钻,是分配資源的最小單位
線程:進程中真正執(zhí)行任務的部分,是 CPU 調度的最小單位店展, CPU 不會為線程分配資源
關系:包含關系(進程包含線程),一個進程可以擁有多個線程秃流,至少要有一條線程(主線程 - UI 線程)
進程(正在運行的學校)
線程(老師)
線程執(zhí)行任務的時候是串行執(zhí)行:一條線程在執(zhí)行多個任務的時候是按照任務的固定順序一個接著一個的執(zhí)行
多線程:一個進程可以擁有多個線程赂蕴,多條線程在執(zhí)行任務的時候并發(fā)(行)執(zhí)行
多線程的并發(fā)執(zhí)行:多條線程執(zhí)行多個任務,多個任務一起執(zhí)行舶胀,給人感覺在同時執(zhí)行
并發(fā)和秉性的區(qū)別
并發(fā):多個任務同時執(zhí)行(現(xiàn)象)
并行:能力
for (var i = 0; i < 10; i++) {
// setTimeout((function (j) {
// return function () {
// console.log("定時器" + new Date +j );
// }
// })(i),0);
(function (j) {
setTimeout(function () {
console.log("定時器" + new Date +j );
},0);
})(i);
}
div 事件和閉包
<body>
<div>第1個標簽</div>
<div>第2個標簽</div>
<div>第3個標簽</div>
<div>第4個標簽</div>
<div>第5個標簽</div>
<div>第6個標簽</div>
<script>
//01 獲得頁面中所有的div標簽
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
// divs[i].onclick = (function (j) {
// return function () {
// alert("第" + j + "個標簽");
// }
// })(i);
(function (j) {
divs[j].onclick = function () {
alert("第" + j + "個標簽");
}
})(i)
}
</script>
</body>
函數(shù)補充說明
- 函數(shù)的幾種創(chuàng)建方式
- 函數(shù)聲明 function 名稱(參數(shù)1概说,參數(shù)2){函數(shù)體}
- 函數(shù)表達式
var 變量1 = functon 名稱(參數(shù)1,參數(shù)2){函數(shù)體} 命名函數(shù)表達式
var 變量2 = function(參數(shù)1嚣伐,參數(shù)2){函數(shù)體} 匿名函數(shù)表達式 - 使用構造函數(shù)來創(chuàng)建
var func = new Function()
var func01 = function name() {
console.log("func01");
}
var func02 = function () {
console.log("func02");
}
//細微的差別:name(函數(shù)名稱)
//函數(shù)本身是對象糖赔,函數(shù)有屬性(name)
console.log(func01.name); //name
console.log(func02.name); //空 谷歌瀏覽器打印的結果是func02
func01.des = "des";
console.log(func01.des);
var obj = {
name:"張三",
showName:function () {
console.log(this.name);
}
}
delete obj.showName;
obj.showName();
// function demo() {
// var a = 10;
// var b = 20;
// }
//
//
// {
// var a = 10;
// var b = 20;
// }
//
// 函數(shù):函數(shù)是有名字的代碼塊。
// demo();
// demo();
// demo();
函數(shù)的回調
- 函數(shù)回調:函數(shù)作為其他函數(shù)的參數(shù)來使用轩端。
- 需要注意 this 的指向
function foo(callBack,callBackObj) {
//............
if (typeof callBack == "string")
{
callBack = callBackObj[callBack]
}
callBack.call(callBackObj); //以普通函數(shù)方式調用 this(window)
}
function demo() {
console.log("demo");
}
foo(demo);
var dog = {
color:"紅色",
age:0.3,
showAge:function () {
console.log(this.age);
}
}
foo(dog.showAge,dog);
var person = {
color:"紅色",
age:99,
showAge:function () {
console.log(this.age);
}
}
foo(person.showAge,person);
foo("showAge",person); //兼容性處理
函數(shù)作為返回值(計數(shù)器)
function demo() {
var count = 0;
return function () {
return count ++;
}
}
var next = demo();
console.log(next()); //0
console.log(next());
console.log(next());
console.log(next());
console.log(next());
自定義函數(shù)(惰性函數(shù)定義)
- 自定義函數(shù)(惰性函數(shù)定義)
特點:函數(shù)的內容在第二次調用的時候才被正確的定義放典,第一次調用的時候主要做一些初始化處理 + 更新函數(shù) - 使用的場景:
代碼需要做一些一次性的初始化處理
function foo() {
console.log("foo!");
//初始化操作......
foo = function () {
console.log("foo! foo!");
foo = function () {
console.log("foo! foo! foo基茵!");
}
}
}
foo(); // foo!
foo(); // foo! foo!
foo(); // foo! foo! foo奋构!
- 使用注意:
- 添加在函數(shù)對象上面的成員會丟失
- 如果把函數(shù)賦值給變量或者是稱為對象的方法,那么再調用的時候還是執(zhí)行舊的函數(shù)體
function demo() {
console.log("1");
demo = function () {
console.log("2");
}
}
demo.des = "描述信息";
console.log(demo.des);
// demo();
console.log(demo.des);
//01 賦值給變量
// var func = demo;
// func(); //1
// func(); //1
// func(); //1
// demo(); //2
//01 賦值給對象
var o = {};
o.desLog = demo;
o.desLog();
o.desLog();
o.desLog();
demo();
即時對象初始化
({
name:"張安",
age:23,
showName:function () {
console.log(this.name);
},
showAge:function () {
console.log(this.age);
},
init:function (nameValue,ageValue) {
//需要進行初始化處理的代碼
//...............
this.name = nameValue;
this.age = ageValue;
this.showName();
this.showAge();
}
}).init("隔壁老王","23");
即時函數(shù)補充
- 即時函數(shù)的組成
- 函數(shù) function (形參){函數(shù)體}
- ()把函數(shù)包裹起來
- ()馬上調用并執(zhí)行函數(shù)
//01
(function () {
console.log("我要過節(jié)啦拱层,好開心啊");
})();
//02
(function () {
console.log("我要過節(jié)啦弥臼,好開心啊");
}());
//03 非主流的寫法
!function () {
console.log("我要過節(jié)啦,好開心啊");
}();
+function () {
console.log("我要過節(jié)啦根灯,好開心啊");
}();
-function () {
console.log("我要過節(jié)啦径缅,好開心啊");
}();
~function () {
console.log("我要過節(jié)啦掺栅,好開心啊");
}();
- 即時函數(shù)可以接收參數(shù)也可以有返回值
var a = 10;
var result = (function (n) {
return n + 1;
})(a);
console.log(result);
筆試題練習
- 穿件對象的幾種方法
- 字面量
- 內置構造函數(shù)
- 工廠函數(shù)
- 自定義構造函數(shù)
# 01 以下創(chuàng)建對象的方法,錯誤的是:
<script>
var obj1 = new Object();
obj1.name = "XMG";
obj1.getName = function () {
return this.name;
}
console.log(obj1.getName());
</script>
<script>
var obj2 = {
name:"XMG",
getName:function () {
return this.name;
}
}
console.log(obj2.getName());
</script>
<script>
var MYClass = function () {
this.name = "XMG";
this.getName = function () {
return this.name;
}
};
var obj3 = new MYClass();
console.log(obj3.getName());
</script>
<!--<script>-->
<!--var obj4; //undefined-->
<!--obj4.name = "XMG";-->
<!--obj4.getName = function () {-->
<!--return this.name;-->
<!--};-->
<!--console.log(obj4);-->
<!--</script>-->
函數(shù)和變量聲明的提升(函數(shù)和變量同名)
# 02 請給出以下代碼的打印結果
<script>
console.log(test); //函數(shù)
function test() {};
console.log(typeof test); //function?string
var test = "2017";
console.log(test); //2017
</script>
# 03 請給出以下代碼的輸出結果
<!--<script>-->
<!--var f = new Number(true); //僅僅為1的時候|true-->
<!--if (f == true) {-->
<!--var a = 10;-->
<!--}-->
<!--function fn() {-->
<!--var b = 20;-->
<!--c = 30;-->
<!--}-->
<!--fn();-->
<!--// console.log(a); //? 10 ? undefined 纳猪?報錯-->
<!--// console.log(b); //? 報錯-->
<!--console.log(c); //30-->
<!--</script>-->
<!--# 04 請給出下面代碼的輸出結果-->
<!--<script>-->
<!--var str1 = new String("demo01");-->
<!--var str2 = new String("demo01");-->
<!--var str3 = "demo01";-->
<!--console.log("undefined" == undefined); //不相等-->
<!--console.log("+++");-->
<!--console.log(str1 == str2); //false-->
<!--console.log(str1 == str3); //true-->
<!--var name = 'World!';-->
<!--(function () {-->
<!--//"undefined" == undefined 相等比較(如果類型不一樣那么會隱式轉換)-->
<!--if (typeof name == undefined) {-->
<!--var name = '文頂頂';-->
<!--console.log('Goodbye ' + name);-->
<!--} else {-->
<!--console.log('Hello ' + name);-->
<!--}-->
<!--})();-->
<!--</script>-->
<!--#05 請給出下面代碼的結果-->
<!--<script>-->
<!--console.log(Array.isArray(Array.prototype));-->
<!--</script>-->
#06 請給出下面代碼的輸出結果
<!--<script>-->
<!--//[0] == true false-->
<!--//[1] == true true-->
<!--//數(shù)組 在比較的時候只有內容是1的時候為true-->
<!--//if判斷的時候 [0] [1] [] {}都為真 -->
<!--// 對象和布爾類型(true|false)比較永遠都為false-->
<!--//幾種結果:true false NO-->
<!--var a = [];-->
<!--if (a) {-->
<!--console.log([1] == true); //false-->
<!--} else {-->
<!--console.log("NO");-->
<!--}-->
<!--console.log("___");-->
<!--</script>-->
#07 請給出下面代碼的輸出結果
<script>
(function(){
var x = y = 1;
//y = 1;
//var x = 1;
})();
console.log(y); //能夠獲取y的值嗎?
console.log(x); //能夠獲取x的值嗎?
筆試題2
- 考察
prototype 和proto
構造函數(shù).prototype
對象.proto
注意:
對象.prototype 和 對象.proto_ 不是一回事
對象.prototype 指的是訪問對象的 prototype 屬性
如果該對象是一個普通的對象(非構造函數(shù))氧卧,那么不存在該屬性
對象.proto 指的是訪問創(chuàng)建該對象的構造函數(shù)的原型對象,等價于 構造函數(shù).prototype
# 01 請給出下面代碼的輸出
<script>
var a = {};
var b = Object.prototype;
console.log(a.__proto__ == Object.prototype); //true
console.log(a.prototype === b); //false
console.log(Object.getPrototypeOf(a) === b); //true ? false
</script>
#02 請給出下面代碼的輸出結果
<!--<script>-->
<!--function f() {}-->
<!--var a = f.prototype;-->
<!--var b = Object.getPrototypeOf(f); //f.__proto__ = Function.prototype = 空函數(shù)-->
<!--console.log(a === b);-->
<!--console.log("++++");-->
<!--// console.log(a,b);-->
<!--console.log(b == f);-->
<!--</script>-->
<!--#03 請給出輸出結果-->
<script>
function foo() { }
var oldName = foo.name;
foo.name = "bar"; //函數(shù)設置name屬性沒有作用
console.log(oldName); //undefined ==》foo
console.log(foo.name); //bar ==> foo
console.log(oldName === foo.name);
// console.log([oldName, foo.name]);
</script>
#04 請給出輸出結果
<script>
function f() {}
var parent = Object.getPrototypeOf(f); //f.__proto__ =》Function.prototype (空函數(shù))
console.log(f.name); // ?
console.log(parent.name); // ?
//A "f", "Empty" 正確
//B "f", undefined
設計模式的簡單說明
- 設計模式
解決軟件開發(fā)中的常見應用場景所采取的不同套路
常見的設計模式:23種 - 分類
創(chuàng)建型的模式
行為型的模式
常用:單利模式 + 工廠模式 + 觀察者模式 + 策略模式 + 代理模式 + 享元模式 + 橋接模式
推薦:大話設計模式(大話數(shù)據結構)
其主要是架構師工作 - 起源
建筑行業(yè)(哥特風格 中式風格)
Gof 四人組
工廠函數(shù)創(chuàng)建對象
function createPerson(name,age) {
var o = new Object();
o.name = name;
o.age = age;
return o;
}
var p1 = createPerson("張三",20);
工廠函數(shù)簡單說明
- 工廠模式
核心過程 - 提供一個父構造函數(shù)
- 設置父構造函數(shù)的原型對象(方法)
- 在父構造函數(shù)身上添加靜態(tài)工廠方法
- 定制合作伙伴(創(chuàng)建子構造函數(shù))
- 使用工廠函數(shù)來創(chuàng)建對象
//01 提供一個父構造函數(shù)
function MakePhone() {}
//02 設置父構造函數(shù)的原型對象(方法)
MakePhone.prototype.desLog = function () {
console.log("我們的口號是:" + this.des);
}
//03 在父構造函數(shù)身上添加靜態(tài)的工廠方法
MakePhone.factory = function (type) {
//001 接受參數(shù)兆旬,并做容錯性處理
var typeString = type;
if (typeString == undefined) {
throw "請選擇廠商";
}
//002 判斷是否支持生產
if (typeof MakePhone[typeString] != "function") {
throw "不支持該手機廠商假抄!";
}
//MakePhone.oppo ==》當做構造函數(shù)來使用
//003 設置繼承
MakePhone[typeString].prototype = MakePhone.prototype; //獲得原型對象上面的方法
//004 創(chuàng)建產品
var newPhone = new MakePhone[typeString]();
return newPhone;
}
//04 定制合作伙伴(設置子構造函數(shù))
MakePhone.oppo = function () {
this.des = "充電兩小時,通話五分鐘";
}
MakePhone.vivo = function () {
this.des = "照亮你的美丽猬,啊哈哈哈哈";
}
MakePhone.zuimei = function () {
this.des = "你的青春我做主";
}
// 05 使用工廠函數(shù)來創(chuàng)建對象
var oppo = MakePhone.factory("oppo");
oppo.desLog();
var vivo = MakePhone.factory("vivo");
vivo.desLog();
var zuimei = MakePhone.factory("zuimei");
zuimei.desLog();