一、严格模式

说明JavaScript中有严格模式和非严格模式两种运行环境

关键字 “use strict”;

实现严格模式 只需要在脚本代码中添加上上述关键字即可。

关键字具体说明

(1) 注意区分大小写,必须全部都是小写的
(2) 注意空格,整个字符串总共10个字符
(3) 单引号和双引号无所谓,但是需要有引号
(4) 必须写在作用域的最顶部,注意其具体的位置
(5) 可以加分号,也可以不加,但是必须是一个字符串

注意 下面的关键字写法均是错误的

"USE strict";
" use strict ";
"("USE strict").toLowerCase();"

➥ 严格模式使用注意

> 〇 修正this的值
> ① 所有的变量必须使用var 关键字声明
> ② 不能使用`delete`关键字删除全局变量
> ③ 在对象中不允许有同名的属性
> ④ 函数的参数必须唯一(不能出现同名的参数)
> ⑤ `arguments`对象的行为不同,严格模式下和实参相对独立
> ⑥ 禁用了`argument.callee`和`caller函数`
> ⑦ 不能在if语句中声明函数
> ⑧ 禁止使用`eval`和`argument`作为标识符
> ⑨ 禁用了`with`语句和八进制字面量

001 所有的变量都必须使用var关键字声明

a = 10;             //错误的演示
console.log(10);

002 不能使用delete关键字删除全局变量

    //在非严格模式下,删除失败(静默失败)   失败了不吭声,严格模式下直接报错
var a = 10;
delete a;
console.log(a);

003 在对象中不允许有同名的属性

    //在非严格模式下,会使用后面的属性赋值作为最终值,在严格模式下则直接报错
var obj = {
name:"张三",
name:"李四"
}
console.log(obj);

004 函数的参数必须唯一(不能出现同名的参数)

    //在非严格模式下,如果函数在定义的时候,使用了多个同名的参数,则在函数内部形参的实际值为最后一个传入的实参值
//在严格模式下,直接报错
// function func(a,a,a) {
// console.log(a);
// console.log(arguments);
// } function func(a,b,c) {
console.log(a);
console.log(arguments);
}
func(1,2,3);

005 arguments对象的行为不同

(1)严格模式下,在函数内部修改了对象的指向,对arguments的值不会产生影响
(2)在严格模式下,形参的值和arguments的值是相互独立的,在函数内部修改了形参的值对arguments不受影响
(3)在非严格模式下,修改了形参的值,arguments中的数据会跟着改变
    //测试引用类型的值作为函数的参数
function funcName(obj) {
console.log(obj);
console.log(arguments[0]); //在函数内部修改形参的值
obj = {age:20};
console.log(obj);
console.log(arguments[0]);
} funcName({name:"张三"});
//测试基本类型数据作为函数的参数
function fun(str) {
console.log(str);
console.log(arguments[0]);
str = "hello";
console.log(arguments[0]);
} fun("hi");

006 禁用了argument.callee和caller函数

argument.callee是对函数自身的引用 argument.calller是对调用函数的引用

        var num = (function (n) {
if (n ==1)
{
return 1;
} return arguments.callee(n-1) + n;
})(10); console.log(num); //55

007 不能在if语句中声明函数

//如果在if语句中声明函数,则会产生语法错误
if (true)
{
console.log("________");
function demo() {
console.log("呵呵呵呵");
} demo();
}

008 禁止使用eval和argument作为标识符

    var eval = "测试的字符串";
console.log(eval); var arguments = "参数列表";
console.log(arguments);

009 修正this的值

    在严格模式下,函数this的值始终是指定的值,无论指定的是什么值
var name = "测试的name";
function demoTest() { //在非严格模式下,打印出来的this为全局的对象window
console.log(this); //在严格模式下打印出来的this为undefined
}
demoTest();

010 禁用了with语句

  var o = {name:"暂时干",age:20};
with(o)
{
name = "lisi";
age = 48
}
console.log(o);

11 禁用了八进制

    //以0开头的数据常常引起混乱
//var num = 023; //2*8 + 3 ==> 19
//console.log(num); //19

严格模式书写格式

01 必须使用单引号或者是双引号括住字符串
02 必须使用小写,不能出现大写字符
03 必须是10个字符,不能多和也不能少
04 字符串后面的分号可以省略
05 必须写在当前作用域的最顶上
    //"use strict";   //正确写法
//"use strict" //正确写法 分号可以省略
//'use strict'; //正确写法 可以使用单引号
//"use strict"; //错误写法 必须是10个字符
//"use Strict"; //错误写法 所有的字符都必须小写 "use strict";
a = 10;
// "use strict"; //错误写法
b = 20;
console.log(a);

作用范围

① 函数的顶部(只对当前的函数有效)

② script标签的顶部,只对当前的标签有效,对页面中其他的script无效

    //位置01       对func01和func02都有效
//"use strict"; function func01() {
//位置02 对func01有效,对func02无效
//"use strict";
a = 10;
console.log(a);
} function func02() {
//位置03 对func02有效,但对func01无效
//"use strict";
b = 20;
console.log(b);
} func01();
func02();

二、作用域和闭包

作用域 变量其作用的范围就是它的作用域

块级作用域 JavaScript中没有块级作用域

 for (var i = 0; i < 10; i++) {
var num = i;
}
console.log(i);
console.log(num);
//**说明** 如果有块级作用域,那么i和num打印的结果应该为undefined

词法作用域 词法作用域指的是在代码写好的那一刻,变量的作用域就已经确定了。

动态作用域 变量的作用域由执行时的环境所决定,主要关注的是当前的函数调用栈

JavaScript语言是词法作用域的

在JavaScript中唯一能够创建作用域的东西是函数

    var a = "这是第一个a";
function func02() {
var a = "这是第二个a";
func01()
}
func02(); //打印结果为:这是第一个a
    var a = "这是第一个a";
function func01() {
console.log(a);
}
function func02() {
var a = "这是第二个a";
func01()
} func01(); //打印结果为:这是第一个a
func02(); //打印结果为:这是第一个a
    var a = "这是第一个a";
function func02() {
var a = "这是第二个a";
func01()
} function func01() {
console.log(a);
} func01(); //打印结果为:这是第一个a
func02(); //打印结果为:这是第一个a </script>

➥ 词法作用域的规则

> ① 在函数内部允许访问外部的变量
> ② 在`JavaScript`中只有函数可以创建作用域
> ③ 作用域规则首先应用提升规则分析(代码的预解析阶段)
> ④ 如果当前作用域中有该变量,则不考虑外部作用域的同名变量

三、作用域链

作用域链的结构

01 在js中函数可以创建作用域
02 函数中又可以创建函数(即又可以开辟新的作用域)
03 函数内部的作用域可以访问外部的作用域
04 如果有多个函数嵌套,那么就会构成一个链式的访问结构,也就是作用域链
05 注意:函数内部的作用域可以访问外部的作用域,但是外部的作用域却不能访问内部的作用域
    function f1() {
//f1--->全局作用域
function f4() {
//f4-->f1--->全局作用域
function f5() {}
}
}
function f2() {
//f2-->全局作用域
function f6() { }
} function f3() {}

作用域注意点

01 在获取值和设置值的时候都是访问变量
02 并非在函数内部写了变量,这个变量就属于当前函数,而是必须使用var 关键字声明的变量才属于当前函数
03 函数在声明的时候,里面的代码并不会执行,只有在函数调用的时候才会执行
04 声明函数时候的函数名,其实也是一个变量名,可以通过这个变量名来进行设置和赋值
05 注意:在变量内部使用var 关键字声明一个变量并不会把同名的全局变量覆盖掉
    var a = 10;
function f1() {
var a = 20; //注意:该行代码并不会覆盖掉全局变量中的变量a
console.log(a);
} f1(); //20
console.log(a); //10

代码说明 在函数中使用var关键字声明变量a并不会覆盖全局作用域中的a。 注意需要同时考虑变量在当前作用域的提升以及访问变量时的搜索原则。

    function f1() {
console.log(1);
} var f1 = "demo字符串"; //该行代码会把f1函数覆盖掉
f1 = "demoTest字符串";
console.log(f1);
//f1();

代码说明 函数的名称也是变量,如果在代码中出现同名的变量,那么函数的实现会被覆盖掉。

作用域中变量搜索原则

01 在使用变量的时候,首先在自己的作用域中查找
02 如果找到了就直接使用,如果没有找到,那么就到上一级作用域中去查找
03 重复上面的步骤,直到0级作用域,如果还是找不到那么就返回undefined(报错)

四、变量和函数声明的提升

JS中的代码执行分为两个步骤: ① 预解析② 执行

其中JavaScript解析器引擎在预解析阶段会对使用var关键字声明的变量和function声明的代码块进行提升操作,把这些变量提升到当前作用域的顶端。

这里简单列出代码提升的几种情况 => (函数 && 变量)

001 函数提升

    func();
function func() {
console.log("测试的函数");
}

02 变量提升

    console.log(a);         //打印出来的结果为undefined
var a = 10; //var a; //注意:只会对变量的声明进行提升
//console.log(a);
//a = 10

03 函数同名情况提升

    func01();                   //打印last
function func01() {
console.log("first");
} func01(); //打印last
function func01() {
console.log("last");
} //模拟提升后的情况
// function func01() {
// console.log("first");
// } // function func01() {
// console.log("last");
// } // func01();
// func01();

说明 预处理的时候,同名的函数都会进行提升,但是后面的会覆盖掉前面的.

04 变量名和函数同名的情况

    console.log(a);                     //打印function
function a() {
console.log("我是一个函数");
}
var a = 20;
console.log(a); //打印20 //变量和函数提升后的结果 错误
// function a() {
// console.log("我是一个函数");
// }
// var a ;
// console.log(a);
// a = 20;
// console.log(a); //变量和函数提升后的结果 正确
// function a() {
// console.log("我是一个函数");
// }
// console.log(a);
// var a = 20;
// console.log(a);

总结 如果出现变量和函数同名的情况,那么只会提升函数到当前作用域顶端而忽略变量的提升操作。

声明提升注意点

001变量的提升是分作用域的

    console.log(a); //undefined
var a = 10; //模拟提升
// var a;
// console.log(a); //undefined
// a = 10;
    var num = 10;
function func() {
var num = 20;
console.log(num);
}
console.log(num); //10
func(); //20 //模拟提升
// var num;
// function func() {
// var num;
// num = 20;
// console.log(num);
// }
// num = 10;
// console.log(num); //10
// func(); //20
    var num = 10;
function func() {
console.log(num);
var num = 20;
}
console.log(num); //10
func(); //undefiend //模拟提升
// var num;
// function func() {
// var num;
// console.log(num);
// num = 20;
// }
// num = 10;
// console.log(num); //10
// func(); //undefiend
        var num = 10;
function func() {
console.log(num);
num = 20;
}
console.log(num); //10
func(); //10 //模拟变量提升
// var num;
// function func() {
// console.log(num);
// num = 20;
// }
// num= 10;
// console.log(num); //10
// func(); //10
// console.log(num); //20

002 函数表达式的提升

说明 在使用函数表达式创建函数时整个函数表达式并不会进行提升,只会对var声明的变量提升。

    func();
var func = function () {
console.log("会不会被调用");
} //以上如上代码将报错
//模拟提升的过程
// var func;
// func(); //找不到这个函数
// func = function () {
// console.log("会不会被调用");
// }

五、闭包

闭包 通过某种方式实现的一个封闭的、包裹的对外不公开的结构 | 空间。

原理 变量的访问原则(即上一级的作用域无法访问下一级的作用域),其实函数本身也是闭包。

闭包要解决的问题 提供一种间接的方式能够访问到函数内部的数据(变量)

实现思路

01 我们需要能够在函数外部访问函数内部的变量,正常情况无法访问;
02 在函数内部如果新创建函数,那么安装作用域链的原则,这个新创建的内部函数能够访问到函数中的这些变量。
03 我们如果能够操作函数中新创建的函数,那么就能够操作函数中的变量(如访问和设置等)
04 如果要能够操作函数中新创建的函数,那么需要在函数中把新创建的函数返回。
05 调用函数,接收并得到其返回值(是一个函数)
06 调用返回值(函数),通过函数传参的方式来设置函数中的变量。
07 调用返回值(函数),通过在函数内部再次return的方式来访问函数中的变量。

闭包的基本模式

在函数内部创建函数(内部函数),在这个内部函数中,可以操作外部函数中的变量
01 在函数(外部)中创建函数(内部函数),在该函数(内部函数)中操作外部函数中的变量
02 在外部函数中,把内部函数作为返回值返回
03 调用外部函数,并接收其返回值(是一个函数)
04 调用接收到的返回值(内部函数),来间接的操作外部函数中的变量
    function func() {
var num = 10;
return function (n) {
num = n;
console.log(num);
}
} var funcName = func();
funcName("哗啦哗啦");

001 获取单个数据(考虑赋值)

    function func() {
var num = 123;
return function (a) {
if (a !== undefined)
{
num = a;
}
return num;
}
} var f1 = func();
var x = f1(456);
var y = f1();
console.log(x);
console.log(y);

说明 上面的代码能够支持通过闭包对函数中的变量num进行访问(取值)或赋值的操作。

002 获取多个数据(数组)

    function func() {
var name = "张学友";
var age = 40;
return [
function getName() {
return name;
},
function getAge() {
return age;
}
]
} var foo = func();
console.log(foo[0]()); //张学友
console.log(foo[1]()); //40

说明 上面的代码能够满足返回多个变量值的需求,但是要数组操作的方式并不常见,且和使用习惯不符合。

003 利用对象返回并设置对个变量值

    function foo() {
var name = "张学友";
var age = 45; return {
getName:function () {
return name;
},
getAge:function () {
return age;
},
setName:function (nameValue) {
name = nameValue;
},
setAge:function (ageValue) {
age = ageValue;
}
}
} var func = foo();
console.log(func.getName()); //张学友
console.log(func.getAge()); //45 func.setName("张三");
func.setAge(30);
console.log(func.getName()); //张三
console.log(func.getAge()); //30

闭包作用的说明

(1)创建一个私有的空间保护数据,外界如果需要访问数据必须通过函数提供的指定方法
(2)在这些指定的方法中,我们可以设置一些校验的逻辑,以保证对数据访问和设置的安全性

关于闭包的一些练习

//备注:001
function foo() {
var num = 123;
console.log(num);
}
foo();
console.log(num);
//备注:002
var scope = "global";
foo(); function foo() {
console.log(scope);
var scope = "local";
console.log(scope);
}
//备注:003
function f1(){
if("a" in window){
var a = 10;
}
console.log(a);
}
f1();
//备注:004
if("a" in window){
var a = 10;
}
console.log(a);
//备注:005
if(!"a" in window){
var a = 10;
}
console.log(a);
//备注:006
var foo = 1;
function bar() {
if(!foo)
{
var foo = 10;
}
console.log(foo); //10
}
bar();
//备注:007
function Foo() {
getName = function(){
console.log("1");
}; this.show = function () {
console.log("hello");
}
return this;
}
Foo.getName = function() {
console.log("2");
};
Foo.prototype.getName = function(){
console.log("3");
};
var getName = function() {
console.log("4");
};
function getName(){
console.log("5");
} Foo.getName();
getName();
Foo().getName();
getName();
new Foo.show()
new Foo.getName()
new Foo().getName();
new new Foo().getName();

前端开发系列016-基础篇之Javascript面向对象(五)的更多相关文章

  1. 前端开发【第4篇:JavaScript基础】

    JavaScript简述 上一篇文章已经聊过JavaScript的历史了这里不再复述了直接切入正题,JavaScript是一门解释型.动态类型.弱类型语言. 解释型语言和编译型语言就类似看一本书,编译 ...

  2. 前端开发【第3篇:JavaScript序】

    JavaScript历史 聊聊JavaScript的诞生 JavaScirpt鼻祖:Bremdan Eich(布兰登·艾奇),JavaScript的诞生于浏览器的鼻祖网景公司(Netscape),发布 ...

  3. 前端开发【第6篇:JavaScript客户端(浏览器)】

    Web浏览器中的JavaScript 客户端JavaScript时间线 1.Web浏览器创建Document对象,并且开始解析web页面,解析HTML元素和它门的文本内容后添加Element对象和Te ...

  4. 前端开发【第5篇:JavaScript进阶】

    语句 复合表达式和空语句 复合表达式意思是把多条表达式连接在一起形成一个表达式 { let a = 100; let b = 200; let c = a + b; } 注意这里不能再块级后面加分号, ...

  5. 从0到1用react+antd+redux搭建一个开箱即用的企业级管理后台系列(基础篇)

    背景 ​ 最近因为要做一个新的管理后台项目,新公司大部分是用vue写的,技术栈这块也是想切到react上面来,所以,这次从0到1重新搭建一个react项目架子,需要考虑的东西的很多,包括目录结构.代码 ...

  6. 前端开发:css基础知识之盒模型以及浮动布局。

    前端开发:css基础知识之盒模型以及浮动布局 前言 楼主的蛮多朋友最近都在学习html5,他们都会问到同一个问题 浮动是什么东西?  为什么这个浮动没有效果?  这个问题楼主已经回答了n遍.今天则是把 ...

  7. ESP8266开发之旅 基础篇① 走进ESP8266的世界

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  8. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  9. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  10. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

随机推荐

  1. WPF旋转板栈设计一例

    效果图 项目中需要做一个机台的平面视图,点击其中一个料盒时,弹出该料盒的料管列表,用WPF示例做了一下,效果如下: 用户控件XAML 1 <UserControl x:Class="W ...

  2. Python3工具_C段扫描工具_主机存活探测初始

    之前搞了多线程 然后基于多线程写了个C段主机存活探测工具 扫描主函数 def sub(): global num num=0 while not q.empty(): threadLock.acqui ...

  3. Go-Spring v1.2.0 版本简介

    引言 随着微服务和云原生架构的普及,Go 语言以其高并发.低延迟和简洁语法在后端开发领域迅速崛起.然而,原生 Go 在项目结构.依赖管理.配置热更新等方面相比 Java Spring 生态尚有短板.G ...

  4. 【MOOC】华中科技大学计算机组成原理慕课答案-第四章-存储系统(二)

    待整理. 单选 1 32位处理器的最大虚拟地址空间为 A. 2G B. 8G C. 16G √D. 4G 2 在虚存.内存之间进行地址变换时,功能部件 ( )将地址从虚拟(逻辑)地址空间映射到物理地址 ...

  5. FastAPI-请求参数与验证

    最近想搞一下接口, 希望能简单上手, 前后端分离, 大致看了一遍 SpringBoot, Gin, NodeJs, Flask, Django, FastAPI 等, 感觉还是用 Python 语言来 ...

  6. vue3 基础-API-响应式 ref, reactive

    上篇咱介绍了 CompositionAPI, 其核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题. 然后初介绍了 setup 函数的作用, 即其是在 cr ...

  7. C# 基础问题汇集

    (1)new List并不是null,可以正常的被遍历和AddRange class Program { public static void Main() { //var t = new test( ...

  8. Seata源码—9.Seata XA模式的事务处理

    大纲 1.Seata XA分布式事务案例及AT与XA的区别 2.Seata XA分布式事务案例的各模块运行流程 3.Seata使用Spring Boot自动装配简化复杂配置 4.全局事务注解扫描组件的 ...

  9. System.currentTimeMillis()高并发性能优化

    摘要:System.currentTimeMillis()性能问题的研究.测试与优化.   性能优化使用的测试环境: jdk版本jdk8   操作系统: macOS 版本:13.2.1 芯片: App ...

  10. Java 自定义线程池的线程工厂

      本文分享创建线程工厂 ThreadFactory 的三种方式,以方便大家快速创建线程池,并通过线程工厂给每个创建出来的线程设置极富业务含义的名字. 线程池大小考虑因素   由于需要自定义线程池,故 ...