JavaScript基础

Author Avatar
Silas Shen 9月 24, 2017

过去的一周里,在学习JavaScript的一些知识。确实,这跟之前学的Java,c有很大的不同。JavaScript作为曾经最被误解的语言(被称作丑陋,无用的玩具),到现在成为最为流行和重要的语言之一。这让任何人都会感到不可思议。这也恰是它吸引我的地方。想要感受它的魔力,先从基础开始。对于JavaScript,我会分为三个部分—基础,进阶和高级来学习。

基本知识

JavaScript=ECMAScript+DOM+BOM

  • ECMAScript JavaScript语言规范
  • DOM 针对HTML的编程接口
  • BOM 针对浏览器的编程接口

标识符

  • 第一个字符必须是字母,下划线或美元符号
  • 其他字符可以是字母,下划线,美元符号或数字

strict mode

目的

  • 明确禁止一些不合理、不严谨的语法,减少JavaScript的一些怪异行为。
  • 增加更多报错的场合,消除代码运行的一些不安全之处,保证代码运行的安全。
  • 提高编译器效率,增加运行速度。
  • 为未来新版本的JavaScript做好铺垫。

方法

  1. 全局
<script>
  'use strict';
  console.log('这是严格模式');
</script> 
  1. 函数
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保留字,也是不能作为变量名的

详细关于严格模式

变量

  1. 局部变量
function test(){
var message='hi';  //局部变量
}
test();
alert(message);  //错误
  1. 全局变量
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

声明

  1. function命令
function print(s) {
  console.log(s);
}
  1. 函数表达式
var print = function(s) {
  console.log(s);
};
  1. 采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
var print = function x(){
  console.log(typeof x);
};

x
// ReferenceError: x is not defined

print()
// function
  • 这样写的用处有两个一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)

return语句和递归

  1. JavaScript引擎遇到return语句,就直接返回return后面的那个表达式的值,后面即使还有语句,也不会得到执行。也就是说,return语句所带的那个表达式,就是函数的返回值。
function add(x, y) {
  return x + y;
}

add(1, 1) // 2
  1. 函数可以调用自身—递归,下面计算斐波那契数列的代码,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;
}

  1. 可以用来检查一个没有声明的变量,而不报错。