JavaScript 学习笔记一

202 阅读9分钟

一、基础

1、数据类型

  • 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、独一无二的值(Symbol)
  • 引用数据类型:对象(Object)、数组(Array)、函数(Function)

JavaScript 变量生命周期在它声明时初始化,局部变量在函数执行完毕后销毁,全局变量在页面关闭后销毁。函数参数只在函数内起作用,是局部变量。

2、类型转换

方法作用
Number()转换为数字
String()、 toString()转换为字符串
Boolean()转换为布尔值
toFixed()把数字转换为字符串,小数点后有指定位数的数字
parseFloat()解析一个字符串,并返回一个浮点数
parseInt()解析一个字符串,并返回一个整数
Number("99 88")   // 返回 NaN

var y = "5";      // y 是一个字符串
var x = + y;      // x 是一个数字

var y = "John";   // y 是一个字符串
var x = + y;      // x 是一个数字 (NaN)

不同的数值转换为数字、字符串、布尔值

3、typeof——检测变量的数据类型

typeof "John"                // string
typeof 3.14                  // number
typeof false                 // boolean
typeof [1,2,3,4]             // object
typeof {name:'John', age:34} // object
typeof new Date()             // 返回 object
typeof function () {}         // 返回 function
typeof myCar                  // 返回 undefined (如果 myCar 没有声明)

typeof null                  // 表示一个空对象引用,object
typeof undefined             // undefined
typeof NaN                    // 返回 number

constructor 属性:返回所有 JavaScript 变量的构造函数

"John".constructor                 // 返回函数 String()  { [native code] }
(3.14).constructor                 // 返回函数 Number()  { [native code] }
false.constructor                  // 返回函数 Boolean() { [native code] }
[1,2,3,4].constructor              // 返回函数 Array()   { [native code] }
{name:'John', age:34}.constructor  // 返回函数 Object()  { [native code] }
new Date().constructor             // 返回函数 Date()    { [native code] }
function () {}.constructor         // 返回函数 Function(){ [native code] }

可以使用 constructor 属性来查看对象是否为数组

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}

4、作用域

作用域为可访问变量,对象,函数的集合。

  • 局部作用域:变量在函数内声明,只能在函数内部访问。局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁。
  • 全局作用域:变量在函数外定义,即为全局变量,网页中所有脚本和函数均可使用。全局变量是 window 对象。 如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量。
// 此处可调用 carName 变量
function myFunction() {
    carName = "Volvo";// 全局变量,可使用 window.carName访问
    // 此处可调用 carName 变量
}

5、声明提升

函数及变量的声明都将被提升到函数的最顶部,变量可以在使用后声明,也就是变量可以先使用再声明。

x = 5; // 变量 x 设置为 5
var x; // 声明 x

只有声明的变量会提升,初始化的不会。

console.log(y) // undefined
var y = 7 // 初始化 y(变量声明 (var y) 提升了,但是初始化(y = 7) 并不会提升)

在严格模式(use strict)下你不能使用未声明的变量,会报错;同时,严格模式下不允许删除变量、对象、函数;不允许变量重名;不允许使用八进制;不允许使用转义字符;不允许对只读属性赋值等等。

6、 let 和 const(块级作用域)

ES2015(ES6) 新增加了let 和 const,let 声明的变量只在 let 命令所在的代码块内有效。const 声明一个只读的常量,声明时必须进行初始化,且初始化后值不可再修改。

块级作用域:let 和 const实现块级作用域,只在 所在的代码块 {} 内有效,在 {} 之外不能访问。

var x = 10;// 这里输出 x 为 10
{ 
    let x = 2;// 这里输出 x 为 2
}
// 这里输出 x 为 10

循环作用域:var 声明的变量是全局的,包括循环体内与循环体外;let声明的变量作用域只在循环体内,循环体外的变量不受影响。

var i = 5;
for (var i = 0; i < 10; i++) {}
// 这里输出 i 为 10

let i = 5;
for (var i = 0; i < 10; i++) {}
// 这里输出 i 为 5

window 对象:var 关键字声明的全局作用域变量属于 window 对象;let 声明的全局作用域变量不属于 window 对象。

const 的本质: const 定义的变量并非常量不可变,它定义了一个常量引用一个值。使用 const 定义的对象或者数组,其实是可变的。

const car = {type:"Fiat", model:"500", color:"white"};// // 创建常量对象
car.color = "red";// 修改属性
car = {type:"Volvo", model:"EX60", color:"red"};    // 错误


const cars = ["Saab", "Volvo", "BMW"];// 创建常量数组
cars[0] = "Toyota";// 修改元素
cars.push("Audi");// 添加元素
cars = ["Toyota", "Volvo", "Audi"];    // 错误

不能使用 let 关键字来重置 var 关键字声明的变量,不能使用 var 关键字来重置 let 关键字声明的变量。let、const 声明的变量不能声明提升;

二、正则表达式

正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。

// 语法
/正则表达式主体/修饰符(可选)
var patt = /runoob/i // runoob  是一个正则表达式主体 (用于检索),i  是一个修饰符 (搜索不区分大小写)
修饰符描述
i对大小写不敏感
g全局匹配(查找所有匹配而非在找到第一个匹配后停止)
m多行匹配
表达式描述
[abc]查找方括号之间的任何字符
[0-9]查找任何从 0 至 9 的数字
(x竖线y)查找任何以竖线分隔的选项
量词描述
n+匹配任何包含至少一个 n 的字符串
n*匹配任何包含零个或多个 n 的字符串
n?匹配任何包含零个或一个 n 的字符串
元字符描述
\d查找数字
\s查找空白字符
\b匹配单词边界
\uxxxx查找以十六进制数 xxxx 规定的 Unicode 字符
  • search():检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置
var str = "Visit Runoob!"; 
var n = str.search(/Runoob/i); // 6
  • replace():在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串
var txt = str.replace(/microsoft/i,"Runoob"); 
  • test():检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false
/e/.test("The best things in life are free!")
  • exec(): 用于检索字符串中的正则表达式的匹配。该函数返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null
/e/.exec("The best things in life are free!");

image.png

三、this 关键字

this 表示当前对象的一个引用。在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

执行环境对象
方法该方法所属的对象
单独使用全局对象
函数全局对象,在严格模式下,this 是未定义的(undefined)
事件接收事件的元素
call()、apply()将 this 引用到任何对象

显式函数绑定

call()、apply()允许切换函数执行的上下文环境(context),即 this 绑定的对象。

var person1 = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
var person2 = {
  firstName:"John",
  lastName: "Doe",
}
person1.fullName.call(person2);  // 返回 "John Doe"

四、异步

  • 同步:同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行;
  • 异步:不保证同步,执行将不再与原有的序列有顺序关系。异步就是从主线程发射一个子线程来完成任务。

image.png

  • 异步使用场景:

用子线程来完成消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。子线程独立于主线程,即使出现阻塞也不会影响主线程的运行。但是子线程一旦发射了就会与主线程失去同步而无法确定是否结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。

为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

  • 回调函数:

在启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。

function print() {
    document.getElementById("demo").innerHTML="RUNOOB!";
}
setTimeout(print, 3000);// print就是一个回调函数

五、Promise

Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。

Promise 构造函数只有一个函数参数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject。resolve 和 reject 都是函数,其中调用 resolve 代表一切正常,reject 是出现异常时所调用的。

Promise 类有 .then() .catch() 和 .finally() 三个方法,参数都是函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。

new Promise(function (resolve, reject) {
    var a = 0;
    var b = 1;
    if (b == 0) reject("Divide zero");
    else resolve(a / b);
}).then(function (value) {
    console.log("a / b = " + value);// a / b = 0
}).catch(function (err) {
    console.log(err);
}).finally(function () {
    console.log("End");// End
});

resolve()、return用于向下一个 then 传递一个值。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作。

  • resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
  • resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。
new Promise(function (resolve, reject) {
    console.log(1111);//1111
    resolve(2222);
}).then(function (value) {
    console.log(value);//2222
    return 3333;
}).then(function (value) {
    console.log(value);//3333
    throw "An error";
}).catch(function (err) {
    console.log(err);//An error
});

六、异步函数

异步函数(async function)是 ECMAScript 2017 标准的规范,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。

async function asyncFunc() {
    await print(1000, "First");
    await print(4000, "Second");
    await print(3000, "Third");
}
asyncFunc();

异步函数实际上原理与 Promise 原生 API 的机制是一模一样的,处理异常的机制将用 try-catch 块实现:

async function asyncFunc() {
    try {
        await new Promise(function (resolve, reject) {
            throw "Some error"; // 或者 reject("Some error")
        });
    } catch (err) {
        console.log(err);
        // 会输出 Some error
    }
}
asyncFunc();