一、基本概念
1、语法
ECMAScript 的语法大量借鉴了 C 及其他类 C 语言(如 Java 和 Perl)的语法。
- 区分大小写
- 标识符(标识符,就是指变量、函数、属性的名字,或者函数的参数)
- 注释
- 严格模式
- 语句
2、数据类型
ECMAScript 中有 5 种简单数据类型(也称为基本数据类型): Undefined 、 Null 、 Boolean 、 Number和 String 。还有 1种复杂数据类型—— Object , Object 本质上是由一组无序的名值对组成的。
- undefined类型
- null类型
- boolean类型
- number类型
- string类型
- object类型
其实还有后面ES6的symbol类型
3、操作符
ECMA-262 描述了一组用于操作数据值的操作符,包括算术操作符(如加号和减号)、位操作符、关系操作符和相等操作符。ECMAScript 操作符的与众不同之处在于,它们能够适用于很多值,例如字符串、数字值、布尔值,甚至对象。不过,在应用于对象时,相应的操作符通常都会调用对象的 valueOf()和(或) toString() 方法,以便取得可以操作的值。
- 一元操作符
- 位操作符
- 布尔操作符
- …
4、语句
ECMA-262 规定了一组语句(也称为流控制语句)。从本质上看,语句定义了 ECMAScript 中的主要语法,语句通常使用一或多个关键字来完成给定任务。语句可以很简单,例如通知函数退出;也可以比较复杂,例如指定重复执行某个命令的次数。
- if语句
- do-while语句
- while语句
- for语句
- for-in语句
- break语句和continue语句
- switch语句
- …
5、函数:
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。ECMAScript 中的函数使用 function 关键字来声明,后跟一组参数以及函数体。
函数的基本语法如下所示:
function functionName(arg0, arg1,...,argN) {
statements
}
ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过return 语句后跟要返回的值来实现返回值。
推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。
理解参数:
引用如下:
ECMAScript 函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不会有什么怨言。之所以会这样,原因是 ECMAScript 中的参数在内部是用一个数组来表示的。函数接收
到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过 arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数。
其实, arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是 arguments[0] ,第二个元素是 argumetns[1] ,以此类推),使用 length 属性来确定传递进来多少个参数。在前面的例子中, sayHi() 函数的第一个参数的名字叫
name ,而该参数的值也可以通过访问 arguments[0] 来获取。
注意:
关于参数还要记住最后一点:没有传递值的命名参数将自动被赋予 undefined 值。这就跟定义了变量但又没有初始化一样。
归结以上:
JavaScript 的核心语言特性在 ECMA-262 中是以名为 ECMAScript 的语言的形式来定义的。
也就是说,JavaScript 官方名称是 ECMAscript,而 ECMAscript 的标准是 ECMA-262
引用如下:
JavaScript 的核心语言特性在 ECMA-262 中是以名为 ECMAScript 的伪语言的形式来定义的。
ECMAScript 中包含了所有基本的语法、操作符、数据类型以及完成基本的计算任务所必需的对象,但
没有对取得输入和产生输出的机制作出规定。理解 ECMAScript 及其纷繁复杂的各种细节,是理解其在
Web 浏览器中的实现——JavaScript 的关键。目前大多数实现所遵循的都是 ECMA-262 第 3 版,但很多也已经着手开始实现第 5 版了。以下简要总结了 ECMAScript 中基本的要素。
ECMAScript 中的基本数据类型包括 Undefined 、 Null 、 Boolean 、 Number 和 String 。
与其他语言不同,ECMScript 没有为整数和浮点数值分别定义不同的数据类型, Number 类型可
用于表示所有数值。
ECMAScript 中也有一种复杂的数据类型,即 Object 类型,该类型是这门语言中所有对象的基
础类型。
严格模式为这门语言中容易出错的地方施加了限制。
ECMAScript 提供了很多与 C 及其他类 C 语言中相同的基本操作符,包括算术操作符、布尔操作
符、关系操作符、相等操作符及赋值操作符等。
ECMAScript 从其他语言中借鉴了很多流控制语句,例如 if 语句、 for 语句和 switch 语句等。
ECMAScript 中的函数与其他语言中的函数有诸多不同之处。
无须指定函数的返回值,因为任何 ECMAScript 函数都可以在任何时候返回任何值。
实际上,未指定返回值的函数返回的是一个特殊的 undefined 值。
ECMAScript 中也没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式
传递的。
可以向 ECMAScript 函数传递任意数量的参数,并且可以通过 arguments 对象来访问这些参数。
由于不存在函数签名的特性,ECMAScript 函数不能重载。
二、变量
ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。之前的 5 种基本数据类型: Undefined 、 Null 、 Boolean 、 Number 和 String 。这 5 种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。
1、变量值的复制:
1、如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制
到为新变量分配的位置上。
在此, num1 中保存的值是 5。当使用 num1 的值来初始化 num2 时, num2 中也保存了值 5。但 num2中的 5 与 num1 中的 5 是完全独立的,该值只是 num1 中 5 的一个副本。此后,这两个变量可以参与任何操作而不会相互影响。
2、当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到
为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一
个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另
一个变量
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "fqniu";
alert(obj2.name); //"fqniu"
首先,变量 obj1 保存了一个对象的新实例。然后,这个值被复制到了 obj2 中;换句话说, obj1
和 obj2 都指向同一个对象。这样,当为 obj1 添加 name 属性后,可以通过 obj2 来访问这个属性,
因为这两个变量引用的都是同一个对象。
2、传递参数:
ECMAScript 中所有函数的参数都是按值传递的。
function setName(obj) {
obj.name = "fqniu";
}
var person = new Object();
setName(person);
alert(person.name); //"fqniu"
以上代码中创建一个对象,并将其保存在了变量 person 中。然后,这个变量被传递到 setName()
函数中之后就被复制给了 obj 。在这个函数内部, obj 和 person 引用的是同一个对象。换句话说,即
使这个变量是按值传递的, obj 也会按引用来访问同一个对象。于是,当在函数内部为 obj 添加 name
属性后,函数外部的 person 也将有所反映;因为 person 指向的对象在堆内存中只有一个,而且是全
局对象。
function setName(obj) {
obj.name = "fqniu";
obj = new Object();
obj.name = "hello fqniu";
}
var person = new Object();
setName(person);
alert(person.name); //"fqniu"
这个例子与前一个例子的唯一区别,就是在 setName() 函数中添加了两行代码:一行代码为 obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的 name 属性。在把 person 传递给setName() 后,其 name 属性被设置为 “fqniu” 。然后,又将一个新对象赋给变量 obj ,同时将其 name属性设置为 “hello fqniu” 。
如果 person 是按引用传递的,那么 person 就会自动被修改为指向其 name 属性值为 “hello fqniu” 的新对象。但是,当接下来再访问 person.name 时,显示的值仍然是 “fqniu” 。
这说明即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写 obj 时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
可以这样理解:在函数里面的两个obj是两个不同的东西,算是互不影响
3、检测类型:
要检测一个变量是不是基本数据类型?用 typeof 操作符是最佳的工具。说得更具体一点, typeof 操作符是确定一个变量是字符串、数值、布尔值,还是 undefined 的最佳工具。如果变量的值是一个对象或 null ,则 typeof 操作符会返回 “object” 。
我们并不是想知道某个值是对象,而是想知道它是什么类型的对象。为此,ECMAScript提供instanceof 操作符,其语法如下所示:
result = variable instanceof constructor
根据规定,所有引用类型的值都是 Object 的实例。因此,在检测一个引用类型值和 Object 构造函数时, instanceof 操作符始终会返回 true 。当然,如果使用 instanceof 操作符检测基本类型的值,则该操作符始终会返回 false ,因为基本类型不是对象。
三、引用类型
- Object类型
创建 Object 实例的方式有两种。第一种是使用 new 操作符后跟 Object 构造函数,第二种方式是使用对象字面量表示法。对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程。
var person = new Object();
person.name = "fqniu";
person.age = 25;
var person = {
name : "fqniu",
age : 25
};
- Array类型
创建数组的基本方式有两种。第一种是使用 Array 构造函数,第二种基本方式是使用数组字面量表示法。数组字面量由一对包含数组项的方括号表示,多个数组项之间以逗号隔开
var colors = new Array();
var colors = new Array("red", "blue", "green");
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
数组方法很多,可以看之前的博客内容JavaScript数组、字符串回顾
- Date类型
创建一个日期对象,使用 new 操作符和 Date 构造函数
var now = new Date();
这里也不过多解释。。。
- RegExp类型
ECMAScript 通过 RegExp 类型来支持正则表达式。使用下面类似 Perl 的语法,就可以创建一个正
则表达式。
var expression = / pattern / flags ;
其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、
向前查找以及反向引用。每个正则表达式都可带有一或多个标志(flags),用以标明正则表达式的行为。
正则表达式的匹配模式支持下列 3 个标志。
g :表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即
停止;
i :表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m :表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模
式匹配的项。
因此,一个正则表达式就是一个模式与上述 3 个标志的组合体。不同组合产生不同结果
- Function类型
函数实际上是对象,每个函数都是 Function 类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是使用函数声明语法定义的。
function sum (num1, num2) {
return num1 + num2;
}
var sum = function(num1, num2){
return num1 + num2;
};
这里也不过多解释。。。
- 基本包装类型
- 1、Boolean类型( Boolean 对象在 ECMAScript 中的用处不大,不过多解释)
- 2、Number类型
Number 是与数字值对应的引用类型。要创建 Number 对象,可以在调用 Number 构造函数时向其中传递相应的数值。 - 3、String类型
String 类型是字符串的对象包装类型,可以像下面这样使用 String 构造函数来创建。
//2、Number类型
var numberObject = new Number(10);
//案例如下
var num = 10;
alert(num.toString()); //"10"
alert(num.toString(2)); //"1010"
alert(num.toString(8)); //"12"
alert(num.toString(10)); //"10"
alert(num.toString(16)); //"a"
//3、String类型
var stringObject = new String("hello world");
字符串方法很多,可以看之前的博客JavaScript数组、字符串回顾
- 单体内置对象
-
1、Global对象
Global (全局)对象可以说是 ECMAScript 中最特别的一个对象,所有在全局作用域中定义的属性和函数,都是 Global 对象的属性;诸如 isNaN() 、 isFinite() 、 parseInt() 以及 parseFloat() ,实际上全都是 Global对象的方法。除此之外, Global 对象还包含其他一些方法。
比如:- URI 编码方法(Global 对象的 encodeURI() 和 encodeURIComponent() 方法可以对 URI(Uniform ResourceIdentifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如空格。而这两个 URI 编码方法就可以对 URI 进行编码,它们用特殊的 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。)
- eval() 方法 ( 整个 ECMAScript语言中最强大的一个方法: eval() ,这个方法就像是一个完整的 ECMAScript 解析器,它只接受一个参数,即要执行的 ECMAScript (或 JavaScript)字符串。)
- window 对象(ECMAScript 虽然没有指出如何直接访问 Global 对象,但 Web 浏览器都是将这个全局对象作为window 对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了 window对象的属性。)
-
2、Math对象
ECMAScript 还为保存数学公式和信息提供了一个公共位置,即 Math 对象。与我们在 JavaScript 直接编写的计算功能相比, Math 对象提供的计算功能执行起来要快得多。 Math 对象中还提供了辅助完成这些计算的属性和方法,Math 对象还包含许多方法,用于辅助完成简单和复杂的数学计算。
比如:- Math.min() 和 Math.max() 方法
- Math.random() 方法返回大于等于 0 小于 1 的一个随机数
- Math.ceil() 执行向上舍入,即它总是将数值向上舍入为最接近的整数;
- Math.floor() 执行向下舍入,即它总是将数值向下舍入为最接近的整数;
- Math.round() 执行标准舍入,即它总是将数值四舍五入为最接近的整数
-
补充创建对象
//1、利用字面量 创建对象
var obj={
uname:'小白',
age:18,
sex:'男',
sayhi:function (){
console.log('hi');
}
}
console.log(obj.uname); //访问对象属性时使用的都是点表示法
console.log(obj['age']); //也可以使用方括号表示法来访问对象的属性
/*
从功能上看,这两种访问对象属性的方法没有任何区别。但方括号语法的主要优点是可以通过变量来访问属性,例如:
var propertyName = "uname";
console.log(person[propertyName]); //小白
如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法。例如:
person["first name"] = "小白";
由于 "first name" 中包含一个空格,所以不能使用点表示法来访问它。然而,属性名中是可以包含非字母非数字的,
这时候就可以使用方括号表示法来访问它们,通常,除非必须使用变量来访问属性,否则我们建议使用点表示法。
*/
obj.sayhi();
//2、利用new object 创建对象
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
};
return o;
}
var person1 = createPerson("张三疯", 99, "CEO");
var person2 = createPerson("张无忌", 37, "CFO");
console.log(person1);
console.log(person2);
//3、利用构造函数 创建对象
function Person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function(){
console.log(this.name);
};
}
var person3 = new Person("杨过", 29, "男");
var person4 = new Person("小龙女", 27, "女");
console.log(person3);
console.log(person4);
// 当作构造函数使用
var person = new Person("杨过", 29, "男");
person.sayName(); //杨过
// 作为普通函数调用
Person("小龙女", 27, "女"); // 添加到 window
window.sayName(); //小龙女
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "旺财", 25, "男");
o.sayName(); //旺财
/*
这个例子中的前两行代码展示了构造函数的典型用法,即使用 new 操作符来创建一个新对象。接下
来的两行代码展示了不使用 new 操作符调用 Person() 会出现什么结果:属性和方法都被添加给 window
对象了。当在全局作用域中调用一个函数时, this 对象总是指向 Global 对象(在浏览器中就是 window 对象)。
因此,在调用完函数之后,可以通过 window 对象来调用 sayName() 方法,并且还返回了 "小龙女" 。
最后,也可以使用 call() (或者 apply() )在某个特殊对象的作用域中 调用 Person() 函数。
这里是在对象 o 的作用域中调用的,因此调用后 o 就拥有了所有属性和 sayName()方法。
*/
构造函数注意点:
1、构造函数名字首字母必须大写;
2、构造函数不需要return 就可以结果
3、调用构造函数必须使用new
4、只要new XXX() 调用函数就创建一个对象 XXX
5、属性和方法前面必须加this
要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4个步骤:
1、构造函数可以在内存中创建一个空的对象
2、this会指向刚才的空对象
3、执行前面的构造函数里面的代码给这个空对象添加属性和方法
4、返回这个对象(构造函数里面不需要return)
以上大部分内容都是看书(Javascript高级程序设计)总结记录,仅用于个人学习!
继续更新中…