JavaScript学习笔记——基础部分
变量、数据类型与运算符
1.下面两种赋值顺序的结果是不同的
var x = "8" + 3 + 5; // x = “835”
var y = 3 + 5 + "8"; // y = “88”
2.在 JavaScript 中,从前端页面获得的值都是字符串类型
3.==与===分别为相等和严格相等。三等号要求数据类型和值都相等,双等号只需要值相等即可,相等包含严格相等。
比较过程上,严格相等先比较两个对象的数据类型是否相等,不相等则结束比较,返回 false ,相等在数据类型不同时,尝试进行数据类型转换。
而相等与严格相等仅适用于非对象类型。对于对象类型,相等或者严格相等比较的都是对象的引用,而不是具体的值,就是说,一个对象和其他任何对象都是不相等的,即使两者属性、值都相等。
对象的比较中,只有经过对象赋值后这两个对象才相等,因为它们指向同一块存储地址。
4.将值设置为null以清空对象,但这之后,这个对象的类型仍然是对象。
类似地,也可以通过undefined来清空对象,这之后,这个对象的类型也是undefined.
- undefined与null的值相等,但类型不相等。也就是:
- (undefined === null) = false
- (undefined == null) = true
- 数字与undefined和null的运算结果不同
- console.log(11 + null); // 11
- console.log(11 + undefined); // NaN
5.函数名引用的是函数对象;函数名与括号的组合引用的是函数结果。
访问没有括号的函数将返回函数的定义。
6.“声明提前”现象:在函数内部,变量不论在何处声明,都应该看成是在最开始声明,但赋值不会看成是在最开始赋值。
7.JavaScript允许重复变量的声明,且采用声明覆盖的方式,即实参个数如果比形参少,那么剩下的默认赋值为 undefined,如果实参传的比形参数量多,那么是全部都会被传进去的,只不过没有对应的形参可以引用(但可以用 arguments 来获取剩下的参数)。
function test(arg1) {
for(var i=0; i<arguments.length; i++) {
console.log(arguments[i]);
}
}
test(1,2); //输出 1 2
8.变量与函数重名时,变量生效。
9.JavaScript的预解析:
- 函数与变量在声明时都会被置顶,但函数更先被声明,且不会被变量声明覆盖,但是会被变量赋值覆盖。
- 变量的声明与赋值写在一起时,JavaScript引擎解析会将声明与赋值拆成两部分,声明部分被置顶,赋值则保持在原来的位置。
- 声明过的变量不会再被重新声明。
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);
}
说明:由于预解析,f1的声明被提前,第一行的f1调用有效。观察f1内部实现,第一条语句的意思是定义一个局部变量a和两个全局变量(这两个全局变量不是通过var来声明的),其值均为9,故首先输出三行9,f1()调用结束。接下来的两行输出全局变量b和c,由于a是局部变量,其作用域仅限于f1函数内,且在外部也没有进行声明,故在外部调用a会报错。
10.变量的存储问题
- 基本类型的变量是存放在栈中的,进行b = a的赋值操作时,a与b独立,改变a的值不会影响b.
- 对象是存放在堆中的,定义对象变量(存放在栈中)a与b,将对象赋给a,再进行b = a的赋值操作时,a与b指向了堆中的同一个对象,因此改变a中某个成员的值时b做出同样的改变;而定义一个内容与a、b完全相同的对象变量c时,a、b与c指向的是不同的对象。
11.JavaScript在ES5中无块级作用域{}
的概念,变量的作用域仅限于全局变量和局部变量,在ES6中加入了这一概念,这使得函数的嵌套变成可行。
12.JavaScript中的字符串是不可变的,字符串的所有方法都不会修改字符串本身,操作完成时返回的是一个新的字符串。
语句
if、do-while、while语句
同C语言语法。
for、for-in语句
1.for循环中在初始化表达式中定义的变量在for循环外仍然可以访问到。
for(var i = 0; i < 10; i++) {
alert(i);
}
alert(i); // i = 10
2.for-in循环同Java中的增强for循环
数组
1.创建数组的两种方式:
var arr1 = new Array();
var arr2 = [];
2.数组类型变量的length属性可以获得数组的长度,它是可读可写的,意味着可以通过修改length的值来达到改变数组容量的目的。
扩容后,未定义的值默认为undefined.
函数
1.JavaScript中形参的数量可以和实参的数量不相同。多余的实参会被忽略,缺省的实参会被赋值为undefined,参与的运算结果为NaN.
2.无返回值的函数返回undefined.
3.return只能返回一个值。若返回多个值,则返回最后一个逗号后面的值。
4.不确定个数的参数传递可以使用存储当前实参的伪数组变量arguments来获取。
5.函数的两种声明方式
- 命名函数
function fn() {}
fn();
- 匿名函数
var fn = function () {};
fn();
两种声明方式的最大区别是匿名函数是是函数表达式,函数在代码执行的到当前行的时候才被执行,fn才被赋值;而命名函数是函数的声明,和 var 一样,会被提前到代码最前面定义。
对象
对象的创建方法
对象字面量
这是最常用的创建对象的方法,通过新建一个键值对的集合(对象字面量)创建对象,如下:
var song = {
name:"Liekkas",
time:180,
"song language":English,
singer: {
singerName:"Sofia Jannok",
singerAge:30
}
};
键值对中的键指的是属性的名字,若其中含有空格,名字需要用双引号包含在内。值指的是属性的值,可以是基本类型:如字符串,数字,布尔型,也可以是一个对象。键值对内部使用冒号而非等号隔开,键值对之间用逗号隔开,最后一个键值对后面没有逗号,所有的键值对在一个大括号中,最后一个右大括号后面应以分号结尾。
通过关键字new创建对象
通过new关键字创建对象也是一个常用的方法。如下:
var Store = new Object(); // 创建对象的一个实例
Store.name = "lofo Market";
Store.location = "NO.13 Five Avenue";
Store.salesVolume = 1000000;
通过上面的代码,我们就能创建一个名为Store的对象。
通过工厂方法创建对象
工厂方法就是通过函数创建对象,函数封装了创建对象的过程。
这是一种通过函数创建对象的方法,函数封装了对象的创建过程,创建新对象时只需要调用该函数即可。这种方法适合于一次创建多个对象。
// 对象的创建函数
function createStoreObject(name,location,salesVolume) {
var store = new Object();
store.name = name;
store.locaion = location;
store.salesVolume = salesVolume;
store.display = function() {
console.log(this.name);
};
return store;
}
// 利用该函数创建一个对象
var store1 = createStoreObject("panda express","No.1,People Street",200000);
这样就创建了一个名为store1的对象,注意这个对象除了属性之外还有一个方法display。要创建更多的类似store1的对象,直接调用该函数即可。
使用构造函数创建对象
上面虽然也是通过函数创建对象,但不是构造函数,只是普通函数。构造函数名必须以大写字母开头,函数体内没有返回语句。
// 构造函数
function Store(name,location,salesVolume) {
this.name = name;
this.locaion = location;
this.salesVolume = salesVolume;
}
// 创建对象的实例
var myStore = new Store("KeyExp","No.1,L.Street",540000);
上面的代码首先是Store对象的构造函数,然后用该构造函数创建了Store对象的一个实例myStore。
使用原型(prototype)创建对象
当我们创建一个函数时,函数就会自动拥有一个prototype属性,这个属性的值是一个对象,这个对象被称为该函数的原型对象。也可以叫做原型。
当用new关键字加函数的模式创建一个对象时,这个对象就会有一个默认的不可见的属性[[Prototype]],该属性的值就是上面提到的原型对象。如下所示:
JavaScript 中每个对象都有一个属性[[Prototype]],指向它的原型对象,该原型对象又具有一个自己的[[Prototype]],层层向上直到一个对象的原型为null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。如下所示:
这种方法是对使用构造函数创建对象的改进,使用构造函数创建一个对象时,会把构造函数中的方法(上面的构造函数只有属性的键值对,没有方法)都创建一遍,浪费内存,使用原型不存在这个问题。
function Store() {};
Store.prototype.name = "SF Express";
Store.prototype.locaion = "Hong Kong";
Store.prototype.salesVolume = 1200000000;
// 创建对象
var myStore = new Store();
// 创建一个新的对象
var hisStore = new Store();
hisStore.name = "STO Express"; // 覆盖了原来的name属性
这种方法的好处是,创建一个新的对象时,可以更改部分属性的值。