越学Django和Web开发,越觉得JS非常重要,前后端交互不懂JS基本没法往下继续写。在用Django学习写博客项目的同时,回头来把JS的内容补一补,之后再考虑补一下CSS或者HTML的canvas相关内容。

在HTML中使用JavaScript

在HTML中使用JS全部需要通过<SCRIPT>标签。

SCRIPT有如下6个属性:

  1. async 异步加载,只对外部脚本文件有效。一定会在页面的load事件前执行,但可能在DOMContentLoaded之前或之后运行。
  2. charset 为UTF-8,一般不用
  3. defer 表示延迟到文档解析后再执行,规范里先于DOMContentLoaded事件运行,但实际效果不可控,因此最好只包含一个defer或者不要包含defer属性。也只能用于外部脚本。
  4. language 不使用
  5. src 外部脚本文件地址
  6. type 一般用 text/javascript即可

一般把Script标签放到body标签内部的末尾。

<noscript>标签,只有在浏览器禁用JS的时候才会显示的标签。

文档模式

即文件开始的声明,现在已经不用过多考虑浏览器的混杂模式和标准模式,统一用<!DOCTYPE html>来声明即可.

 

ECMA基础语法

标识符

第一个字母必须是字母,下划线或者美元符号,其他字符可以是字母,下划线,美元符号或数字。标识符按惯例采取驼峰大小写格式(python采取下划线连接方式,类名采取大写)

注释

单行注释以 // 开始,多行注释为 : /*   */

严格模式

在JS文件的开始写上"use strict";表示严格模式。如果文件内未定义,在函数体的第一行也可以写上该句话表示该函数采用严格模式。

语句结尾如果没有分号,将由解释器决定在哪里添加分号,可能会造成错误,推荐始终加上分号。

可以使用C风格的语法用{}来括起一个代码块。在控制语句中,推荐始终采用代码块的形式,即使控制语句只有一条语句。

ECMA 的保留字和关键字 不要用作标识符。

变量

变量在定义的时候一定要用关键字 var 或者 let,还有const 用于定义常量。

如果省略了var 和 let, 不管变量定义在哪里,这个变量都会成为全局变量,不推荐如此操作。

var 和 let 的区别看 深入浅出ES6的解说。在日后使用JS的时候,如无意外,应该使用let 关键字赋值变量,不要特意去使用var的一些特性,否则会造成很多问题。

数据类型

五种简单数据类型(也称为基本数据类型):

  1. Undefined
  2. Null
  3. Boolean
  4. Number
  5. String

还有1种复杂数据类型–Object,Object本质是一组键值对。

想要知道数据的类型,可以使用typeof 操作符。特别注意的是,null的类型是Object,函数的类型是function。

Undefined类型

Undefined类型只有一个值,就是undefined,表示变量尚未被初始化。

只要记住一点,即不要使用未声明的变量。如果声明了变量不想立刻使用,可以给变量先赋值为null。

Null类型

也只有一个值,是null。意义上来说表示一个空的对象指针。

undefined派生自null,所以二者进行相等测试会返回true,但全等测试会返回false,因为不属于相同的类型。

Boolean类型

布尔值,只有两个值true 和 false,注意不要像C语言一样认为其是特殊的INT类型。

可以用内置函数boolean()来将其他类型的数据转换成布尔值。注意记忆转换成false的值:空字符串,0,NaN,null,undefined。

Number类型

Number类型用IEEE754双精度浮点数表示数字。可以用十进制,八进制(000),十六进制(0x开头)来表示,严格模式下八进制无效。

由于IEEE754标准存在浮点误差,所以不要判断浮点数的结果。

数值范围可以用Number.MIN_VALUENumber.MAX_VALUE获得,如果超出,会得到一个特殊的Infinity值,无法参加下一次运算。判断一个结果是否在有效范围内,可以使用内置的isFinite()函数。

NaN表示非数值,用于本来该得到数值结果但却没有得到的情况,比如0做除数(其实0除以0才会得到NaN,正数除以0得到Infinity,负数除以0得到-Infinity)。JS这样就不会像其他语言一样引发错误。NaN参加的运算,结果还是NaN。NaN与NaN不管是全等还是相等判断, 一定都返回false。用内置的isNaN()方法可以判断一个值是否可以转换成数值。

数值转换有Number()parseInt()parseFloat。常用后面两种将字符串转换成整数或者浮点数。其中parseInt()还可以指定第二个参数作为基底来转换不同进制的数字。

String类型

JS的字符串都是Unicode字符串。

字符串像其他语言一样,内部有特殊的字符字面量,也叫转义序列。转义符号为”\”。常用的有\n \r \t \b \\ \xnn \unnnn

字符串转换,可以调用对象的toString()方法。数值,布尔值,对象和字符串值都有该方法。null 和 undefined 类型没有。数值的该方法可以加一个参数表示基底。

原生JS没有字符串格式化方法,拼接字符串的话必须手动进行。

Object类型

类似于对象和实例的关系。所有的object类型的数值 ,都是object的一个实例。可以用var o = new Object()来得到一个新对象。

在浏览器里创建后可以看到有一系列属性和方法:

  1. constructor  构造函数,保存着建立该实例的函数,这个例子里也就是Object()
  2. hasOwnProperty(propertyName)  检查当前对象是否有某个属性
  3. isPrototypeOf(object)  检查传入对象是否是传入对象的原型
  4. propertyIsEnumerable(propertyName)  检查属性是否可以用for-in 迭代
  5. toLocaleString()  返回对象的字符串表示,与地区对应
  6. toString()  返回对象的字符串表示
  7. valueOf()  返回对象的字符串、数值或者布尔值表示,一般与toString()返回的结果一样

由于JS和Python一样,一切皆对象,对象会到JS的对象部分再来讨论。

操作符

操作符种类 操作符 解释
一元操作符 ++ 自增1,放在变量前,在表达式求值之前就自增,放在变量后,表达式求值之后再自增
自减1,放在变量前,在表达式求值之前就自增,放在变量后,表达式求值之后再自增
+ 对数值无影响,对非数值应用会自动转换类型
将数值取反,对非数值应用会自动转换类型
位运算符 ~ 按位取反
& 两个数值按位与
| 两个数字按位或
^ 两个数字按位异或
<< 二进制左移n位,用0填补右侧空白
>> 二进制右移,有符号右移,用符号位填充左侧空白
>>> 二进制右移,无符号右移,始终以0填充左侧空位
布尔操作符 ! 逻辑非,表示NOT,可以应用于任何数据类型,注意哪些值相当于false
&& 逻辑与,两个操作数的AND。带有短路操作,第一个操作数为false的时候就不再对第二个操作数求值。
|| 逻辑或,带有短路操作,第一个为true的时候不再对第二个操作数求值,常用来赋值。
乘性操作符 * 计算乘积
/ 除法操作符
% 求余或者叫取模
加性操作符 + 相加数值,如果操作的内容中至少一个是字符串,就转换另外一个为字符串然后拼接
减法,如果一个操作数是字符串,就会转换成数字再相减
关系运算符 < > <= >= 比较数值,如果两个操作数都是字符串,比较字符编码;如果一个是数值一个是字符串,转换字符串为数值再比较
相等操作符 == 相等,会自动转换类型供比较,实践中不要使用
!= 不相等,会自动转换类型比较,实践中不要使用
=== 全等操作符,既比较值也比较数据类型,实践中推荐使用
!== 不全等操作符,实践中推荐使用
条件操作符 var = expression ? val_true : val_false 三元运算符,来自C语言,表达式为true则赋值val_true,否则val_false
赋值操作符 = 除了基础赋值,还可以和乘性,加性和位操作符组合成复核赋值。
逗号操作符 , 用于一条语句中执行多个操作,如果用于单一赋值,会返回表达式中的最后一项。

 

语句

if 语句

if (condition) {statement} else if (condition2) {statment} else {statment}

  • condition可以是任何表达式,会自动转换成布尔值
  • 始终以花括号括住执行语句,不管有几行,养成良好编程习惯
  • 返回HttpResponse,则交给当前中间件的process_response处理,开始向上返回

do-while 语句

do {statment} while (expression)

  • 用do-while 完成的语句,也都可以用while语句完成。
  • 始终用花括号括住语句

while 语句

while (expression) {statement}

  • 先测试表达式,再执行语句
  • 始终用花括号括住语句

for 语句

for (initial; expression; post-loop-expression ) {statement}

  • initial部分用let 定义变量,用var则变量在循环完成后会泄露
  • 省略所有括号内容则是无限循环
  • 始终用花括号括住语句

for in 语句

for (var in expression ) {statement}

  • 这个方法用来遍历一个对象的属性,有点类似于Python里的dir和自省
  • 对象属性未必有顺序。

label 语句

label_name : {statement}

  • 给一段语句加上标签,用于跳转到这里
  • 实践中避免使用该语句,类似于GOTO,会导致程序结构混乱

break 和 continue 语句

  • break用于结束当前循环,如果嵌套循环,只会结束break所在的循环
  • continue用于继续跳过当前到循环体结束的语句,继续执行下一次循环

with 语句

with(expression){statement}

  • 将一个对象用于代码块内部的上下文变量
  • 实践中不要使用。严格模式下根本无法使用with语句

switch 语句

switch(expression) {case value: {statment}; break;}

  • 多重分支语句,注意break,该加的时候要加,某几种情况对应一个操作的时候不要加,但最好注明。
  • switch的表达式可以是各种数据类型,case的值不一定是常量,也可以是表达式求值的结果
  • switch在比较值的时候采用的是全等操作,所以要注意数据类型的匹配

函数

function func_name(args){func body}

  • 函数是一等对象,也可以传递。
  • 函数调用用函数名()。
  • 编程时要么所有函数都使用return,要么都不返回值,风格要统一。
  • JS的函数没有函数签名,参数通过AO对象进行收集,可以传入任意参数而不会引发错误,只是函数得不到想要的结果而已。
  • 在函数内部可以用内置arguments来做访问参数数组。
  • 利用可以传入任意参数的特性,可以编写类似于重载的功能,但不要过多依赖于该特性。