闭包复习
- 闭包概念:
封闭空间,包裹 - 闭包的作用:
延长变量的声明周期
保护内部的数据,代码更安全
为我们提供一种间接访问函数内部私有数据的方法 - 函数内部私有数据的访问
函数内部声明的变量在函数外部无法访问
但是有的时候,我们有访问(读取数据 + 修改数据)函数内部私有数据的需求 - 在函数内部直接返回数据
- return
只能获取值,无法修改值
这种方法获得的数据是一次性的数据,多次获取得到的数据不是同一份 - 闭包(全世界所有描述 js 的技术文章 32% 在讨论闭包)
闭包是持有了本来不属于自己数据的函数
<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>
# 访问私有数据(读写)
<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>
# 返回多个数据 方式一
<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>
# 返回多个数据 方式二
<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>
# 返回多个数据 方式三
<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>
闭包获取和设置数据
<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>
闭包的作用
- 延长变量的声明周期
- 保护内部的数据,代码更安全,做一些数据检验处理
- 为我们提供一种间接访问函数内部私有数据的方法
<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 和闭包的执行
- 定时器
setTimeOut(只执行一次)
setInterval(每个一段时间执行一次)
<script>
var date = new Date();
console.log(date);
setTimeout(function () {
console.log("定时器" + new Date);
},2000)
</script>
-
思考
js 代码的执行 -
页面渲染任务
-
js 主要代码 (for,语句)
-
事件型的任务(点击事件,定时器事件)
-
js 本身是单线程的
-
进程:系统中正在运行的运行程序,是 cpu 调度的单位,是分配资源的最小单位
-
线程:进程中真正执行任务的部分,是 CPU 调度的最小单位, CPU 不会为线程分配资源
-
关系:包含关系(进程包含线程),一个进程可以拥有多个线程,至少要有一条线程(主线程 - UI 线程)
-
进程(正在运行的学校)
-
线程(老师)
-
线程执行任务的时候是串行执行:一条线程在执行多个任务的时候是按照任务的固定顺序一个接着一个的执行
-
多线程:一个进程可以拥有多个线程,多条线程在执行任务的时候并发(行)执行
-
多线程的并发执行:多条线程执行多个任务,多个任务一起执行,给人感觉在同时执行
-
并发和秉性的区别
并发:多个任务同时执行(现象)
并行:能力
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>
函数补充说明
- 函数的几种创建方式
- 函数声明 function 名称(参数1,参数2){函数体}
- 函数表达式
var 变量1 = functon 名称(参数1,参数2){函数体} 命名函数表达式
var 变量2 = function(参数1,参数2){函数体} 匿名函数表达式 - 使用构造函数来创建
var func = new Function()
var func01 = function name() {
console.log("func01");
}
var func02 = function () {
console.log("func02");
}
//细微的差别:name(函数名称)
//函数本身是对象,函数有属性(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;
// }
//
// 函数:函数是有名字的代码块。
// demo();
// demo();
// demo();
函数的回调
- 函数回调:函数作为其他函数的参数来使用。
- 需要注意 this 的指向
function foo(callBack,callBackObj) {
//............
if (typeof callBack == "string")
{
callBack = callBackObj[callBack]
}
callBack.call(callBackObj); //以普通函数方式调用 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); //兼容性处理
函数作为返回值(计数器)
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());
自定义函数(惰性函数定义)
- 自定义函数(惰性函数定义)
特点:函数的内容在第二次调用的时候才被正确的定义,第一次调用的时候主要做一些初始化处理 + 更新函数 - 使用的场景:
代码需要做一些一次性的初始化处理
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!
- 使用注意:
- 添加在函数对象上面的成员会丢失
- 如果把函数赋值给变量或者是称为对象的方法,那么再调用的时候还是执行旧的函数体
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");
即时函数补充
- 即时函数的组成
- 函数 function (形参){函数体}
- ()把函数包裹起来
- ()马上调用并执行函数
//01
(function () {
console.log("我要过节啦,好开心啊");
})();
//02
(function () {
console.log("我要过节啦,好开心啊");
}());
//03 非主流的写法
!function () {
console.log("我要过节啦,好开心啊");
}();
+function () {
console.log("我要过节啦,好开心啊");
}();
-function () {
console.log("我要过节啦,好开心啊");
}();
~function () {
console.log("我要过节啦,好开心啊");
}();
- 即时函数可以接收参数也可以有返回值
var a = 10;
var result = (function (n) {
return n + 1;
})(a);
console.log(result);
笔试题练习
- 穿件对象的几种方法
- 字面量
- 内置构造函数
- 工厂函数
- 自定义构造函数
# 01 以下创建对象的方法,错误的是:
<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>-->
函数和变量声明的提升(函数和变量同名)
# 02 请给出以下代码的打印结果
<script>
console.log(test); //函数
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-->
<!--//数组 在比较的时候只有内容是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
构造函数.prototype
对象.proto
注意:
对象.prototype 和 对象.proto_ 不是一回事
对象.prototype 指的是访问对象的 prototype 属性
如果该对象是一个普通的对象(非构造函数),那么不存在该属性
对象.proto 指的是访问创建该对象的构造函数的原型对象,等价于 构造函数.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 = 空函数-->
<!--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"; //函数设置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 (空函数)
console.log(f.name); // ?
console.log(parent.name); // ?
//A "f", "Empty" 正确
//B "f", undefined
设计模式的简单说明
- 设计模式
解决软件开发中的常见应用场景所采取的不同套路
常见的设计模式:23种 - 分类
创建型的模式
行为型的模式
常用:单利模式 + 工厂模式 + 观察者模式 + 策略模式 + 代理模式 + 享元模式 + 桥接模式
推荐:大话设计模式(大话数据结构)
其主要是架构师工作 - 起源
建筑行业(哥特风格 中式风格)
Gof 四人组
工厂函数创建对象
function createPerson(name,age) {
var o = new Object();
o.name = name;
o.age = age;
return o;
}
var p1 = createPerson("张三",20);
工厂函数简单说明
- 工厂模式
核心过程 - 提供一个父构造函数
- 设置父构造函数的原型对象(方法)
- 在父构造函数身上添加静态工厂方法
- 定制合作伙伴(创建子构造函数)
- 使用工厂函数来创建对象
//01 提供一个父构造函数
function MakePhone() {}
//02 设置父构造函数的原型对象(方法)
MakePhone.prototype.desLog = function () {
console.log("我们的口号是:" + this.des);
}
//03 在父构造函数身上添加静态的工厂方法
MakePhone.factory = function (type) {
//001 接受参数,并做容错性处理
var typeString = type;
if (typeString == undefined) {
throw "请选择厂商";
}
//002 判断是否支持生产
if (typeof MakePhone[typeString] != "function") {
throw "不支持该手机厂商!";
}
//MakePhone.oppo ==》当做构造函数来使用
//003 设置继承
MakePhone[typeString].prototype = MakePhone.prototype; //获得原型对象上面的方法
//004 创建产品
var newPhone = new MakePhone[typeString]();
return newPhone;
}
//04 定制合作伙伴(设置子构造函数)
MakePhone.oppo = function () {
this.des = "充电两小时,通话五分钟";
}
MakePhone.vivo = function () {
this.des = "照亮你的美,啊哈哈哈哈";
}
MakePhone.zuimei = function () {
this.des = "你的青春我做主";
}
// 05 使用工厂函数来创建对象
var oppo = MakePhone.factory("oppo");
oppo.desLog();
var vivo = MakePhone.factory("vivo");
vivo.desLog();
var zuimei = MakePhone.factory("zuimei");
zuimei.desLog();
网友评论