JavaScript基础
过去的一周里,在学习JavaScript的一些知识。确实,这跟之前学的Java,c有很大的不同。JavaScript作为曾经最被误解的语言(被称作丑陋,无用的玩具),到现在成为最为流行和重要的语言之一。这让任何人都会感到不可思议。这也恰是它吸引我的地方。想要感受它的魔力,先从基础开始。对于JavaScript,我会分为三个部分—基础,进阶和高级来学习。
基本知识
JavaScript=ECMAScript+DOM+BOM
- ECMAScript JavaScript语言规范
- DOM 针对HTML的编程接口
- BOM 针对浏览器的编程接口
标识符
- 第一个字符必须是字母,下划线或美元符号
- 其他字符可以是字母,下划线,美元符号或数字
strict mode
目的
- 明确禁止一些不合理、不严谨的语法,减少JavaScript的一些怪异行为。
- 增加更多报错的场合,消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译器效率,增加运行速度。
- 为未来新版本的JavaScript做好铺垫。
方法
- 全局
<script>
'use strict';
console.log('这是严格模式');
</script>
- 函数
function strict() {
'use strict';
return '这是严格模式';
}
function strict2() {
'use strict';
function f() {
return '这也是严格模式';
}
return f();
}
过渡
非函数代码块不得声明函数
'use strict';
if (true) {
function f1() { } // 语法错误
}
for (var i = 0; i < 5; i++) {
function f2() { } // 语法错误
}
- 上面代码在if代码块和for代码块中声明了函数,在严格模式下都会报错
保留字
function package(protected) { // 语法错误
'use strict';
var implements; // 语法错误
}
- 严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。使用这些词作为变量名将会报错
- 此外,ES5本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的
详细关于严格模式
变量
- 局部变量
function test(){
var message='hi'; //局部变量
}
test();
alert(message); //错误
- 全局变量
function test(){
message='hi'; //全局变量
}
test();
alert(message); //'hi'
- 定义局部变量时,不要漏了var,否则会造成局部变量的污染
数据类型
typeof运算符
原始类型
typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
- 数值、字符串、布尔值分别返回number、string、boolean
函数
function f() {}
typeof f
// "function"
- 函数返回function
undefined
typeof undefined
// "undefined"
- undefined返回undefined[1]
// 错误的写法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正确的写法
if (typeof v === "undefined") {
// ...
}
- 用来判断语句
其他
typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
- 除上述情况外,其他情况都返回object
undefined和null
两者都可以表示“没有”,含义很相似,语法效果几乎一样。
if (!undefined) {
console.log('undefined is false');
}
// undefined is false
if (!null) {
console.log('null is false');
}
// null is false
undefined == null
// true
- 在if语句中,它们都会被自动转为false
用法和含义
// 变量声明了,但没有赋值
var i;
i // undefined
// 调用函数时,应该提供的参数没有提供,该参数等于undefined
function f(x) {
return x;
}
f() // undefined
// 对象没有赋值的属性
var o = new Object();
o.p // undefined
// 函数没有返回值时,默认返回undefined
function f() {}
f() // undefined
- 当⼀个变量是为了保存⼀个对象,但没办法⽴即初始化的时候,应该为之分配⼀个null值
bull
如果JavaScript预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值
undefined
null
false
0
NaN
""或’’(空字符串)
- 转换规则是除了上面六个值被转为false,其他值都视为true
if ([]) {
console.log(true);
}
// true
if ({}) {
console.log(true);
}
// true
- 需要特别注意的是,空数组([])和空对象({})对应的布尔值,都是true。
number
整数和浮点数
JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,再进行运算。
特殊数值
+0和-0
-0 === +0 // true
0 === -0 // true
0 === +0 // true
+0 // 0
-0 // 0
(-0).toString() // '0'
(+0).toString() // '0'
- 几乎所有场合,正零和负零都会被当作正常的0。
(1 / +0) === (1 / -0) // false
- 除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的
NaN
NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
NaN + 32 // NaN
NaN - 32 // NaN
NaN * 32 // NaN
NaN / 32 // NaN
NaN === NaN // false
- NaN与任何数(包括它自己)的运算,得到的都是NaN
Infinity
Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity。
//场景一
Math.pow(2, Math.pow(2, 100))
// Infinity
// 场景二
0 / 0 // NaN
1 / 0 // Infinity
string
字符串与数组
var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"
// 直接对字符串使用方括号运算符
'hello'[1] // "e"
- 字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)
var s = 'hello';
delete s[0];
s // "hello"
s[1] = 'a';
s // "hello"
s[5] = '!';
s // "hello"
- 字符串内部的单个字符无法改变和增删
length属性
var s = 'hello';
s.length // 5
s.length = 3;
s.length // 5
s.length = 7;
s.length // 5
- 字符串的length属性无法改变,但是不会报错
object
对象(object)是JavaScript的核心概念,也是最重要的数据类型。JavaScript的所有数据都可以被视为对象。简单说,所谓对象,就是一种无序的数据集合,由若干个“键值对”(key-value)构成。
生成方法
var o1 = {}; //简洁明了
var o2 = new Object(); //采用构造函数的写法清晰地表示了意图
var o3 = Object.create(Object.prototype); //一般用在需要对象继承的场合
属性
var o = {
p: function (x) {
return 2 * x;
}
};
o.p(1)
// 2
- 对象的每一个“键名”又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用
var obj = {};
obj.foo = 123;
obj.foo // 123
- 属性可以动态创建,不必在对象声明时就指定
这篇文章是关于JavaScript基础的学习总结,暂不深入讨论关于object的更多内容
function
声明
- function命令
function print(s) {
console.log(s);
}
- 函数表达式
var print = function(s) {
console.log(s);
};
- 采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
var print = function x(){
console.log(typeof x);
};
x
// ReferenceError: x is not defined
print()
// function
- 这样写的用处有两个一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)
return语句和递归
- JavaScript引擎遇到return语句,就直接返回return后面的那个表达式的值,后面即使还有语句,也不会得到执行。也就是说,return语句所带的那个表达式,就是函数的返回值。
function add(x, y) {
return x + y;
}
add(1, 1) // 2
- 函数可以调用自身—递归,下面计算斐波那契数列的代码,fib函数内部又调用了fib()。
function fib(num) {
if (num === 0) return 0;
if (num === 1) return 1;
return fib(num - 2) + fib(num - 1);
}
fib(6) // 8
运算符
加法运算符
'1' + {foo: 'bar'} // "1[object Object]"
'1' + 1 // "11"
'1' + true // "1true"
'1' + [1] // "11"
- 由于运算符左边是一个字符串,导致右边的运算子都会先转为字符串,然后执行字符串连接运算
'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"
- 这种由于参数不同,而改变自身行为的现象,叫做“重载”(overload)。由于加法运算符是运行时决定到底执行那种运算,使用的时候必须很小心
数值运算符and负数值运算符
+true // 1
+[] // 0
+{} // NaN
- 数值运算符的作用在于可以将任何值转为数值(与Number函数的作用相同)
var x = 1;
-x // -1
-(-x) // 1
- 负数值运算符(-),也同样具有将一个值转为数值的功能,只不过得到的值正负相反。连用两个负数值运算符,等同于数值运算符
语句
函数
模拟函数的重载
使用模拟函数重载来编写一个具有如下功能的函数:
1,如果输入参数大于三个,返回最后一个参数。
2,如果输入参数小于等于三个且全部为数字,则返回排序后的数组,如果最后一个数为奇数则降序排列,反之升序排列。
3,如果输入参数小于等于三个且包含字符串,则将所有参数强制转化为字符串联接返回。
function myFunc() {
var arguLen = arguments.length
if (arguLen > 3) { //第一种情况
return arguments[arguLen-1];
}
else if (arguLen <= 3) {
var numFlag = true; //用于判断是否均为数字
var strFlag = false; //用于判断是否包含字符串
for (var i =0; i<=arguLen; ++i){
if (typeof arguments[i] != "number") {
numFlag = false;
}
if (typeof arguments[i] === "string") {
strFlag = true;
break;
}
}
if (numFlag) { //第二种情况
// arguments是array-like object,故先转为数组
var args = [].slice.call(arguments,0); //转成数组
// 最后一个参数为偶数时的情况
if (args[arguLen - 1] % 2 == 0){
return args.sort((a, b) => a - b); //升序
}
else {
return args.sort((a,b) => b - a); //降序
}
}
else if (strFlag) { //第三种情况
var result = "";
for (var i = 0; i <= arguLen; ++i;) {
result += String(arguments[i]);
}
return result;
}
}
return;
}
可以用来检查一个没有声明的变量,而不报错。 ↩