JavaScript 笔记
Brief Syntax Introduction
- JS 是解释型语言。
解释型语言 与 编译型语言:
解释型:一行一行看,容易出错但方便,可以及时方便地找到出错位置以及出错原因,容易跨平台(可以嵌入到其他软件)。
编译型:把高级语言预先翻译成机器语言,并把结果保存下来,速度快(编译器优化),不易出错,但不能跨平台(e.g. .exe can't be run in MacOS)。
-
行末分号非必需: JS 中的每一行都可以选择使用分号终止,即编译器会自动补全没有用分号的地方。
-
JS 中的变量是弱类型的,即变量的类型只有在被赋值的时候才得到确认。
数据类型与变量
-
const
用来申明常量(一旦声明后续值不可更改),let
用来申明变量(一个变量只能申明一次,值以及值的类型可以被多次更改)。 -
JS 中允许一个变量未被提前申明就使用。此时该变量会被自动被申明为全局变量。若在程序的最开始加上
use strict
语句,则可以避免这支双刃剑带来的弊端。(在strict
模式下,变量必须要先经过申明,才能被使用,否则会报错) -
JS 中的基本类型有数字、字符串、布尔值、符号、
null
和undefined
。数字中不区分整数和浮点数。 -
JS 中遇到计算除法时除数为
0
的情况时,不会报错,会根据被除数的值来返回对应的结果。若被除数是正数,则返回Infinity
;若被除数是负数,则返回-Infinity
;若被除数是0
,则返回NaN
(Not a Number)。
除以0
的余数(1 % 0
)为NaN
。 -
与
python
类似, JS 中一个*
代表相乘,**
则代表幂运算。 -
JS 中
===
表示检查是否相等,!==
表示检查是否不等。
字符串
-
JS 中的字符串用
''
或""
括起来表示。若想表达的字符串中本身含有'
或"
,则需要用到转义字符。
e.g.I'm "OK"!
的表示是:'I\'m \"OK\"!'; -
在 JS 中输出多行字符串的方式是用反引号。
e.g.`No \n anymore `; -
与 python 类似,要把多个字符串连接起来,可以用
+
号连接。也可以通过模版字符串的方式来方便输出过程。(反引号与${}
的结合)let name = '小明'; let age = 20; let message1 = '你好, ' + name + ', 你今年' + age + '岁了!'; let message2 = `你好, ${name}, 你今年${age}岁了!` //message1 = message2 -
JS 中的字符串是不可变的,即不能通过
s[id] = 'A'
的方式来将s
中id
位置的字母改成A
。 -
JS 中有很多类似 python 和 C++ STL 中的字符串函数,如
toUpperCase
,indexOf
(搜索元素在数据结构中出现的位置,未找到则返回-1
),substring
等。
数组
-
JS 中的数组可以包含任意数据类型,并通过索引来访问/修改每个元素。
a = [1, 'hello, world', ['a', b, 100]]; a[0] = 'qaq'; a; // a = ['qaq', 'hello, world', ['a', b, 100]] -
在 JS 中允许给数组的
length
赋一个新值。除此之外,假如进行了数组的越界访问,也不会报错。var arr = [1, 2, 3]; arr.length = 6; arr; // arr 变为 [1, 2, 3, undefined, undefined, undefined] arr.length = 2; arr; // arr变为[1, 2] arr[4] = 'qaq'; arr; // arr 变为 [1, 2, undefined, undefined, 'qaq'] -
同 python 的切片类似,
slice()
可以将一个数组的局部“拿出来”,变成一个新的数组。var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C'] arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G'] var aCopy = arr.slice(); aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G'] -
如果要在数组的头部添加若干元素,可以使用
unshift()
;shift()
则可以用来把数组的第一个元素删除。
splice()
则可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素。var arr = [1, 2, 3, 4]; arr.unshift('A', 'B'); // 返回Array新的长度: 6 arr; // ['A', 'B', 1, 2, 3, 4] arr.shift(); // 'A' arr; // ['B', 1, 2, 3, 4] // 从索引 1 开始删除 3 个元素,然后再添加 2 个元素: arr.splice(1, 3, 'qaq', 222); // 返回删除的元素 [1, 2, 3] arr; // ['B', 4, 'qaq', 222] -
如果要在数组的尾部添加/删除若干元素,可以使用
push()
和pop()
。var arr = [1, 2]; arr.push('A', 'B'); // 返回Array新的长度: 4 arr; // [1, 2, 'A', 'B'] arr.pop(); // pop()返回'B' arr; // [1, 2, 'A'] arr.pop(); arr.pop(); arr.pop(); // 连续pop 3次 arr; // [] arr.pop(); // 空数组继续pop不会报错,而是返回undefined arr; // []
对象
在 JS 中,对象是一种无序的集合数据类型,由若干键值对组成。用法与 python 中的 dictionary
很像。但 JS 对象的键必须是字符串,值可以是任意数据类型。这一点和 dictionary
对键和值类型的无限制不同( JS 中 Map
的引入解决了这个问题)。
var xiaoming = { name: 'Yiling Zhang', birth: 2003, school: 'Xidian University', height: 1.77, weight: 65, score: 100 };
函数
函数的定义与调用
function get_pow(x, y) { var res = 1, i; for (i = 1; i <= y; i++) res = res * x; return res; } var get_pow = function (x, y) { var res = 1, i; for (i = 1; i <= y; i++) res = res * x; return res; }; //匿名函数,在 JS 中函数也可以作为变量,通过这个变量就可以调用该函数。
传入函数的多个变量以逗号分隔开。如果传入某个函数的变量的个数,比该函数预先设定的要多,程序仍然会返回正确的结果,且不会报错。如果要少,则不会报错,但是结果可能不正确。
在函数的内部,系统提供了关键字 arguments
。该关键字只在函数内部起作用,通过该参数可以访问到传入该函数的所有参数。可以通过访问 arguments.length()
来获取到传入某个函数的参数的个数。
function abs() { if (arguments.length() == 0) return 0; else { var x = arguments[0]; return x >= 0 ? x : -x; } } abs(); // 0 abs(-2, 1); // 2
变量作用域与解构赋值
局部作用域、块级作用域
若在函数内部用 var
申明变量,则该变量的作用域是该函数内部,即这是一个局部变量。 在 JS 中允许函数的嵌套,即某个函数内可以定义另一个函数。同时允许内函数和外函数中定义重名的变量。 函数在查找变量时从自身函数定义开始,从内向外查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。
use strict; function f() { var x = 1; function g() { var x = 2; x; // x = 2 } x; // x = 1 }
在函数内部中用 var
申明一个变量,该变量会在整个函数中都起作用,不具有块级作用域。用 let
来申明则不会有这种问题,新申明的变量会具有块级作用域。
function f() { var sum = 0; for (var i = 0; i < 100; i++) sum += i; i++; // 仍然可以使用在上一个循环内定义的i } function f() { var sum = 0; for (let i = 0; i < 100; i++) sum += i; i++; // SyntaxError (与在c++中的逻辑一样) }
请严格遵守在函数内部首先申明所有变量这一规则!否则会出一些奇奇怪怪的错误。
全局作用域
不在任何函数内定义的变量就具有全局作用域。 JS 默认有一个全局对象window
,全局作用域的变量(变量、函数等)实际上被绑定到 window
的一个属性。
var x = 1; alert(x); // 1 alert(windows.x); // 1
解构赋值
在 JS 中可以使用解构赋值,直接对多个变量同时赋值:
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']]; x; // 'hello' y; // 'JavaScript' z; // 'ES6'
var person = { name: '小明', age: 20, gender: 'male', passport: 'G-12345678', school: 'No.4 middle school' }; let {name, passport : id} = person; // 把passport属性赋值给变量id: name; // '小明' id; // 'G-12345678' // 注意: passport不是变量,而是为了让变量id获得passport属性: passport; // Uncaught ReferenceError: passport is not defined
解构赋值在很多时候可以大大简化代码。例如,交换两个变量 x 和 y 的值,可以这么写,不再需要临时变量:
var x = 1, y = 2; [x, y] = [y, x]
快速获取当前页面的域名和路径:
var {hostname : domain, pathname : path} = location;
如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个 Date
对象:
function buildDate({year, month, day, hour = 0, minute = 0, second = 0}) { return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second); } buildDate({ year: 2017, month: 1, day: 1 }); // Sun Jan 01 2017 00:00:00 GMT+0800 (CST) // 传入的对象只需要year、month和day这三个属性
方法
可以给对象绑定函数。绑定到对象上的函数叫 方法 ,其在内部使用了 this
关键字。 在方法内部, this
始终指向当前对象。
var xiaoming = { name: '小明', birth: 1990, age: function () { var y = new Date().getFullYear(); return y - this.birth; } }; xiaoming.age; // function xiaoming.age() xiaoming.age(); // 今年调用是25,明年调用就变成26了
若不通过某个对象直接在函数里调用 this
,this
默认指向 windows
。在 strict
模式下,函数的 this
指向的是 undefined
,从而系统会报错提醒你这里的不规范写法。故要保证 this
指向正确,必须用 obj.xxx()
的形式调用,或者可以用一个变量首先捕获 this
。
'use strict'; var xiaoming = { name: '小明', birth: 1990, age: function () { var y = new Date().getFullYear(); return y - this.birth; } }; var fn = xiaoming.age; fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
'use strict'; var xiaoming = { name: '小明', birth: 1990, age: function () { var that = this; // 在方法内部一开始就捕获this function getAgeFromBirth() { var y = new Date().getFullYear(); return y - that.birth; // 用that而不是this } return getAgeFromBirth(); } }; xiaoming.age(); // 25
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 2025年广告第一单,试试这款永久免费的开源BI工具
· 为什么 .NET8线程池 容易引发线程饥饿
· 用 2025 年的工具,秒杀了 2022 年的题目。
· 场景题:假设有40亿QQ号,但只有1G内存,如何实现去重?
· 在 .NET 中使用 Tesseract 识别图片文字