JS:闭包,面向对象,封装,继承

  1. 闭包
    *****面向对象*****
  2. 什么是面向对象
  3. 封装
  4. 继承

一. 闭包

  1. 问题: 全局变量和局部变量都有不可兼得的优缺点
    (1). 全局变量:
    a. 缺点: 极易被篡改!全局污染
    b. 优点: 可反复使用
    (2). 局部变量:
    a. 优点: 不会被外部篡改
    b. 缺点: 不可反复使用!
  2. 解决: 今后,只要希望给一个函数保存一个专属的变量,既可重用,又不会被随意篡改,都要用闭包解决!
  3. 如何: 3步:
    (1). 用外层函数,包裹要保护的变量和内层函数——相当于给内层函数找一妈
    (2). 外层函数要把内层函数返回到外层函数外部
    (3). 想使用内层函数的人,必须调用外层函数,用变量保存住返回出来的内层函数对象,才能反复调用。
  4. 示例: 定义函数帮小孩儿保管压岁钱
    1_closure.html



运行结果:
花了100,还剩900
花了100,还剩800
花了100,还剩700

5. 原理:
图片1.png

图片2.png

图片3.png

图片4.png

6. 一句话概括闭包是如何形成的 / 什么是闭包?

答: 外层函数调用后,外层函数的函数作用域对象,被内层函数的作用域链引用着,无法释放!形成了闭包对象!

  1. 闭包的缺点: 比一般的函数多占用一块存储空间——外层函数的函数作用域对象。
  2. 解决: 只要一个闭包结构不再被使用时,都要将保存内层函数的外部变量赋值为null,比如pay=null;

*****面向对象*****

一. 什么是面向对象:

  1. 问题: 程序中通常都会管理大量数据!如果毫无组织的存放,极容易出错!极其不便于使用
  2. 解决: 今后,几乎所有程序,都用面向对象思想保存数据。
  3. 什么是: 将现实中一个事物的属性和功能集中保存在程序中一个对象结构中,再起一个名字。
  4. 为什么: 极其便于大量数据的管理和维护
  5. 如何: 3步/3大特点: 封装,继承,多态

二. 封装:

  1. 什么是: 创建一个对象结构,保存现实中一个事物的属性和功能。
  2. 为什么: 极其便于大量数据的管理和维护
  3. 何时: 今后,只要使用面向对象思想开发,都要先创建对象。
  4. 如何: 3种:
    (1). 用{}:
    a. var 对象名={
    属性名: 属性值,
    ... : ... ,
    方法名: function(){
    ... ...
    }
    }
    b. 说明:
    1). 事物的属性值,就会成为对象中的属性值
    2). 事物的功能,就会成为对象中的方法。
    科普: 方法和函数:
  5. 相同点: 本质都是function(){ ... }
  6. 不同点: 保存的位置不同:
    1). 不属于任何对象的独立在全局的function,称为函数
    2). 保存在对象中的function,称为方法
    c. 如何访问对象中的成员: (成员=属性+方法)
    1). 想访问对象中的属性:先找到对象,再进入对象,找属性名
    语法: 对象名.属性名
    2). 想访问对象中的方法: 先找到对象,再进入对象,找方法名
    语法: 对象名.方法名() //调用
    d. 示例: 定义对象lilei,描述lilei的属性和方法:
    2_{}.html



运行结果:
I'm Li Lei, I'm 11
12
I'm Li Lei, I'm 12
{sname: "Li Lei", sage: 12, intrSelf: ƒ}
I'm undefined, I'm undefined

e. this:
1). 问题: 明明同一个对象中的方法和属性,方法中想用自己对象中的属性,竟然报错:xxx属性名 未定义
2). 原因: 对象不是作用域,对象无权进入方法的作用域链中。所以,在方法内,不加任何前缀,就想像普通变量一样直接使用对象中的属性,根本找不到的!

图片5.png

3). 解决: 2种:
i. 不好: 在方法中用"对象名.属性名",先找到对象,再找到对象内的属性。
缺点: 对象名其实就是一个普通的变量,所以有对象名很可能被改变。一旦对象名被修改,而忘记修改方法中写死的对象名,立刻就会出现不一致,程序立刻就错误!
ii. 好: 用关键字this代替方法中写死的对象名: "this.属性名"
什么是this:
每个函数中都自带的——不用创建就可直接使用。
专门在调用函数时——只有调用函数时讨论this才有意义。
自动获得当前正在调用函数的.前的对象——内容
的关键字。
总结: 今后只要对象自己的方法中,想使用对象自己的属性,都必须加this!
图片6.png

4). 强调: 判断this指向,一定不要看定义在哪里,必须看在哪里,如何被调用的,前边有没有点。
图片7.png

(2). 用new:
a. 如何: 2步:
1). 先创建一个空对象等待:
var 对象名=new Object();
2). 再强行向对象中添加新属性:
对象名.属性名=属性值;
对象名.方法名=function(){
... this.属性名 ...
}
b. 揭示了本质: 其实js内存中,一切都是关联数组!
c. 对象与关联数组:
1). 都是名值对儿的集合
2). 访问对象成员:
i. 标准: 对象名["属性名"]
ii. 简写: 对象名.属性名
iii. 特例: 如果属性名不是写死的,来自于其他变量,则既不能用点,又不能加"",只能: 对象名[变量名]
3). 都可随时向不存在的位置添加新属性
所以,将来想向对象中添加一个新属性,没有专门的函数或优雅的办法。只有唯一一种野蛮的办法!强行赋值!
对象名.新属性=新值;
4). 都可随时访问对象中不存在下标位置或属性,都不报错,都返回undefined。
所以,将来想判断一个数组或对象中是否包含某个成员,都可以用:
if(对象.属性名!==undefined){ ... 包含该成员 ... }
5). 都可用for in循环遍历
d. 示例: 定义一个clone函数,可以克隆任何一个对象

 


运行结果: 
{sname: "Li Lei", sage: 11}
false

(3). 用构造函数:

a. 问题: {}一次只能创建一个对象。如果想创建多个相同结构,不同属性值的对象,用{},代码就会很繁琐,且重复,极其不便于今后的维护和修改。
b. 解决: 今后,只要想创建多个相同结构,不同属性值的对象时,都用构造函数来创建。
c. 什么是: 专门描述同一类型所有对象的统一结构的函数。
d. 如何: 2步:
1). 定义构造函数:
function 类型名(形参1, 形参2,...){
this.属性名1=形参1;
this.属性名2=形参2;
this.方法名=function(){
... this.属性名 ...
}
}
强调:
i. 将要添加到新对象中的属性,必须用this.前缀才行!不加this.前缀,则该属性无法加入将来的新对象中。
ii. 属性值不能写死,应该将来在创建某一个新对象时,动态传入属性值。传入什么,对象中就保存什么。所以,构造函数中应该用形参变量,暂时为将来的属性值占位。
2). 调用构造函数:
i. var 对象名=new 类型名(属性值1, 属性值2, ... )
ii. 强调: 只要调用构造函数,必须用new。
e. 优点: 重用对象的结果。
f. 示例: 定义学生类型,反复创建两个学生对象
5_constructor.html

 


运行结果: 
Student {sname: "Li Lei", sage: 11, intrSelf: ƒ}
11
I'm Li Lei, I'm 11
Student {sname: "Han Meimei", sage: 12, intrSelf: ƒ}
12
I'm Han Meimei, I'm 12

g. 原理: new做了4件事儿:
1). 新建一个空对象等待
2). (未完待续...)
3). 自动调动构造函数,为新对象添加规定的新属性:
i. new关键字可以先将构造函数中的this,强行指向正在创建的新对象。
ii. 构造函数中的this.属性名=属性值,都变成新对象.属性名=属性值,都变成给新对象强行赋值新属性
4). 返回新创建的对象的地址。

图片8.png

简写:

  1. [] 是new Array()
  2. function 是new Function()
  3. // 是new RegExp()
  4. {} 是new Object()
    {}和function(){}
总结:

this共有几种情况:3种
一定不要看定义在哪儿,只看在哪里如何调用

  1. obj.fun() this->.前的obj对象
  2. 普通函数调用fun(),既没有点,也没有new,this->window(默认)
  3. new Fun() this->new正在创建的新对象
    (5). 闭包:
    a. 只要希望给一个函数保护一个可反复使用的专属变量,又防止这个变量被外界篡改时,都用闭包。
    b. 闭包三步:
    1). 用外层函数妈妈包裹要保护的变量和内层函数
    2). 外层函数妈妈用return把内层函数孩子返回到外部
    3). 外部想使用内层函数的人,必须调用外层函数,才能获得return出来的内层函数对象。并将内层函数保存在一个变量中反复使用。
    c. 闭包形成的原因: 外层函数调用后,外层函数的作用域对象被内层函数引用着无法释放,形成了闭包对象
    d. 闭包的缺点: 闭包比一般的函数占用多一块内存——外层函数的函数作用域对象。
    所以,用完闭包后,应该尽快释放:
    保存内层函数的变量=null
    4. 面向对象: 封装 继承 多态
    自己跟着视频,一步一步画图,自己标顺序,知识才能变成自己的
    (1). 封装: 3种:
    a. 用{}创建一个对象:
    var 对象名={
    属性名:属性值,
    ... : ... ,
    方法名: function(){
    ... this.属性名 ...
    }
    }
    b. 用new Object():
    1). 2步:
    i. var 对象名=new Object()
    ii. 对象名.属性名=属性值;
    对象名.方法名=function(){ ... }
    2). 对象底层也是关联数组:
    i. 都是名值对儿的集合
    ii. 都可用[""]和.方式访问成员。
    如果属性名来自于变量,就只能用[],不要加""
    iii. 访问不存在的属性,都不报错,返回undefined
    判断是否包含某个属性:
    对象.属性名!==undefined
    iv. 强行给不存在的属性赋值,都不报错,而是自动添加该属性
    给对象添加新属性,唯一办法,强行赋值:
    对象名.新属性名=新值
    v. 都可用for in遍历
    c. 只要反复创建多个相同结构的对象都用构造函数:
    1). 2步:
    i. 定义构造函数:
    function 类型名(形参1,形参2, ...){
    this.属性名1=形参1;
    this.属性名2=形参2;
    //构造函数中不要再包含方法定义定义!
    }
    ii. 用new 调用构造函数:
    var 对象名=new 类型名(属性值1, 属性值2,...)
    2). new做了4件事:
    i. 创建一个新的空对象
    ii.
    iii. 调用构造函数,传入实参,并自动替换构造函数中的this为new正在创建的新对象。构造函数中,通过强行赋值的方式为新对象添加规定的属性,并保存属性值。
    iv. 返回新对象的地址,保存到=左边的变量中。
    3). 优点: 重用对象结构代码
    4). 缺点: 如果构造函数中包含方法定义,则每次创建新对象都会重复创建相同方法的副本。——浪费内存!

你可能感兴趣的:(JS:闭包,面向对象,封装,继承)