JavaScript小测前的知识点整理复习 04.19

本文详细梳理了JavaScript的发展历程、语言特点、数据类型、存储转换、包装对象、标识符与表达式、函数定义和调用、执行上下文、作用域链、内存管理和闭包等内容,是JavaScript学习者的重要复习资料。
摘要由CSDN通过智能技术生成

01JavaScript发展历程及语言特点

背景知识

ECMAScript是JavaScript的语法标准。

前端JavaScript由ECMAScript和DOM(文档对象模型)、BOM(浏览器对象模型)组成。

JavaScript核心和DOM并不是不可分割的,它们的标准相互独立。

DOM对JavaScript来说是宿主对象,是语言中可更换的部分。

ECMAScript对JavaScript来说是,是核心语言,是不可被替代的功能。

浏览器是客户端JavaScript运行的宿主环境。

JavaScript语言特点

JavaScript是一种直译式脚本语言,是一种弱类型、动态类型语言。

JavaScript只能够在浏览器中执行吗?

–不是的,JavaScript 除了在浏览器中运行,还可以在其他的运行环境中运行,如 node.js 环境。目前 JavaScript 的运行环境有浏览器和 node.js 环境两种。

JavaScript 在浏览器中是如何运行的?

––浏览器下载 JavaScript 脚本文件后,由浏览器 JavaScript 引擎解释执行。

02数据类型以及存储和转换

数据类型分类

基本(原始)类型:Number、String、Boolean、Null、Undefined

引用(对象)类型:Object(Array、Function、Date)等

数据存储

基本数据类型的临时变量分配在栈区。

引用数据类型的变量的引用(地址)存储在栈区,被引用(指向)的对象存储在堆区。

var a = {x:10}
//变量a存在于栈中,{x:10}作为对象存在于堆中

参数传递:ECMAScript中所有函数的参数都是按值来传递的

–基本类型值:把变量里的数据值传递给参数,之后参数和变量互不影响。

–引用类型值:吧对象的引用(地址)值传递给参数,参数和对象都指向同一个对象,相互影响

function foo(num, obj) {
        num = 20;
        obj.value = "hello world";
      }
      var num1 = 10;
      var obj1 = {
        value: "hello"
      };
      foo(num1, obj1);
      console.log(num1); //10
      console.log(obj1); //hello world

数据类型转换

分为显示类型转换和隐式类型转换。

undefined和null 、NaN转换为False其他为true

03包装对象和数据类型转换

包装对象

对象是一个单独拥有属性和方法的实体。

包装对象:

–存取字符串、数字或布尔值的属性时临时创建的临时对象称为包装对象

–用来处理属性的引用,一旦属性引用结束,包装对象就会销毁。

包装类型和引用类型的区别:

–主要区别是对象的生存期

–字符值和字符串对象

–数字值和数值对象

–布尔值布尔对象。

临时对象在使用之后会立即释放

var str=”test”;
str.p = 4//设置临时对象属性
var t = str.p; // 临时对象已释放,再输出t时为undefined

数据类型转换

undefined和null会转换为空对象。

Object转换为Boolean时

任何对象转换为布尔值为true,包括空对象

真值(truthy)与假值(falsy)

在 JavaScript 中,真值指的是在强制转换布尔值时,转换后的值为真的值。所有值都是真值,除非它们被定义为假值(即除 false、0、""、null、undefined 和 NaN 以外皆为真值)。

进行类型比较的时候:

undefined == null,结果是true。且它俩与所有其他值比较的结果都是false。

String == Boolean,需要两个操作数同时转为Number。

String/Boolean == Number,需要String/Boolean转为Number。

Object == Primitive,需要Object转为Primitive。

console.log([] == ![]) //true

– 1. 等号右边有 ! ,优先级比 == 更高,优先计算右边的结果。 [] 为非假值,

​ 所以右边的运算结果为 false,即:![] ==> false

– 2. == 的两边分别是 object 和 boolean 类型的值

​ 把 object 转换成 number 类型,需要对 object 进行 ToNumber 操作,即

​ Number([].valueOf()) ==> 0

​ boolean 类型的值时先把这个值转换成 number 类型,右边转换成了 0,

​ 即Number(false) ==> 0

04标识符与表达式

标识符

–标识符是代码中用来标识变量、函数、或属性的字符序列

– 命名规则:

• 由字母、数字、下划线和$符号组成

• 不能以数字开头

• 大小写敏感(区分大小写)

注意:标识符不能和 JavaScript 其它关键字同名

保留字在某种意思上是为将来的关键字而保留的单词。因此保留字不能被用作变量名或函数名。

function add(a,b){}   //函数声明
var add = function(a,b){};  //函数表达式

JavaScript 解析器识别函数声明的条件是以 function 关键字开始,只要在 function关键字的前面有任何其他的元素,就会从函数声明转变为函数表达式。

–在 function 前面加!、+、 - 甚至是逗号等到都可以起到识别为函数表达式的效果

–在这些运算符中加括号是最安全的做法,因为它不会改变函数的返回值。

当逻辑运算符两边的操作数都是布尔类型

&& :真真为真,其余为假

|| : 假假为假,其余为真

当逻辑运算符两边的操作数不是布尔类型

–首先将左操作数转换成布尔类型

– 对转换后的左操作数进行逻辑判断(true or false)

– 根据短路原则返回原始左操作数或原始右操作数

短路原则:

–对于 &&,转换后的左操作数若为 true,则直接返回原始右操作数,若为 false 则直接返回原始左操作数

– 对于 | |,转换后的左操作数若为 true,则直接返回原始左操作数,若为 false 则直接返回原始右操作数

用途:通过遵循短路特性,使用 || 来设置函数参数的默认值

– 函数定义时可以给参数指定默认值,调用时若未传参数则该参数的值取它定义时的默认值

//定义一个计算圆面积的函数area_of_circle(),它有两个参数:
//r: 表示圆的半径;
//pi: 表示π的值,如果不传,则默认3.14
function area_of_circle(){
    return r * r * (pi || 3.14);
}

比较运算符:

JavaScript 有两种比较方式:严格比较运算符和宽松比较运算符。

​ 严格相等运算符(===)

– 仅当两个操作数的类型相同且值相等为 true

​ 宽松相等运算符(==)

– 在进行比较之前,将两个操作数转换成相同的类型

赋值表达式的返回值为右操作数

逗号操作符:– 对它的每个操作数求值(从左到右),并返回最后一个操作数的值

练习:

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };
console.log(a.x);   //undefined
console.log(b);	    //n: 1  x: {n: 2}

a.x = a = { n: 2 };是连续赋值,同时点运算符优先级高,所以先执行a.x = {n:2},

然后执行a = {n : 2};

switch 语句中的 case

–case在比较时使用的是全等操作符比较 ,因此不会发生隐式类型转换。

–case后可以使一个表达式(如i<60)

05函数定义和调用形式

函数定义方式

三种:

–通过函数声明的形式来定义

–通过函数表达式的形式来定义

–通过Function构造函数实例化的形式来定义

Function构造函数:

– 可以传入任意数量的实参

– 最后一个实参为函数体

– 函数体中 javascript 语句之间分号隔开

– Function 构造函数创建一个匿名函数

new Function( [arg1[, arg2[, …argN]], ], functionBody)

函数定义三要素:函数名、函数的参数、函数的返回值。

匿名函数、具名函数优势、代理函数名

函数的name属性会返回函数实例的名称

使用new Function()语法的函数其名称为"anonymous"

函数的length属性指明函数定义的形参个数

arguments

JavaScript 函数在定义时有固定数目的命名参数,但当调用这个函数时,传递给它的参数数目却可以是任意的。

arguments 对象

– 代表传入函数的实参

– 是函数中的局部变量

– 不能显式创建,只有函数调用时才可用

– 它是一个类数组对象

类数组对象:

– 与数组一样具有 length 与 index 属性

– 本质确实个 Object

arguments与形参的 “双向绑定” 特性

– 在调用时 arguments 对象与实际传递了值的形参变量发生双向绑定

– arguments 对象中的对应单元会和命名参数建立关联

arguments中的length属性:

– 表示函数调用时传入的实参数量

– 在调用时,实参个数确定, arguments.length 确定, 不会再发生改变。

函数对象call/apply/bind方法

toString方法:返回一个当前函数源代码的字符串

valueOf方法:返回函数本身

this关键字

– 在 function 内部被创建

– 指向调用时所在函数所绑定的对象

– this 不能被赋值,this 的值取决于函数被调用的方式

apply/call/bind方法总结:

– apply,call,bind 三个方法第一个参数都是改变函数在调用时 this 指向的对象

– apply,call,bind 第一个参数为空,null,undefined,this 指向的是 window

– apply,call 两个方法只是参数形式有所不同,apply 参数是一个数组,call 参数则是列表序列

– apply,call 都会立即调用函数执行,bind 不会立即调用函数

函数调用形式

– 作为函数直接调用:定时器函数,立即执行函数

– 作为对象方法调用:事件函数

– 作为构造函数调用

– 通过 call/apply 间接调用

06函数定义和调用过程

执行上下文

JavaScript 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言

– 编译型语言写的程序执行之前,需要一个专门的编译过程,把所有程序编译成为机器语言的文件

– 解释型语言在运行程序的时候才解析,每执行一段代码就要翻译一段代码

– 两种方式编译的时机不同

JavaScript 引擎是一段一段地运行代码的

JavaScript 代码执行时,会为当前代码创建相应的运行环境

执行上下文(execution context) 简称EC

– 可以理解为当前代码的运行环境

– 作用是用来保存当前代码运行时所需要的数据

– 在全局环境、函数环境中会创建执行上下文

执行上下文栈(Execution context stack,ECS)

– 执行上下文栈按照函数的调用顺序来管理执行上下文

– 栈底永远是全局上下文,栈顶是当前正在执行的函数

– 特点:先进后出

注意:函数执行时才会创建执行上下文。

执行上下文的生命周期

– 创建阶段 :生成变量对象、建立作用域链、确定this指向

– 执行阶段 :变量赋值、函数引用、执行其他代码

– 等待回收阶段

每个执行上下文都有一个与之关联的变量对象(variable object)和一个作用域链(scope chain)

testEC = {
    VO :{},          //变量对象
    scopeChain : [], //作用域链
    this  : {}       //this指向
}

return语句作用:

–返回值

–终止函数的执行:销毁当前执行上下文,弹出执行上下文栈。

变量对象

变量对象(Variable Object)

– 变量对象是与执行上下文相关的数据作用域(scope of data) 。

– 变量对象是与上下文关联的特殊对象,用于存储被定义在上下文中的变量(variables) 和函数声明(function declarations)

变量对象创建过程

– 建立 arguments 对象

– 检查当前上下文的函数声明

– 检查当前上下文中的变量声明

JavaScript代码运行机制

分为两个阶段:

–代码解析阶段:将代码翻译成可执行代码 (预解析:声明提升)

–代码执行阶段:执行可执行代码

JavaScript编译和执行过程

–全局解析阶段(全局预解析)

– 全局顺序执行阶段(变量赋值、函数调用等操作)

– 当遇到函数调用时,进行函数范围内的预解析,再执行函数内代码,

– 当存在函数嵌套时,以此类推,会进行多次函数解析与执行

注:解析执行是一个不断交替的过程。

预解析工作之一:声明提升

– 所有的变量声明和函数声明提升当前作用域的最前面

声明提升规则:

– 规则1:函数声明整体提前

– 规则2:变量声明提前,赋值留在原地

– 规则3:函数会优先被提升,然后才是变量

– 规则4:函数声明有冲突,会覆盖;变量声明有冲突,会忽略

foo(); // 3
function foo() {
    console.log(1);
}
var foo = function() {
    console.log(2);
};
function foo() {
    console.log(3);
}
foo();

等价于:

/*
function foo() {       //被覆盖
    console.log(1);
}
*/
function foo() {
    console.log(3);
}
//   var foo;      被忽略
foo();     //3
foo = function() {
    console.log(2);
};
foo();     //2

全局上下文的变量对象:

浏览器中的全局上下文的变量对象:

–变量对象就是window对象

–在页面关闭前一直存在

windowEC.VO = window;

作用域链

作用域

– 作用域是一套关于如何存储变量当中的值,并且能在之后对这个值进行访问修改的规则

作用域类型

– 全局作用域(global scope)

– 函数作用域(function scope)

– 块作用域(block scope)

全局作用域(global scope)

– 在全局作用域下声明的变量叫做全局变量

– 全局变量在全局(代码的任何位置)下都可以使用

– 全局作用域中无法访问到局部作用域中的变量

全局变量的创建方式

– 在全局作用域下 var 声明的变量

– 在函数内部,没有使用 var关键字声明直接赋值的变量

– 使用 window 全局对象创建的属性和方法

函数作用域(function scope)

– 在函数作用域下声明的变量叫做局部变量

– 局部变量只在当前函数内部中使用

注意:a = 20;这种没有用var的,也是全局的。但要注意假如这句被包含在函数中,函数必须运行,这个全局变量才能被创建。

var a = 10;
b = 20;
function fun(){
    var a = 100;
    c=200;
    function bar (){
        var a =500;
        d = 600;
    }
    bar();
    console.log(d);
}
fun();    //输出了600

– 局部作用域中可以访问到全局作用域中的变量

局部变量的创建方式

– 在函数内部通过 var 声明的变量

– 函数的形参

块作用域(block scope)

– 任何一对花括号 { } 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域

– ES5 没有块作用域,在 ES6 中添加了块作用域

作用域模型

分为两种:

–词法作用域(静态性)是由函数定义的书写位置决定的,与调用位置无关

–动态作用域(动态性)是由调用位置决定,不关心变量和函数的定义的书写位置

function foo() {
    console.log(a);
}
function bar(){
    var a = 3;
    foo();
}
var a =2;
bar();    //输出2
/*
        步骤:foo的上一层是全局。遵从的是静态性;与书写位置有关
                与调用位置无关
*/

词法作用域补充部分

– 通过 new Function 创建的函数对象不遵从静态词法作用域

– 通过 new Function 创建的函数对象总是在全局作用域中执行

[[scope]] 属性

– 虚拟属性,无法访问和修改

– 函数创建定义时生成的属性,保存着这个函数所有父级执行上下文环境中的变量对象的集合

var x = 10;

function foo() {
    console.log(x);
}
foo(); // 10

function fun() {
    var x = 20;
    var foo1 = foo;
    foo1(); // 10还是20?  是10
}
fun();

在复制函数的时候, 复制后的函数与复制前的函数引用的是同一个[[scope]] 属性

作用域链:

–由当前执行环境与所有父级执行环境的一系列变量对象组成
–ScopeChain = VO + [[scope]]
– 提供对变量和函数访问的权限和顺序的规则

内存空管理

垃圾回收机制:

– 当一个值失去引用之后就会回收

– 一般的,当一个函数的执行上下文运行完毕之后,内部的所有内容就会失去引用,被垃圾回收机制回收

– 但是,一个函数的执行上下文运行完毕之后,内部的内容仍然被引用着,就不会被回收

函数定义

– [[scope]] 作用域确定

函数执行

– 解析阶段 作用域链确定 创建变量对象(声明提升规则)

(执行上下文创建阶段)

– 执行阶段 修改变量对象

(执行上下文执行阶段)

函数执行结束

– 执行环境不被引用,执行上下文被销毁

– 执行环境被引用,执行上下文不销毁

07IIFE、闭包和this

IIFE

IIFE英文全称:Immediately-Invoked Function Expression即立即执行的函数表达式。

lIFE的作用(建立函数作用域,解决ES5没有块作用域所带来的问题,如:变量污染变量共享等问题)

IIFE写法:

–使用小括号

–与运算符结合

–JS(ES5)中没有块作用域,js文件内和文件间的同名变量容易互相污染

–我们往往会通过IIFE引入一个新的作用域来限制变量的作用域

闭包

– 函数与对其词法环境的引用共同构成闭包。

– 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所需访问的所有局部变量。

闭包的作用

– 可通过闭包访问函数作用域内的局部变量

– 使函数中的变量被保存在内存中不被释放

闭包的缺点

– 由于闭包会使得函数中的变量都被保存在内存中,内存消耗大

– 闭包会在父函数外部,改变父函数内部变量的值

闭包的两种常见形式:

以普通函数形式返回

作为对象的方法返回

this绑定

– this 是被自动定义在所有函数的作用域中一个关键字

– this 是在函数运行期间绑定,与函数定义无关

this 作用

– 复用代码,为函数自动引用合适的上下文对象

– 提供了一个更加优雅而简便的方式来隐式传递一个对象引用

绑定规则:

作为函数直接调用(定时器函数、立即执行函数) => 默认绑定

作为对象方法调用(事件函数) => 隐式绑定

作为构造函数调用 => new绑定

通过call / apply间接调用 => 显示绑定

new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

严格模式

开启严格模式

– 整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 “use strict”;

– 某个函数开启严格模式,得把 “use strict”; 声明放在函数体所有语句之前

严格模式对 JavaScript 的语法和行为,都做了一些改变

– 普通模式中,如果一个变量没有声明就赋值,默认是全局变量

严格模式下,禁止这种用法,变量必须先声明再使用

– 普通模式中,在全局作用域函数中的 this 指向 window 对象

严格模式下,全局作用域中函数中的 this 是 undefined

– 普通模式中,构造函数不加 new 也可以调用,this 指向全局对象

严格模式下,构造函数不加 new 调用,this 报错

– 普通模式中,函数允许参数重名

严格模式下,函数参数不允许重名

函数形式

纯函数

– 相同的输入得到相同的输出

– 不会产生副作用

高阶函数:例如定时器

– 函数的参数为函数

– 函数的返回值为函数

回调函数

– 一个函数被作为参数传递给另一个函数(在这里我们把另一个函数叫做“otherFunction”),回调函数在 otherFunction 中被调用。

– 回调函数并不会马上被执行。它会在包含它的函数内的某个特定时间点被“回调”(比如定时器)

最近很忙,烂七八糟,没有正常更新。这是为了4.20的小测整理的JavaScript基本内容。冲冲冲!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值