// This is an in-line comment.
/* This is a
multi-line comment */
如果你有大量的 JavaScript 代码,我们可以将它放入一个单独的文件。
脚本文件可以通过 src
特性(attribute)添加到 HTML 文件中。我们可以使用一个 标签将 JavaScript 代码添加到页面中。
type
和 language
特性(attribute)不是必需的。
<script src="/path/to/script.js"></script>
要附加多个脚本,请使用多个标签:
<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>
…
如果设置了 src 特性,script 标签内容将会被忽略。
一个单独的 标签不能同时有 src 特性和内部包裹的代码。
这将不会工作:
<script src="file.js">
alert(1); // 此内容会被忽略,因为设定了 src
</script>
我们必须进行选择,要么使用外部的 ,要么使用正常包裹代码的
。
为了让上面的例子工作,我们可以将它分成两个
<script src="file.js"></script>
<script>
alert(1);
</script>
确保 “use strict” 出现在最顶部
请确保 “use strict” 出现在脚本的最顶部,否则严格模式可能无法启用。
这里的严格模式就没有被启用:
alert("some code");
// 下面的 "use strict" 会被忽略,必须在最顶部。
"use strict";
// 严格模式没有被激活
只有注释可以出现在 “use strict” 的上面。
没有办法取消 use strict
没有类似于 “no use strict” 这样的指令可以使程序返回默认模式。一旦进入了严格模式,就没有回头路了。当你使用开发者控制台运行代码时,请注意它默认是不启动 use strict 的。现代 JavaScript 支持 “classes” 和 “modules”,它们会自动启用 use strict。因此,如果我们使用它们,则无需添加 “use strict” 指令。
JavaScript 提供七种不同的数据类型,它们是 undefined
(未定义)、null
(空)、boolean
(布尔型)、string
(字符串)、symbol
、number
(数字)、bigint
(可以表示任意大的整数)和object
(对象)。
值类型(基本类型):
引用数据类型:
Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
在 JavaScript 中创建变量通常称为"声明"变量。
我们使用 var 关键词来声明变量:
var carname;
您可以在一条语句中声明很多变量。该语句以 var 开头,并使用逗号分隔变量即可:
var lastname="Doe", age=30, job="carpenter";
声明也可横跨多行:
var lastname="Doe",
age=30,
job="carpenter";
一条语句中声明的多个变量不可以同时赋同一个值:
var x,y,z=1;
x,y 为 undefined, z 为 1。
一般,我们需要在使用一个变量前定义它。但是在早期,我们可以不使用 let 进行变量声明,而可以简单地通过赋值来创建一个变量。现在如果我们不在脚本中使用 use strict 声明启用严格模式,这仍然可以正常工作,这是为了保持对旧脚本的兼容。
// 注意:这个例子中没有 "use strict"
num = 5; // 如果变量 "num" 不存在,就会被创建
alert(num); // 5
上面这是个糟糕的做法,严格模式下会报错。
"use strict";
num = 5; // 错误:num 未定义
使用 const 声明的变量称为“常量”。它们不能被修改,如果你尝试修改就会发现报错:
const myBirthday = '18.04.1982';
myBirthday = '01.01.2001'; // 错误,不能对常量重新赋值
使用大写字母和下划线来命名这些常量。
在编程语言中,一般固定值称为字面量
数字(Number)字面量 可以是整数或者是小数 3.14
字符串(String)字面量 可以使用单引号或双引号 “John Doe”,在 JavaScript 中,字符串(String)的值是不可变的(immutable),这意味着一旦字符串被创建就不能被改变。
数组(Array)字面量 定义一个数组 [40, 100, 1, 5, 25, 10]
对象(Object)字面量 定义一个对象 {firstName:“John”, lastName:“Doe”, age:50, eyeColor:“blue”}
函数(Function)字面量 定义一个函数:function myFunction(a, b) { return a * b;}
大多数情况下,运算符和函数会自动将赋予它们的值转换为正确的类型。比如,alert 会自动将任何值都转换为字符串以进行显示。算术运算符会将值转换为数字。
当我们需要一个字符串形式的值时,就会进行字符串转换。比如,alert(value) 将 value 转换为字符串类型,然后显示这个值。我们也可以显式地调用 String(value) 来将 value 转换为字符串类型:
在算术函数和表达式中,会自动进行 number 类型转换。比如,当把除法 / 用于非 number 类型:
alert( "6" / "2" ); // 3, string 类型的值被自动转换成 number 类型后进行计算
undefined 变成NaN
null变成 0
true / false ->1 / 0
string ->“按原样读取”字符串,两端的空白会被忽略。空字符串变成 0。转换出错则输出 NaN。
直观上为“空”的值(如 0、空字符串、null、undefined 和 NaN)将变为 false。
其他值变成 true。
0, null, undefined, NaN, “” ->false
其他值 ->true
我们可以将任何类型的值存入变量。例如,一个变量可以在前一刻是个字符串,下一刻就存储一个数字:
// 没有错误
let message = "hello";
message = 123456;
允许这种操作的编程语言,例如 JavaScript,被称为“动态类型”(dynamically typed)的编程语言,意思是虽然编程语言中有不同的数据类型,但是你定义的变量并不会在定义后,被限制为某一数据类型。
number 类型代表整数和浮点数。数字可以有很多操作,比如,乘法 *、除法 /、加法 +、减法 - 等等。除了常规的数字,还包括所谓的“特殊数值(“special numeric values”)”也属于这种类型:Infinity
、-Infinity
和 NaN
。
Infinity
代表数学概念中的 无穷大 ∞。是一个比任何数字都大的特殊值。我们可以通过除以 0 来得到它:
alert( 1 / 0 ); // Infinity
或者在代码中直接使用它:
alert( Infinity ); // Infinity
NaN
代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果,比如:
alert( "not a number" / 2 ); // NaN,这样的除法是错误的
NaN 是粘性的。任何对 NaN 的进一步操作都会返回 NaN:
alert( "not a number" / 2 + 5 ); // NaN
所以,如果在数学表达式中有一个 NaN,会被传播到最终结果。
数学运算是安全的,在 JavaScript 中做数学运算是安全的。我们可以做任何事:除以 0,将非数字字符串视为数字,等等。脚本永远不会因为一个致命的错误(“死亡”)而停止。最坏的情况下,我们会得到 NaN 的结果。
在 JavaScript 中,“number” 类型无法表示大于 (2的53次方-1)(即 9007199254740991),或小于 -(2的53次方-1) 的整数。这是其内部表示形式导致的技术限制。在大多数情况下,这个范围就足够了,但有时我们需要很大的数字,例如用于加密或微秒精度的时间戳。
BigInt 类型是最近被添加到 JavaScript 语言中的,用于表示任意长度的整数。可以通过将 n
附加到整数字段的末尾来创建 BigInt 值。
// 尾部的 "n" 表示这是一个 BigInt 类型
const bigInt = 1234567890123456789012345678901234567890n;
JavaScript 中的字符串必须被括在引号里。
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;
在 JavaScript 中,有三种包含字符串的方式。
- 双引号:"Hello".
- 单引号:'Hello'.
- 反引号:`Hello`.
双引号和单引号都是“简单”引用,在 JavaScript 中两者几乎没有什么差别。
反引号是 功能扩展 引号。它们允许我们通过将变量和表达式包装在 ${…}
中,来将它们嵌入到字符串中例如:
let name = "John";
// 嵌入一个变量
alert( `Hello, ${name}!` ); // Hello, John!
// 嵌入一个表达式
alert( `the result is ${1 + 2}` ); // the result is 3
${…}
内的表达式会被计算,计算结果会成为字符串的一部分。可以在 ${…}
内放置任何东西:诸如名为 name 的变量,或者诸如 1 + 2 的算数表达式,或者其他一些更复杂的。
需要注意的是,这仅仅在反引号内有效,其他引号不允许这种嵌入。
boolean 类型仅包含两个值:true 和 false。
这种类型通常用于存储表示 yes 或 no 的值:true 意味着 “yes,正确”,false 意味着 “no,不正确”。
特殊的 null 值不属于上述任何一种类型。
它构成了一个独立的类型,只包含 null 值:
let age = null;
相比较于其他编程语言,JavaScript 中的 null 不是一个“对不存在的 object 的引用”或者 “null 指针”。
JavaScript 中的 null 仅仅是一个代表“无”、“空”或“值未知”的特殊值。上面的代码表示 age 是未知的。
特殊值 undefined 和 null 一样自成类型。undefined 的含义是 未被赋值。
如果一个变量已被声明,但未被赋值,那么它的值就是 undefined:
let age;
alert(age); // 弹出 "undefined"
通常,使用 null 将一个“空”或者“未知”的值写入变量中,而 undefined 则保留作为未进行初始化的事物的默认初始值。
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式
JS 中创建数组有两种方式:
var myCars=new Array();
myCars[0]="Saab";
myCars[1]="Volvo";
myCars[2]="BMW";
var myCars=new Array("Saab","Volvo","BMW");
var myCars=["Saab","Volvo","BMW"];
通过指定数组名以及索引号码,可以访问某个特定的元素。
访问myCars数组的第一个值:
var name=myCars[0];
如果 var firstName = "Ada"
中,那么你可以通过 firstName[firstName.length - 1]
来得到字符串的最后的一个字符
可以通过修改 length 长度来实现数组扩容的目的。 length 属性是可读写的
var arr = ['red', 'green', 'blue', 'pink'];
arr.length = 7;
可以通过修改数组索引的方式追加数组元素,不能直接给数组名赋值,否则会覆盖掉以前的数据
var arr = ['red', 'green', 'blue', 'pink'];
arr[4] = 'hotpink';
这种方式也是我们最常用的一种方式。
.push() 接受一个或多个参数(parameters),并把它压入到数组的末尾。
var arr1 = [1,2,3];
arr1.push(4);
var arr2 = ["Stimpson", "J", "cat"];
arr2.push(["happy", "joy"]);
arr1
现在值为 [1, 2, 3, 4]
,arr2
值为 ["Stimpson", "J", "cat", ["happy", "joy"]]
。
.pop() 函数用来弹出一个数组末尾的值。 我们可以把这个弹出的值赋给一个变量存储起来。 换句话说就是 .pop() 函数移除数组末尾的元素并返回这个元素。
数组中任何类型的元素(数值,字符串,甚至是数组)都可以被弹出来 。
var threeArr = [1, 4, 6];
var oneDown = threeArr.pop();
console.log(oneDown);
console.log(threeArr);
第一个 console.log 将显示值 6,第二个将显示值 [1, 4]。
shift()移除的是第一个元素
var ourArray = ["Stimpson", "J", ["cat"]];
var removedFromOurArray = ourArray.shift();
removedFromOurArray 值为 Stimpson,ourArray 值为 [“J”, [“cat”]]
unshift() 在数组的头部添加元素
var ourArray = ["Stimpson", "J", "cat"];
ourArray.shift();
ourArray.unshift("Happy");
在 shift、ourArray 后值为 [“J”, “cat”]。 在 unshift、ourArray 后值为 [“Happy”, “J”, “cat”]。
JavaScript 使用关键字 function 定义函数。函数可以通过声明定义,也可以是一个表达式。函数在使用时分为两步:声明函数和调用函数
function functionName(parameters) {
执行的代码
}
分号是用来分隔可执行JavaScript语句。由于函数声明不是一个可执行语句,所以不以分号结束。
JavaScript 函数可以通过一个表达式定义。函数表达式可以存储在变量中:
var x = function (a, b) {return a * b};
在函数表达式存储在变量后,变量也可作为一个函数使用:
var x = function (a, b) {return a * b};
var z = x(4, 3);
以上函数实际上是一个 匿名函数 (函数没有名称)。函数存储在变量中,不需要函数名称,通常通过变量名来调用。上述函数以分号结尾,因为它是一个执行语句。
函数声明后不会立即执行,会在我们需要的时候调用到。
声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码
// 调用函数
函数名(); // 通过调用函数名来执行函数体代码
函数同样可以通过内置的 JavaScript 函数构造器(Function())定义。
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
实际上,不必使用构造函数。上面实例可以写成:
var myFunction = function (a, b) {return a * b};
var x = myFunction(4, 3);
JavaScript(es6前)中的作用域有两种:
在 JavaScript 中,作用域涉及到变量的作用范围。 在函数外定义的变量具有全局作用域。 这意味着,具有全局作用域的变量可以在代码的任何地方被调用。这些没有使用 var 关键字定义的变量,会被自动创建在 global 作用域中,形成全局变量。
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
在一个函数内声明的变量,以及该函数的参数都具有局部(local)作用域。 这意味着它们只在该函数内可见
function myTest() {
var loc = "foo";
console.log(loc);
}
myTest();
console.log(loc);
myTest() 函数调用将在控制台中显示字符串 foo。 console.log(loc) 行会产生一个错误,因为 loc 没有定义在函数之外
一个程序中有可能具有相同名称的局部变量 和全局变量。 在这种情况下,局部变量将会优先于全局变量。
var someVar = "Hat";
function myFun() {
var someVar = "Head";
return someVar;
}
函数 myFun 将会返回字符串 Head,因为局部变量的优先级更高。
== 作用域链:采取就近原则的方式来查找变量最终的值==
function f1() {
var num = 123;
function f2() {
console.log( num );
}
f2();
}
var num = 456;
f1();
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); console.log(typeof(a));
console.log(b);console.log(typeof(b));
}
}
}
fn1();
JavaScript 函数有个内置的对象 arguments 对象。argument 对象包含了函数调用的参数数组。
x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
var i, sum = 0;
for (i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:
预解析只会发生在通过 var 定义的变量和 function 上。学习预解析能够让我们知道为什么在变量声明之前访问变量的值是 undefined,为什么在函数声明之前就可以调用函数。
预解析也叫做变量、函数提升。
变量提升: 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
console.log(num);
var num = 10;
函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn();
function fn() {
console.log('打印');
}
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
var num = 10;
function fn(){
console.log(num);
var num = 20;
console.log(num);
}
fn();
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
JavaScript的运算符按运算符类型可以分为以下5种:
(1)算术运算符;
(2)比较运算符;
(3)赋值运算符;
(4)逻辑运算符;
(5)条件运算符;
typeof运算符用于返回它的操作数当前所容纳的数据的类型,这对于判断一个变量是否已被定义特别有用。
它支持两种语法形式:
换言之,有括号和没有括号,得到的结果是一样的。对 typeof x 的调用会以字符串的形式返回数据类型:
例如:
typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof Math // "object" (1)
typeof null // "object" (2)
typeof alert // "function" (3)
JavaScript 中的所有事物都是对象:字符串、数值、数组、函数…此外,JavaScript 允许自定义对象。
JavaScript 提供多个内建对象,比如 String、Date、Array 等等。 对象只是带有属性和方法的特殊数据类型。
在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object):
在 JavaScript 中,几乎所有的对象都是 Object 类型的实例,它们都会从 Object.prototype
继承属性和方法。Object 构造函数创建一个对象包装器。
Object 构造函数,会根据给定的参数创建对象,具体有以下情况:
new Object([value])
person=new Object();
person.firstname="John";
person.lastname="Doe";
person.age=50;
person.eyecolor="blue";
对象字面量:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法。{ } 里面采取键值对的形式表示
{ name1 : value1, name2 : value2,...nameN : valueN }
var star = {
name : 'jack',
age : 18,
sex : '男',
sayHi : function(){
console.log('大家好啊~');
}
};
console.log(star.name)
console.log(star['name'])
star.sayHi();
构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在 js 中,使用构造函数要时要注意以下两点:
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function() {
alert('我的名字叫:' + this.name + ',年龄:' + this.age + ',性别:' + this.sex);
}
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);
注意
new 在执行时会做四件事情:
for…in 语句用于对数组或者对象的属性进行循环操作
for (var k in obj) {
console.log(k); // 这里的 k 是属性名
console.log(obj[k]); // 这里的 obj[k] 是属性值
}
objectName.propertyName
person.lastName;
objectName["propertyName"]
person["lastName"];
objectName.methodName()
name = person.fullName();
如果不使用 () 访问 fullName 方法,则将返回函数定义:
// 创建对象:
var person = {
firstName: "Bill",
lastName : "Gates",
id : 12345,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
// 显示对象中的数据:
document.getElementById("demo").innerHTML = person.fullName;
document.getElementById("demo").innerHTML = person.fullName();
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象,内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法),内置对象最大的优点就是帮助我们快速开发。 JavaScript 提供了多个内置对象:Math、 Date 、Array、String等。
String(字符串)对象
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
(1)值类型(简单数据类型): string ,number,boolean,undefined,null
值类型变量的数据直接存放在变量(栈空间)中
(2)引用类型(复杂数据类型):通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等
引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中