JavaScript
No.1 基本语法
-
JavaScript 是一种动态类型的弱类型语言,变量的类型在运行时可以被改变。
-
语句以分号结尾,表达式不需要。
-
变量提升:JavaScript 引擎在执行代码之前会先读取所有的变量声明,并将它们提升到作用域的顶部。提升方式是将声明与初始化分开,声明会被提升,初始化不会被提升。
if (true){ var a=0; console.log(a); } var a=1 console.log(a);上面的代码会输出 0 和 1,因为变量 a 被提升到了作用域的顶部。 等价于:
var a; if (true){ a=0; console.log(a); } a=1 console.log(a); -
var & let & const
- var:声明的变量会被提升到函数作用域的顶部或全局作用域的顶部,但不会被初始化。
- let:声明的变量不会被提升到作用域的顶部,而是在声明的位置初始化。
- const:声明的变量必须被初始化,且不能被修改,不会被提升到作用域的顶部。
-
switch 语句,比较使用的是全等操作符(===)
-
if,for,while,do-while,switch 语法与 C 语言类似。
No.2 数据类型
- 基本数据类型:Number、String、Boolean、Null、Undefined、Symbol
- 引用数据类型:Object、Array、Function
- typeof 运算符可以返回一个变量的数据类型:
typeof x - instanceof 运算符可以用来检测一个对象是否是一个类的实例:
object instanceof class
Null & Undefined & Boolean
-
null 是一个表示“空”的对象,转为数值时为 0;undefined 是一个表示”此处无定义”的原始值,转为数值时为 NaN。
-
下列运算符会返回布尔值:
前置逻辑运算符: ! (Not) 相等运算符:===,!==,==,!= 比较运算符:>,>=,<,<=如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为 false,其他值都视为 true(包括空数组、空对象、空字符串等):
undefined null false 0 NaN "" ''
Number
- JavaScript 只有一种数字类型,即 64 位双精度浮点数(IEEE 754 标准)。
- 数值范围:
Number.MAX_VALUE、Number.MIN_VALUE、Number.POSITIVE_INFINITY、Number.NEGATIVE_INFINITY、Number.NaN - NAN:
NaN是一个特殊的数值,表示“非数字”(Not-A-Number)。不等于任何值,包括它自己。 - 数值转换:
- parseInt():将字符串转为整数,非字符串会先转为字符串,遇到非数字字符会停止转换,返回已经转换的部分。接收第二个参数,表示字符串按照什么进制转换。
- parseFloat():将字符串转为浮点数
- isNaN():判断一个值是否为 NaN
String
- 字符串是一种不可变的数据类型,一旦创建,它们的值就不能被改变。
- 字符串的长度:
string.length
Object
-
对象可以理解为 python 中的字典,键值对的集合。
-
键名都是字符串,值可以是任意数据类型。
-
添加属性:
object.key = value -
删除属性:
delete object.key, 不能删除继承来的属性 -
对象间通过
=赋值时,只是复制了引用,两个对象指向同一个内存地址。 -
访问对象属性时,如果属性名是一个合法的变量名,可以直接用点运算符;否则用方括号:
object['key'] -
Object.keys():返回一个数组,包含对象自身的所有可枚举属性的键名。 -
key in object:判断对象是否包含某个属性,包括继承的属性。 -
for…in 循环有两个使用注意点。
- 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
- 它不仅遍历对象自身的属性,还遍历继承的属性。
- 如果只想遍历对象自身的属性,不包括继承的属性,可以使用
Object.keys()方法代替。或者使用object.hasOwnProperty(key)方法判断一个属性是对象自身的属性,还是继承的属性。
-
with 语句:将代码的作用域设置到一个特定的对象中,可以不用重复引用对象名。
var obj = {p: 1}; with (obj) { p = 2; }with 不修改作用域链,所以在 with 代码块中定义的变量,还是在原来的作用域中。
Function
-
function 声明:
function name(parameters) { code } -
函数表达式:
var name = function(parameters) { code } -
函数声明提升:函数声明会被提升到作用域的顶部,可以在声明之前调用。
-
使用 function 关键字声明的函数会被提升到作用域的顶部,而使用函数表达式声明的函数不会被提升。
-
函数的属性与方法:
name:函数的名称length:函数的参数个数toString():返回函数的源代码apply():调用函数,传递一个包含多个参数的数组call():调用函数,传递一个参数列表bind():创建一个新函数,绑定 this 对象,传递一个参数列表arguments:函数内部的一个局部变量,包含调用函数时传递的参数列表
-
作用域:JavaScript 只有两种作用域:全局作用域和函数作用域。
- 全局作用域:在函数外部声明的变量,拥有全局作用域,可以在代码的任何地方被访问。
- 函数作用域:在函数内部声明的变量,拥有函数作用域,可以在函数内部的任何地方被访问。
-
参数传递:
- 基本数据类型:传递的是值的副本,不会影响原始值。
- 引用数据类型:传递的是对象地址,会改变原始值。
var obj = [1, 2, 3]; function f(o) { o = [2, 3, 4]; } f(obj); console.log(obj); // [1, 2, 3] -
arguments 对象:包含函数调用时传递给函数的参数列表。
arguments.length:参数的个数arguments[0]:第一个参数arguments.callee:指向当前正在执行的函数- 将 arguments 对象转为数组:
var args = Array.prototype.slice.call(arguments)
-
闭包:java 使用链式作用域,即函数可以访问其外部作用域的变量,但是外部作用域不能访问函数内部的变量。即使其外部作用域被销毁,函数依然可以访问外部作用域的变量。
function f() { var n = 999; function g() { console.log(n); } return g; } var result = f(); result(); // 999闭包的作用:1. 读取函数内部的变量;2. 让这些变量的值始终保持在内存中。
function createIncrementor(start) { return function() { return start++; }; } var inc = createIncrementor(5); console.log(inc()); // 5 console.log(inc()); // 6inc 的存在依赖于 createIncrementor,所以 start 的值始终保持在内存中。
-
闭包可以用于封装私有变量。
function Person(name) { var _name = name; function getName() { return _name; } return getName; } var p = Person('Tom'); console.log(p.getName()); // Tom -
IIFE:立即调用的函数表达式(Immediately-Invoked Function Expression)。
(function() { console.log('Hello World'); })();IIFE 的作用:1. 不必为函数命名,避免污染全局变量;2. 立即执行,不必调用。
Array
-
数组是一种特殊的对象,用来表示和操作一组数据。任何数据类型都可以放入数组。
-
其键名是从 0 开始的整数,会被自动转为字符串。所以可以通过字符 0 访问第一个元素。
-
length 属性:
- 会自动更新,值为最大整数属性名加 1,不一定等于数组的元素个数。
- 可以手动设置,会删除大于等于 length 的键名。
- 数组可以添加非整数键名,但不会计算在 length 属性中。
-
in 运算符:判断一个键名是否存在于数组中,包括继承的键名。
-
for…in 循环:会便利所有的键名,包括非整数键名和继承的键名。
-
空位 & undefined:数组的空位不是 undefined,而是没有任何值。forEach 方法会跳过空位,但不会跳过 undefined。
-
forEach():对数组的每个元素执行一次提供的函数。
var arr = [1, 2, 3]; arr.forEach(function (value, index, array) { console.log(value, index, array); }); -
map():对数组的每个元素执行一次提供的函数,返回一个新数组。
var arr = [1, 2, 3]; var arr2 = arr.map(function (value, index, array) { return value * 2; }); console.log(arr2); // [2, 4, 6] -
filter():对数组的每个元素执行一次提供的函数,返回一个新数组,只包含返回值为 true 的元素。
var arr = [1, 2, 3]; var arr2 = arr.filter(function (value, index, array) { return value > 1; }); console.log(arr2); // [2, 3] -
reduce():对数组的每个元素执行一次提供的函数,返回一个累计值。
var arr = [1, 2, 3]; var sum = arr.reduce(function (prev, cur, index, array) { return prev + cur; }); console.log(sum); // 6 -
some():对数组的每个元素执行一次提供的函数,只要有一个返回值为 true,就返回 true。
var arr = [1, 2, 3]; var result = arr.some(function (value, index, array) { return value > 2; }); console.log(result); // true
No.3 异步
-
JavaScript 是单线程的,同一时间只能做一件事。
-
异步编程:通过回调函数、事件监听、Promise 等方式实现异步编程。
-
回调函数:将函数作为参数传递给另一个函数,等到另一个函数执行完毕后再执行回调函数。
function f(callback) { //code callback(); } f(function() { console.log('Hello World'); }); -
事件监听:通过事件监听函数,当事件发生时执行回调函数。
f1.on('done', f2); function f1() { setTimeout(function () { f1.trigger('done'); }, 1000); } function f2() { console.log('Hello World'); } -
发布/订阅模式:发布者发布事件,订阅者订阅事件,当事件发生时执行回调函数。
Jquery.subscribe('done', f2); function f1() { setTimeout(function () { Jquery.publish('done'); }, 1000); }