JavaScript基础 - 学习笔记

JavaScript基础 - 学习笔记

This is a Learn Notes for JavaScript.


ECMAScript 与 JavaScript

ECMAScript(以下简称 ES)是一种语言标准,而 JavaScript(以下简称 JS)是对 ES 的一种实现。

说 JavaScript 的版本,实际上就是说它实现了 ECMAScript 标准的哪个版本。

快速上手

嵌入位置

JavaScript 代码可以直接嵌在网页的任何地方,不过通常我们都把 JavaScript 代码放到 中的

也可以把 JavaScript 代码放在单独的文件中,使用 <script src="..."></script> 引入。

可以在同一个 html 中引入多个 JS 文件、多次编写

<script type="text/javascript"> 中的 tpye 已不必显式书写,如今默认即 JS

运行 JS

直接在硬盘上创建好 HTML 和 JavaScript 文件,然后用浏览器打开。
这种方式运行部分 JavaScript 代码没有问题,但由于浏览器的安全限制,以 file:// 开头的地址无法执行如联网等 JS 代码。
最终,还是需要架设一个Web服务器,以 http:// 开头的地址来执行所有 JS 代码。

基本语法

  • JS 语法中,每个语句以 ; 结束,语句块用 {...}。但是 JS 并不强制要求语句结尾加 ; ,浏览器中的 JS 引擎会自动补上 ;

让 JS 引擎自动加分号,在某些情况下会改变程序的语义,导致运行结果与期望不一致。

  • 注释使用 // 注释单行,使用 /* ... */ 注释多行
  • JS 严格区分大小写,标识符的大小写敏感

数据类型简介

  • Number
123; // normal number
NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity
  • 字符串

使用 ' ...' 或者 "..." 表示字符串。

  • 布尔值

与 C++、Java、C#等一致。

  • 比较运算符

大于、小于、大于等于、小于等于,并无特殊。

JS 在设计时,有两种比较运算符:
第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。
由于 JS 这个设计缺陷,不要使用==比较,始终坚持使用===比较。

浮点运算要使用绝对值法,代替===比较符

例外NaN 这个特殊的 Number 与所有其他值都不相等,包括它自己。唯一能判断NaN的方法是通过isNaN()函数:

NaN === NaN; // false
isNaN(NaN); // true
  • null 和 undefined

null表示一个“空”的值,它和0以及空字符串''不同:0是一个数值,''表示长度为0的字符串,而null表示“空”。
在 JS 中,还有一个和null类似的undefined,它表示“未定义”。

区分两者的意义不大。大多数情况下,都应该用nullundefined仅仅在判断函数参数是否传递的情况下有用。

  • 数组

数组用[]表示,元素之间用,分隔。
另一种创建数组的方法是通过Array()函数实现:new Array(1, 2, 3); // 创建了数组[1, 2, 3]
数组的元素可以通过索引来访问。索引的起始值为0

  • 对象

JS 的对象是一组键-值组成的无序集合,例:

var person = {
    name: 'Bob',
    age: 20,
};

要获取一个对象的属性,用对象变量.属性名的方式:

person.name; // 'Bob'
  • 变量

变量名是大小写英文、数字、$和_的组合,且不能用数字开头,也不能是JavaScript的关键字。

申明一个变量用var语句,使用=对变量进行赋值。

变量名也可以用中文,但这是极其危险的行为

关于strict 模式,通过在 JS 代码第一行写上 'use strict',即可进入,会严格要求变量使用 var 定义。

ES6 字符串

  • 多行字符串
`这是一个
多行
字符串`;
  • 模板字符串
var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;

需要特别注意的是,字符串是不可变的,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果。

Array 数组

  • 直接给Arraylength赋一个新的值会导致Array大小的变化
  • 如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化
  • 在编写代码时,不建议直接修改Array的大小,访问索引时要确保索引不会越界

对象

  • 对象是一种无序的集合数据类型,它由若干键值对组成。
  • 访问属性是通过.操作符完成的,但这要求属性名必须是一个有效的变量名。如果属性名包含特殊字符,就必须用''括起来。访问这个属性也无法使用.操作符,必须用['xxx']来访问
  • 访问一个不存在的属性会返回undefined
  • 对象可自由增删属性

条件、循环

条件判断:

if (){
}
else {
}

普通 for 循环:

for ( ; ; ){
}

for in 循环,可遍历对象、数组:

var a = ['A', 'B', 'C'];
for (var i in a) {
    console.log(i); // '0', '1', '2'
    console.log(a[i]); // 'A', 'B', 'C'
}

while 循环:

while (){
}

do while循环:

do{
}while()

ES6 的 Map、Set

  • Map的键不必和对象一样(严格是string),可以是数值型,不去重
  • Set会进行自动去重

ES6 的 iterable

具有iterable类型的集合可以通过新的for ... of循环来遍历:

var a = ['A', 'B', 'C'];
for (var x of a) { // 遍历Array
    console.log(x);
}

那么for ... of循环和for ... in循环有何区别?

for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。for ... of则只循环集合本身的元素:

var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
    console.log(x); // '0', '1', '2', 'name'
}
for (var x of a) {
    console.log(x); // 'A', 'B', 'C'
}

更好的方式是直接使用iterable内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数:

var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    console.log(element + ', index = ' + index);
});

函数

定义函数

function funcname(x, y, z) {
    ......
    return ...;
}
  • function指出这是一个函数定义
  • funcname是函数的名称
  • (x, y, z)括号内列出函数的参数,多个参数以,分隔
  • { ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句

注意,函数体内部的语句,一旦执行到return时,函数就执行完毕,并将结果返回。如果没有return语句,函数执行完毕后,会返回undefined

由于JS 的函数也是一个对象,上述定义的函数实际上是一个函数对象,而函数名可以视为指向该函数的变量,即:

funcname = function(x, y, z) {
    ......
    return ...;
};

两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。

ES6 函数参数

  • JavaScript 允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多或者少也没有问题:多则舍弃,少则参数为 undefined
  • 关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array。利用arguments,即使函数不定义任何参数,还是可以拿到参数的值
  • function foo(a, b, ...rest) 中的 rest 可获得额外参数

return 的 trap

JavaScript引擎有一个在行末自动添加分号的机制,这可能让你栽到return语句的一个大坑。

// 此样例会有问题
// return会被修改为return;
return
    { name: 'foo' };

// 所以需要这样写
return {
	name: 'foo'
}

ES6 变量作用域

  • JavaScript 的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。内部函数的变量会“屏蔽”外部函数的变量。
  • JavaScript 的函数定义有个特点,它会先扫描整个函数体的语句,把所有变量的声明 提升到函数顶部,所以请***严格遵守“在函数内部首先申明所有变量”这一规则***

JavaScript 的变量作用域实际上是函数内部(不是块级),我们在for循环等语句块中是无法定义具有局部作用域的变量的。

在ES6中

  • 使用let可以获得块级作用域的变量
  • 使用const可以获得块级作用域的常量

ES6 解构赋值

// 1.
let [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// 2.
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']]; // 嵌套
// 3.
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
// 4.
let person = {
    name: '小明',
    age: 20,
    gender: 'male',
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zipcode: '100001'
    }
};
let {name, address: {city, zip}} = person; // 对象的解构赋值 层次要一致; 对应的属性不存在,变量将被赋值为undefined
var {name, single=true} = person; // 使用了默认值 避免 undefined
// 有些时候,如果变量已经被声明了,再次赋值的时候,要用小括号
var x, y;
({x, y} = { name: '小明', x: 100, y: 200});

高阶函数

function add(x, y, f) {
    return f(x) + f(y);
}

箭头函数

直接 return 版本:

x => x * x
// 等价于
function (x) {
    return x * x;
}

复杂 return 版本:

x => {
    if (x > 0) {
        return x * x;
    }
    else {
        return - x * x;
    }
}

多(无)参数版本:

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

返回对象:

x => ({ foo: x })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值