• 【JS高级】ES5标准规范之严格模式详解_08


    目录

    ❣️ 严格模式

    1. 存在问题

    2. 解决方案

    3. 什么是严格模式

    4. 何时使用严格模式

    5. 如何使用严格模式

    6. 严格模式的4个新规定

    ⬛ 小结 + 扩展

    一. 严格模式的使用

    二. 严格模式下的执行限制

    三. “use strict” 的位置必须在首部

    💥 扩展:this判断—8种指向

    💠 总结:知识点提炼 


    🆙【前文回顾】👉  js面向对象三大特性之多态_07


      

    ❣️ 严格模式

    1. 存在问题

    JS语言其实并不是一门很严谨的语言,反而有很多广受诟病的缺陷!

    2. 解决方案

    ES5标准中添加了严格模式,来解决一部分js语言的缺陷

    3. 什么是严格模式

    比普通的js程序运行机制要求更严格的运行机制

    除了正常的运行模式,JavaScript 还有第二种运行模式:严格模式(strict mode)。顾名思义,这种模式采用更加严格的 JavaScript 语法。
     

    同样的代码,在正常模式和严格模式中,可能会有不一样的运行结果。一些在正常模式下可以运行的语句,在严格模式下将不能运行。

    4. 何时使用严格模式

    今后所有js代码都必须运行在严格模式下!

    👨‍🌾 严格模式设计的目的
     

    早期的 JavaScript 语言有很多设计不合理的地方,但是为了兼容以前的代码,又不能改变老的语法,只能不断添加新的语法,引导程序员使用新语法。
     

    严格模式是从 ES5(ECMAScript标准的第五个版本) 进入标准的,主要目的有以下几个。

    •  明确禁止一些不合理、不严谨的语法,减少 JavaScript 语言的一些怪异行为。
    •  增加更多报错的场合,消除代码运行的一些不安全之处,保证代码运行的安全。
    •  提高编译器效率,增加运行速度。
    •  为未来新版本的 JavaScript 语法做好铺垫。

     总之,严格模式体现了 JavaScript 更合理、更安全、更严谨的发展 

    5. 如何使用严格模式

    只要在当前作用域的顶部添加: "use strict";

                                                      启用 严格

    6. 严格模式的4个新规定

              严格模式的新规定: 4

             (1). 禁止给未声明的变量赋值 👇

             a. js: 如果强行给未声明的变量赋值,不会报错,而是自动在全局创建该变量——全局污染

             b. 严格模式: 禁止给未声明的变量赋值。如果强行赋值会报错: xxx 未定义!

             c. 示例: 禁止给未声明的变量赋值: ⏬

             7_use_strict.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. "use strict";
    11. function send(){
    12. var gf;
    13. cf="今晚308,w84u";//报错: 避免歧义!
    14. console.log(`gf收到消息:${gf}`)
    15. }
    16. send();
    17. console.log(`全局收到: ${cf}`);
    18. script>
    19. body>
    20. html>

    运行结果:

    Uncaught ReferenceError: cf is not defined

    🆚 去掉严格模式


    运行结果:

    gf收到消息:undefined

    全局收到: 今晚308,w84u

             (2). 静默失败升级为错误 👇

             a. 静默失败: 程序执行不成功,但也不报错

             b. 问题: 静默失败极其不便于调试程序

             c. 严格模式: 所有静默失败都变为报错!——极其利于程序的调试!

             d. 示例: 让静默失败升级为错误: ⏬

             8_use_strict.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. "use strict";
    11. var eric={
    12. eid:1001,
    13. ename:"埃里克"
    14. }
    15. //公司要求所有员工的eid属性,禁止修改
    16. //下一篇文章会介绍关于保护对象知识点————修改一个属性的开关使用Object.defineProperty
    17. // 定义 属性 eric的eid
    18. Object.defineProperty(eric,"eid",{
    19. //可修改 为 false —— 不可修改
    20. writable:false
    21. })
    22. eric.eid=-2;
    23. console.log(eric);
    24. script>
    25. body>
    26. html>

    运行结果:

    Uncaught TypeError: Cannot assign to read only property 'eid' of object '#'
    翻译: 不能给只读属性eid赋值。

    🆚 去掉严格模式
     

    虽然无法修改,但是也不报错 

             (3). 普通函数调用中的this不再指向window,而是undefined 👇

             a. js: 如果一个函数调用时,前边即没有点,又没有new,则其中的this默认指window

             b. 问题: 极容易造成全局污染

             c. 严格模式: 普通函数调用中的this不再指window,而是指undefined

             d. 优点: 防止因为错误使用this,而造成全局污染

             e. 示例: 错误使用构造函数

             9_use_strict.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. "use strict";
    11. // "Han Meimei",12
    12. // ↓ ↓
    13. function Student(sname,sage){
    14. //this->window
    15. //window.sname=sname;//"Han Meimei"
    16. //window.sage=sage;//12
    17. //use strict;
    18. //this->undefined
    19. //undefined.sname //报错!
    20. this.sname=sname;
    21. this.sage=sage;
    22. }
    23. var lilei=new Student("Li Lei",11);
    24. var hmm=Student("Han Meimei",12); // 注意函数调用没有new
    25. console.log(lilei);
    26. console.log(hmm);
    27. console.log(sname, sage);
    28. script>
    29. body>
    30. html>

    运行结果:

    Uncaught TypeError: Cannot set property 'sname' of undefined
    翻译: 不能设置undefinedsname属性

    🆚 去掉严格模式


    分析:去掉严格模式后
    ①var hmm=Student("Han Meimei",12);

    调用函数,传入实参值Han Meimei、12,由于this->window
     

    ②this.sname=sname;this.sage=sage; 即window.sname=Han Meimei; window.sage=12; 

    强行在全局添加属性sname、sage并赋值,造成全局污染

             (4). 禁用了arguments.callee

             a. 问题: 递归调用时,在函数内写死函数名会形成紧耦合。一旦函数名改变,总要记着同时改函数内写死的函数名。一旦忘记修改函数内写死的函数名,就会报错!

             b. 解决: 在函数内用arguments.callee代替写死的函数名

                      1). 什么是arguments.callee: 在函数调用时,可自动获得当前函数本身的关键字

                      2). 何时: 几乎只有递归调用时,才用arguments.callee

                      3). 优点: 松耦合。即使修改外部的函数名,也不用修改函数的内容,就可自动获得当前函数本身!

             c. 其实,禁用arguments.callee暗示我们尽量少用递归。因为有些递归算法效率极低!因为重复计算量太大。

             d. 解决: 绝大多数递归都可用循环来代替:

    1. //斐波那契数列循环版本
    2. //创建函数,计算斐波那契数列第n项的值
    3. function fib(n){
    4. //第1项和第2项的值都是1
    5. var n1=1,n2=1;
    6. //如果要求第n项的,只需要让n1和n2不断的往后挪动,挪动结束后,n2的值就是所求项的值
    7. //每次挪动从3开始,表示循环从3开始
    8. for(var i=3;i<=n;i++){//每循环一次,就挪动一次
    9. //挪动的原理:n1的值是上一次n2的值,n2的值是上一次n1和n2相加的和
    10. var c=n1;
    11. n1=n2;
    12. n2=c+n2;
    13. }
    14. //挪动结束后,n2的值就是所求项的值
    15. return n2;
    16. }
    17. var r=fib(2);
    18. console.log(r);

             e. 但是, 想用循环代替递归,难度极高,所以:

                      1). 如果递归不影响效率时,依然可以使用递归

                      2). 除非递归非常影响效率时,才被迫寻求用循环解决!

             f. 示例: 使用递归实现斐波那契数列算法: ⏬

             10_use_strict.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Documenttitle>
    7. head>
    8. <body>
    9. <script>
    10. "use strict";
    11. //斐波那契数列
    12. //第一个值是1, 第二个值也是1
    13. //从第三个值开始,每个值都是相邻的前两个数的和
    14. //1,1,2,3,5,8,13,21,34,55
    15. //1 2 3 4 5 6 7 8 9 10
    16. //数学公式:
    17. //f(1)=1 f(2)=1
    18. //f(n)=f(n-1)+f(n-2)
    19. //想获取斐波那契数列中第i个值是几
    20. //递归调用
    21. function fib(i){
    22. if(i<3){
    23. return 1;
    24. }else{
    25. return arguments.callee(i-1)+arguments.callee(i-2);
    26. }
    27. }
    28. console.log(fib(10));//55
    29. script>
    30. body>
    31. html>

    运行结果:

    Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

    🆚 去掉严格模式

     运行结果:55

    ⬛ 小结 + 扩展

    严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,发布于2009年12月第五版。旨在改善错误检查功能并且标识可能不会延续到未来JavaScript版本的脚本。ES5严格模式是限制性更强的JavaScript变体,它与常规JavaScript的语义不同,其分析更为严格。

    目前,除了IE6-9,其它浏览器均已支持ES5严格模式。

    一. 严格模式的使用

    严格模式 的使用很简单,只有在代码首部加入字符串 “use strict”。有两种应用场景,一种是全局模式,一种是局部模式。

    1)全局模式

    1. 'use strict'
    2. //code

    2)局部模式

    将”use strict”放到函数内的第一行,如下

    1. function() {
    2. "use strict";
    3. //code
    4. }

    二. 严格模式下的执行限制

    1)不使用var声明变量严格模式中将不通过

    我们知道JS中,不使用var声明的变量默认转为全局变量。但在严格模式中将不允许,会报语法错误。

    1. 'use strict'
    2. g = 100 //错误

    比如for循环

    1. 'use strict'
    2. for (i=0; i<5; i++) { //错误
    3. console.log(i)
    4. }

     运行结果:12 Uncaught ReferenceError: i is not defined at

    🆚 去掉严格模式

    运行结果:

    2)任何使用’eval’的操作都会被禁止

    1. 'use strict'
    2. var obj = {}
    3. var eval = 3
    4. for (var eval in obj) {}
    5. function eval() {}
    6. function func(eval) {}

    3)eval作用域 JS中作用域有两种,全局作用域和函数作用域。严格模式带来了第三种作用域:eval作用域,如下

    1. 'use strict'
    2. var a = 10
    3. eval('var a = 20; console.log(a)'); //20
    4. console.log(a) //10

    4)with被禁用

    1. 'use strict'
    2. var obj = {
    3. name:'zhangsan',
    4. age:100,
    5. sex:'男'
    6. }
    7. with(obj) { //报错
    8. console.log(name);
    9. console.log(age);
    10. console.log(sex);
    11. }

    运行结果:Uncaught SyntaxError: Strict mode code may not include a with statement

    🆚 去掉严格模式
     

    运行结果:
    zhangsan
    100
    20 男

    5)caller/callee 被禁用

    1. function func() {
    2. 'use strict'
    3. arguments.callee
    4. arguments.caller
    5. }
    6. func()

    运行结果:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 

    6)对禁止扩展的对象添加新属性会报错

    1. 'use strict'
    2. var obj = {}
    3. Object.preventExtensions(obj)
    4. obj.a = 1 // 报错

    7)删除系统内置的属性会报错

    1. 'use strict'
    2. delete Object.prototype // 报错
    3. delete Function.prototype // 报错

    8)delete使用var声明的变量或挂在window上的变量报错

    1. 'use strict'
    2. var obj = {a:1}
    3. window.a = 1
    4. delete obj // 报错
    5. delete a // 报错

    9)delete不可删除属性(isSealed或isFrozen)的对象时报错

    1. 'use strict'
    2. var obj = {a: 1}
    3. Object.seal(obj)
    4. delete obj.a //报错

    10)对一个对象的只读属性进行赋值将报错

    1. 'use strict'
    2. var obj = {}
    3. Object.defineProperty(obj, 'a', {value: 1, writable: false})
    4. obj.a = 2 // 报错

    11)函数有重名的参数将报错

    1. 'use strict'
    2. function func(a, a) {
    3. alert(a)
    4. }
    5. func()

    而在非严格模式中,后面的同名参数将覆盖前面的。

    12)八进制表示法被禁用

    1. 'use strict'
    2. var num = 022

    13)arguments严格定义为参数,不再与形参绑定

    1. function func(a) {
    2. arguments[0] = 2
    3. alert(a) // 2
    4. }
    5. func(1)

    func调用时传参为1,函数内部通过arguments修改为2,此时alert的为修改后的2。 而在严格模式中则不能被修改,如下

    1. 'use strict'
    2. function func(a) {
    3. arguments[0] = 2
    4. alert(a) // 1
    5. }
    6. func(1)

    14)函数必须声明在顶层

    我们知道函数声明和函数表达式是两个不同的概念。一般函数声明都在最顶层,ES5前的JS宽松,你可以写在if或for内。当然Firefox的解析方式与其他浏览器不同。而在严格模式中这些写法将直接报错

    1. 'use strict'
    2. if (true) {
    3. function func1() { } // 语法错误
    4. }
    5. for (var i = 0; i < 5; i++) {
    6. function func2() { } // 语法错误
    7. }

    15)ES5里新增的关键字不能当做变量标示符使用,如implements, interface, let, package, private, protected, public, static, yield

    1. 'use strict'
    2. var let = 10 //报错
    3. var yield = 20

    16)call/apply的第一个参数直接传入不包装为对象

    1. 'use strict'
    2. function func() {
    3. console.log(typeof this)
    4. }
    5. func.call('abcd') // string
    6. func.apply(1) // number

    依次为”string”,”number”。而在非严格模式中call/apply将对值类型的”abcd”,1包装为对象后传入,即两次输出都为”object”。

    17)call/apply的第一个参数为null/undefined时,this为null/undefined 这里以call来示例

    1. 'use strict'
    2. function func() {
    3. console.log(this)
    4. }
    5. func.call(undefined) // undefined
    6. func.call(null) // null

    依次是undefined,null。而非严格模式中则是宿主对象,浏览器里是window,node.js环境则是global。

    18)bind的第一个参数为null/undefined时,this为null/undefined bind是ES5给Function.prototype新增的一个方法,它和call/apply一样在function上直接调用。它返回一个指定了上下文和参数的函数。当它的第一个参数为null/undefined时,情形和call/apply一样,this也为null/undefined。

    1. 'use strict'
    2. function func() {
    3. console.log(this)
    4. }
    5. var f1 = func.bind(null)
    6. var f2 = func.bind(undefined)
    7. f1() // null
    8. f2() // undefined

    而在非严格模式输出的都是window(或global)。

    三. “use strict” 的位置必须在首部

    “use strict” 的位置必须在首部。首部指其前面没有任何有效js代码。以下都是无效的,将不会触发严格模式。

    a)“use strict” 前有代码, 无效

    1. var width = 10
    2. 'use strict'
    3. g = 100

    b)“use strict” 前有个空语句,无效

    1. ;//这里是空语句
    2. 'use strict'
    3. g = 100
    1. function func() {
    2. ;
    3. 'use strict'
    4. g = 200
    5. }
    1. function func() {
    2. ;'use strict'
    3. localVar = 200
    4. }

    当然,“use strict”前加注释是可以的

    1. // strict mode
    2. 'use strict'
    3. g = 100
    4. function func() {
    5. // strict mode
    6. 'use strict'
    7. g = 200
    8. }
    9. func()

    💥 扩展:this判断—8种指向

    this  8种指向: 判断this,一定不要看定义在哪儿!只看调用时!

    1. obj.fun()   this->obj

    2. fun() 或 (function(){ ... })() 或 多数回调函数 或 定时器函数   this->window

    3. new Fun()   this->new正在创建的新对象

    4. 类型名.prototype.共有方法=function(){ ... }   this->将来谁调用指谁,同第一种情况

    5. DOM或jq中事件处理函数中的this->当前正在触发事件的DOM元素对象

                                   如果需要使用简化版函数,必须$(this)

    6. 箭头函数中的this->箭头函数外部作用域中的this

    7. jQuery.fn.自定义函数=function(){ ... }   this->将来调用这个自定义函数的.前的jQuery子对象,不用再$(this)

    8. new Vue()中methods中的函数中的this->当前new Vue()对象


    💠 总结:知识点提炼 

    1. 只要验证字符串格式或查找、屏蔽敏感词时都要用正则

    (1). 最简单的正则: 一个敏感词的原文

    (2). 某一位字符上可能有多种备选字时用: [备选字列表]

    (3). 如果[]中部分字符是连续的,可用: [x-x]

             a. 一位小写字母: [a-z]

             b. 一位大写字母: [A-Z]

             c. 一位字母(大小写都行): [A-Za-z]

             d. 一位字母或数字都行: [0-9A-Za-z]

             e. 一位汉字: [\u4e00-\u9fa5]

    (4). 预定义字符集:

             a.  \d 一位数字

             b.  \w 一位数字、字母或_

             c.  \s  空格、tab、换行等空字符

             d.  .   任意字符

    (5). 如果规定一个字符集或子规则反复出现的次数时就用量词:

             a. 有明确数量边界的量词:

          1). {n}  =n 必须n个,不能多也不能少

          2). {n,m}  n个<=    <=m个

          3). {n,}    n个<=   多了不限

             b. 没有明确数量边界的量词:

          1). *   0个<= 可有可无,多了不限

          2). ?   0个或1个  可有可无,最多一个

          3). +   1个<=  至少一个,多个不限

    (6). 两个规则中选其一匹配即可: 规则1|规则2

    (7).希望将多个子规则分为一组先联合匹配,再和分组外的其他规则联合匹配:

      (多个子规则)

    (8). 匹配特殊位置: 3个

             a. 字符串的开头位置: ^

             b. 字符串的结尾位置: $

             c. 英文句子中的单词的左右边界: \b

    2. String家提供的正则相关函数: 3件事

    (1). 查找敏感词: 4种情况

          a. 查找一个固定的敏感词出现的位置:
             var i=str.indexOf("敏感词")

             // 如果找不到,返回-1

          b. 用正则查找多种敏感词出现的位置:
             var i=str.search(/正则/i)

             // 如果找不到,返回-1

          c. 查找敏感词的内容:

          1). 查找第一个敏感词的内容和位置:
          var arr=str.match(/正则/i)

          // arr: [ 0:"敏感词内容", index:敏感词位置 ]

          // 如果找不到返回null

          2). 查找所有敏感词的内容,不关心位置:
          var arr=str.match(/正则/ig)

          // arr: [ 敏感词1, 敏感词2, ...  ]

          // 如果找不到返回null

         d. 查找每个敏感词的内容和位置: reg.exec

    补: js中所有数组底层本质都是关联数组(下标都为字符串)

    1. 访问数组中元素值的标注写法:

      arr["下标"]

    2. 简写:

      a. 如果下标为自定义字符串名称,可简写为:

      arr.自定义名称的下标

      b. 如果下标为数字内容的字符串,可简写为:

      arr[数字下标]

    总结: 查找方法的返回值规律

    1. 如果原函数返回的是下标位置i,如果找不到,都返回-1

    2. 如果原函数返回的是一个数组arr或一个对象obj,如果找不到,都返回null

    3. 如果原函数返回类数组对象,如果找不到返回空类数组对象:

       { length:0 }

    (2). 替换敏感词: 2种

             a. 简单替换:
             变量=str.replace(/正则/ig, "新值")

             b. 高级替换:
             变量=str.replace(/正则/ig, function(形参){

                   return 根据本次敏感词动态生成一个新值

             })

             c. 删除敏感词:
             变量=str.replace(/正则/ig, "")

    (3). 切割字符串:

             a. 简单切割:
             var arr=str.split("切割符")

             b. 复杂切割:
             var arr=str.split(/正则/i)

             c. 打散字符串为字符数组:
             var arr=str.split("")

    3. RegExp对象: 

             (1). 创建正则表达式对象:

             a. 如果正则是固定的:
             var reg=/正则/ig

             b. 如果正则需要动态生成:
             var reg=new RegExp("正则",ig)

             (2). 验证字符串格式:
             var bool=reg.test(str)
             reg必须同时前加^后加$

             (3). 既查找每个关键词的内容又查找每个关键词的位置: (待续)

             do{

                   var arr=reg.exec(str);

                   if(arr!=null){

                                  获得本次找到的敏感词的内容(arr[0])和位置(arr.index)

                   }

             }while(arr!=null);

    4. 函数: 

    (1). 创建函数三种方式:

             a. function 函数名(形参列表){ 函数体; return 返回值 } //会被声明提前,不好

             b. var 函数名=function(形参列表){ 函数体; return 返回值 }//不会被声明提前,首选

             c. var 函数名=new Function("形参1", "形参2", ... , "函数体; return 返回值")

    函数本质:

      1). 函数也是一个对象,对象中保存着函数的函数体代码

      2). 函数名只是一个普通的变量,函数名通过函数对象地址,引用着函数对象

      3). function在底层等效于new Function()

        function 函数名(){ ... }和var 函数名=function(){}在底层都会被翻译为

        var 函数名=new Function(...)

        只不过function 函数名(){}是先提前,再翻译

        而var 函数名=function(){}是不提前,原地翻译

    (2). 重载: 今后,一件事,根据传入不同的参数值,动态执行不同的逻辑时,都用重载

    function 一个函数名(不写形参变量){

      //arguments对象自动接住所有实参值

      if(arguments.length==0){

        执行一种逻辑

      }else if(arguments.length==1){

        执行另一种逻辑

      }else{

        执行其它逻辑

      }

    }

    其中arguments是类数组对象: 和数组相比:

             a. 相同点: 也有下标,length属性,也可for循环遍历

             b. 不同点: 不是数组类型,无法使用数组家的函数

    (3). 匿名函数:

             a. 所有回调函数优先使用匿名函数——用完释放,节约内存

             b. 所有js代码都应该保存在匿名函数自调中,禁止使用全局变量,避免全局污染!

             (function(){

                   要执行的js代码

             })();

             结果: 匿名函数内的都是局部变量,不会产生全局变量。

             局部变量随匿名函数一起释放。不会污染全局。

    (4). 作用域和作用域链: (跟着视频亲自画图!!!)

             a. 作用域:

             1). 全局作用域:window,保存全局变量

             优: 可重用,缺: 随处可用, 极易被污染

             2). 函数作用域: 保存局部变量

             局部变量包括2中: 函数中var出的变量和形参变量

             优: 仅函数内可用,不会被污染,缺: 不可重用

             3). 函数作用域对象原理:

                   i. 每个函数定义时都自带好友列表,好友列表里2个格子,一个是空,一个引用window

                   ii. 调用函数时临时创建函数作用域对象保存函数局部变量。并将函数作用域对象的地址保存到函数好友列表中离自己近的格子里。

                   iii. 函数执行过程中按就近原则先在自己的函数作用域对象中找局部变量使用。如果找不到,才被迫去全局window中找变量使用.

                   iv. 函数调用后,好友列表中离自己近的格子清空,导致函数作用域对象以及内部的局部变量被释放!——所以局部变量不可重用!

             b. 作用域链: 保存一个函数所有可用的作用域对象的链式结构(好友列表)学名就叫作用域链。
             1). 作用域链保存着一个函数可用的所有变量

             2). 作用域链控制着变量的使用顺序。先局部后全局。

    5. 闭包:  
             a. 只要希望给一个函数保护一个可反复使用的专属变量,又防止这个变量被外界篡改时,都用闭包。

             b. 闭包三步:

          1). 用外层函数妈妈包裹要保护的变量和内层函数

          2). 外层函数妈妈用return把内层函数孩子返回到外部

          3). 外部想使用内层函数的人,必须调用外层函数,才能获得return出来的内层函数对象。并将内层函数保存在一个变量中反复使用。

             c. 闭包形成的原因: 外层函数调用后,外层函数的作用域对象被内层函数引用着无法释放,形成了闭包对象

             d. 闭包的缺点: 闭包比一般的函数占用多一块内存——外层函数的函数作用域对象。所以,用完闭包后,应该尽快释放:
          保存内层函数的变量=null

    6. 面向对象: 封装 继承 多态 

    (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. 让新对象继承(_ _proto_ _)构造函数的原型对象

                   iii. 调用构造函数,传入实参,并自动替换构造函数中的this为new正在创建的新对象。构造函数中,通过强行赋值的方式为新对象添加规定的属性,并保存属性值。

                   iv. 返回新对象的地址,保存到=左边的变量中。

            3). 优点: 重用对象结构代码

            4). 缺点: 如果构造函数中包含方法定义,则每次创建新对象都会重复创建相同方法的副本。             ——浪费内存!

    (2). 继承: 

             a. 今后,只要同一类型所有子对象共用的方法和属性值,都要集中保存在构造函数的原型对象中!

          构造函数.prototype.属性名/共有方法名=属性值/function(){ ... }

             b. 自有属性和共有属性:

            1). 获取属性值:都可用"子对象.属性名"

            2). 修改属性值:

                   i. 自有属性: 子对象.自有属性名=新值

                   ii. 共有属性: 构造函数.prototype.共有属性名=新值

            c. 内置类型原型对象:

          1). 11种内置类型/对象: String, Number, Boolean, Array, Date, RegExp, Math(对象), Error, Function, Object, global(对象)

            2). 一种类型=构造函数+原型对象

                   i. 构造函数: 创建子对象

                   ii. 原型对象: 为所有子对象保存共有成员

            3). 查看该类型共有哪些API: 类型名.prototype

            4). 该类型缺少想用的方法: 类型名.prototype.共有新方法=function(){ ... }

            d. 原型链: 保存着一个对象可用的所有属性和方法。控制着属性和方法的使用顺序:先自有再共有——就近原则!

    (3). 多态 

    重点讲重写:如果子对象觉得从父对象继承来的成员不好用,可以在子对象自己内部重写和父对象同名的成员,覆盖父对象的成员,优先使用自己的。

    ******面向对象终极总结: 封装,继承,多态******

    ①封装: 创建对象,2种:

      如果只创建一个对象: {}

      如果反复创建多个相同结构的对象: 构造函数

    ②继承: 所有子对象共用的属性值和方法,都要放在构造函数的原型对象中

    ③多态: 重写: 只要觉得从父对象继承来的成员不要用,都在子对象中重写同名成员

    ④如果觉得这个父对象对象都不好用,可以自定义继承: 2种:

      1). 只换一个子对象的父对象: 2种:

      i. 子对象.__proto__=新父对象

      ii. Object.setPrototypeOf(子对象, 新父对象)

      2). 更换多个子对象的原型对象: 构造函数.prototype=新对象

    ********************************************************************

    7. 严格模式: "use strict"; ⏬

    (1). 禁止给未声明过的变量赋值

    (2). 静默失败升级为错误

    (3). 普通函数调用中的this不指window,而是指undefined

    (4). 禁用arguments.callee

    总结: this 判断this时,一定不要看他定义在哪儿。必须看它在哪里以何种方式调用 4种:

    1. obj.fun()  this->点前的obj对象

    2. fun()  this->默认指window

    3. new Fun()   this->new正在创建的新对象

    4. 类型名.prototype.共有方法=function(){ ... } 

             this->将来谁调用这个函数,就指谁

             将来调用这个函数的.前的某个子对象


    🆕【后文传送门】👉   ES5标准规范之严格模式下的保护对象_09​​ 


    ​​​​

    如果这篇【文章】有帮助到你,希望可以给【青春木鱼】点个👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【前端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️青春木鱼❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!     

  • 相关阅读:
    CSS 中::after的妙用(实现在margin中显示内容)
    用Java实现贪吃蛇小游戏
    总结改变和获取 url 的方法 (包括 umi,react-router,原生)
    使用API Monitor工具巧妙探测C++程序中监听某端口的模块
    小趴菜实战Mac上安装Anaconda
    【PHP库】phpseclib - sftp远程文件操作
    在Eclipse将Java代码打包为jar用于jmeter BeanShell
    Zookeeper(一)- Zookeeper介绍与集群部署
    ThinkPHP高仿蓝奏云网盘系统源码/对接易支付系统程序
    《重磅发布 | 80+大屏&组件模板,即刻下载、快速构建应用!遥遥领先~》
  • 原文地址:https://blog.csdn.net/sunyctf/article/details/125898004