JavaScript通用语法(一)

目录

语法概念

常见语法内容

数据类型

  • null、undefine和布尔

  • Number(数值)

  • String(字符串)

  • Object(对象)

  • Function(函数)

  • Array(数组)

JavaScript的概念

JavaScript 是一种轻量级的脚本语言。所谓“脚本语言”(script language),指的是它不具备开发操作系统的能力,而是只用来编写控制其他大型应用程序(比如浏览器)的“脚本”。

从语法角度看,JavaScript 语言是一种“对象模型”语言。各种宿主环境通过这个模型,描述自己的功能和操作接口,从而通过 JavaScript 控制这些功能。但是,JavaScript 并不是纯粹的“面向对象语言”,还支持其他编程范式(比如函数式编程)。

JavaScript 的核心语法部分相当精简,只包括两个部分:基本的语法构造(比如操作符、控制结构、语句)和标准库(就是一系列具有各种功能的对象比如Array、Date、Math等)。除此之外,各种宿主环境提供额外的 API(即只能在该环境使用的接口),以便 JavaScript 调用。以浏览器为例,它提供的额外 API 可以分成三大类。

  • 浏览器控制类:操作浏览器
  • DOM 类:操作网页的各种元素
  • Web 类:实现互联网的各种功能

常见语法知识

JS中有一部分语法知识非常通用,与java语言非常相似,大概内容如下:

变量

var i = 3 + 1; // 变量声明
//等同于(声明和赋值)
var i;
i = 3+1;

var A = 4; // 变量区分大小写

//如果变量赋值的时候,忘了写var命令,这条语句也是有效的。
var x = 4;
//等同于
x = 4;

//如果只是声明变量而没有赋值,则该变量的值是undefined
var a;
a // undefined

//如果一个变量没有声明就直接使用,JavaScript 会报错,告诉你变量未定义。
s; // 会提示报错

变量提升

JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。方法中的变量提示只作用于方法块中。全局的变量提示作用与全局。

// var a 在console.log(a)后面,但是编译时a会被提前声明,但是注意赋值操作不会被提前。

console.log(a);
var a = 1;
// 等价于
var a;
console.log(a);
a = 1;

标识符

标识符(identifier)指的是用来识别各种值的合法名称。最常见的标识符就是变量名,以及后面要提到的函数名。JavaScript 语言的标识符对大小写敏感,所以a和A是两个不同的标识符。

简单说,标识符命名规则如下:

  • 第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
  • 第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字0-9。

条件语句

var x = 1;

if(x === 3)
{

}else if(x=== 2)
{

}else if(x=== 1)
{

}else
{

}

switch 结构

// 如果break 省略不写,会跳不出switch结构
switch (x) 
{
  case 1:
    console.log('x 等于1');
    break;
  case 2:
    console.log('x 等于2');
    break;
  default:
    console.log('x 等于其他值');
}

循环语句

var x = 0;
//while
while(x < 10)
{
    console.log(x);
    x++;
}

// do while;
x = 0;
do{
   console.log(x);
   x++;
}while(x < 10)

x= 0;
//for 循环
for(int i = 0; i < 10; i++)
{
   console.log(x);
   x++;
}

break和continue

break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行。

// break 跳出循环
var i = 0;
while(i < 100) 
{
  console.log('i 当前为:' + i);
  i++;
  if (i === 10) break;
}


//continue 跳出当前循环
var i = 0;
while (i < 100)
{
  i++;
  if (i % 2 === 0) continue;
  console.log('i 当前为:' + i);
}

数据类型

null, undefined 和布尔值

var i;
i // undefined

// 对象没有赋值的属性
var  o = new Object();
o.p // undefined

var a = null;

undefined == null
// true

null是一个表示“空”的对象,转为数值时为0,undefined是一个表示"此处无定义"的原始值,转为数值时为NaN。

其他对象与布尔值的转化:

// false
if ('') {
  console.log('true');
}

// true
if([])
{
    console.log('true');
}

// true
if({})
{
    console.log('true');
}

// false
var a;
if(a)
{
    console.log('true');
}
对象类型转换为true的值转换为false的值
String任何非空字符串""或’’,空字符串
Number非0非NaN的任何数0或者NaN
Object其他null或者undefined

数值

JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。

//true
1.0 == 1;

这就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算。

由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。

0.1 + 0.2 === 0.3
// false

0.3 / 0.1
// 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)
// false

根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。

第1位:符号位,0表示正数,1表示负数

第2位到第12位(共11位):指数部分

第13位到第64位(共52位):小数部分(即有效数字)

指数部分一共有11个二进制位,因此大小范围就是0到2047。IEEE 754 规定,如果指数部分的值在0到2047之间(不含两个端点),那么有效数字的第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字这时总是1.xx…xx的形式,其中xx…xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。

(-1)^符号位 * 1.xx...xx * 2^指数部分

维持精度下最大和最小的二进制表示数值是:(小数位有52位,加上默认计算时添加的’1.’,实际计算时小数部分位数最大为53位,指数位最大为 2^11 -1 ,最大进位2047位,但是小数位最长53位,决定了实际最大进位为53位,所以最大和最小值如下:)

min = -1 * 2^53;
max = 1 * 2^53;

由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。

javaScript表示的数值范围:

指数最大值为2^11(0 —— 2047),一半表示负数,一般表示正数,实质上指数的范围是 2^-1023 —— 2^1024(开区间)。

如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity

Math.pow(2, 1024) // Infinity

如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位,即1.000……1),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。

Math.pow(2, -1075) // 0

Number对象的最大值和最小值:

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324

JavaScript 的数值有多种表示方法,可以用字面形式直接表示,比如35(十进制)和0xFF(十六进制),二进制,八进制等。

123e3 // 123000
123e-3 // 0.123
-3.1E+12
.1e-23

科学计数法允许字母e或E的后面,跟着一个整数,表示这个数值的指数部分。

数值的进制表示方法:

进制表示方法
十进制没有前导0的数值
八进制有前缀0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
二进制有前缀0b或0B的数值
十六进制有前缀0x或0X的数值

默认情况下,各进制会自动转为十进制。如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错。通常来说,有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制。

NaN

NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。

5 - 'x' // NaN

//另外,一些数学函数的运算结果会出现NaN:
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN

//0除以0也会得到NaN
0 / 0 // NaN

NaN的运算。

NaN与任何数(包括它自己)的运算,得到的都是NaN

NaN === NaN // false
//数组的indexOf方法内部使用的是严格相等运算符,所以该方法对NaN不成立
[NaN].indexOf(NaN) // -1

Infinity

Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity.

Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。Infinity与NaN比较,总是返回false。任何与NaN比较的计算,都会返回NaN,而NaN在转换成boolean 时返回false。

Infinity的计算

// 无法预料结果,因此返回NaN
0 * Infinity // NaN
// 结果为0;
0 / Infinity // 0
// 结果为无限大
Infinity / 0 // Infinity

//Infinity与null计算时,null会转成0,等同于与0的计算。
null * Infinity // NaN
null / Infinity // 0
Infinity / null // Infinity

//Infinity与undefined计算,返回的都是NaN。
undefined + Infinity // NaN
undefined - Infinity // NaN
undefined * Infinity // NaN
undefined / Infinity // NaN
Infinity / undefined // NaN

数值相关的计算:

parseInt方法用于将字符串转为整数。

parseInt('123') // 123

//如果字符串头部有空格,空格会被自动去除
parseInt('   81') // 81

//如果parseInt的参数不是字符串,则会先转为字符串再转换。
parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1

//字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15

parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1

//如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。
parseInt('0x10') // 16
//如果字符串以0开头,将其按照10进制解析。
parseInt('011') // 11

// parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。

parseInt('1000', 10) // 1000
parseInt('1000', 2) // 8
parseInt('1000', 6) // 216
parseInt('1000', 8) // 512

//如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN。如果第二个参数是0、undefined和null,则直接忽略。
parseInt('10', 37) // NaN
parseInt('10', undefined) // 10

//如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回NaN。
parseInt('1546', 2) // 1
parseInt('546', 2) // NaN

parseFloat方法用于将一个字符串转为浮点数。

parseFloat('3.14') // 3.14

//如果字符串符合科学计数法,则会进行相应的转换。
parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14

//如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。
parseFloat('3.14more non-digit characters') // 3.14
//parseFloat方法会自动过滤字符串前导的空格。
parseFloat('\t\v\r12.34\n ') // 12.34

//如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN
parseFloat([]) // NaN
parseFloat('FF2') // NaN
parseFloat('') // NaN

IsNaN()

isNaN方法可以用来判断一个值是否为NaN;

isNaN(NaN) // true
isNaN(123) // false

//但是,isNaN只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回true,这一点要特别引起注意。
isNaN('Hello') // true
// 相当于
isNaN(Number('Hello')) // true
isNaN({}) // true
// 等同于
isNaN(Number({})) // true

isNaN(['xzy']) // true
// 等同于
isNaN(Number(['xzy'])) // true

String

字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。

//单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号。
'abc'
"abc"
'key = "value"'
"It's a long journey"

//如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠。但是输出时会变成一行。
var longString = 'Long \
long \
long \
string';

//连接运算符(+)可以连接多个单行字符串,将长字符串拆成多行书写,输出的时候也是单行。
var longString = 'Long '
  + 'long '
  + 'long '
  + 'string';

字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。

var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"

// 如果超出了字符长度,则返回undefined;
'abc'[3] // undefined
'abc'[-1] // undefined
'abc'['x'] // undefined

字符串的length属性不变。


Object(对象)
对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。

//如果键名是数值,会被自动转为字符串。
var obj = {
  foo: 'Hello',
  bar: 'World',
  1:'世界'
};

//如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。

属性的操作

var obj = {
  p: 'Hello World'
};
//点运算
obj.p // "Hello World"
//方括号运算
obj['p'] // "Hello World"
//请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。

属性的赋值

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

var obj = {};
//javaScript 允许动态的增删属性;
// 增加属性
obj.'foo' = 'Hello';
obj['bar'] = 'World';

属性的遍历与删除

var obj = {
  "saber":"川澄绫子",
}
delete obj."saber";

// 返回属性的array数组;
var keyArray = Object.keys(obj);

属性是否存在:in 运算符

in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。它的左边是一个字符串,表示属性名,右边是一个对象。

var obj = {
  "语文":89,
  "书写":80,
  "数学":99,
  "历史":60
}
//in运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。就像上面代码中,对象obj本身并没有toString属性,但是in运算符会返回true,因为这个属性是继承的。
'toString' in obj // true;
//这时,可以使用对象的hasOwnProperty方法判断一下,是否为对象自身的属性。
obj.hasOwnProperty('toString'); // false;

属性的遍历:for…in 循环

for…in循环用来遍历一个对象的全部属性。

  • 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
  • 它不仅遍历对象自身的属性,还遍历继承的属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
  console.log('键名:', i);
  console.log('键值:', obj[i]);
}

with 语句

with语句的格式如下:

with (对象) {
  语句;
}

它的作用是操作同一个对象的多个属性时,提供一些书写的方便。with 语句中的作用域指定不明确,下示例中的 href 如果全局有一个href对象的话,那么存在指定不明确的问题。

// 例二
with (document.links[0]){
  console.log(href);
  console.log(title);
  console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);

Function(函数)
函数的声明:

  • function命令声明
  • 函数表达式声明
  • Function 构造函数
// function命令声明:function 方法名 (参数) {       语句 };
function print(s) {
  console.log(s);
}

// 函数表达式: var  显式函数名 = function 隐式函数名(可选) (参数) { 语句 };表达式声明的函数必须已;结尾,function 后面接的隐式函数名只能在函数的方法体中使用,对外使用 显式函数名。
var f = function x(s){
  console.log(s);
};

//Function 构造函数,使用较少;
var add = new Function(
  'x',
  'y',
  'return x + y'
);
// 等同于
function add(x, y) {
  return x + y;
}

如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。注意javaScript像java一样存在方法重载,通过函数参数的个数对同名函数加以区分。


function f() {
  console.log(1);
}
// 由于函数名提升,导致执行的是下一个f()方法。
f() // 2

function f() {
  console.log(2);
}
f() // 2

‘函数名()’—— 函数名 + () —— 函数调用符,便会调用这个函数。

funtion add(x,y)
{
  return x + y;
}

add(5,10); // add 是函数名,()是函数调用符,()中可以添加参数。

JavaScript 中函数是一种值,这表示函数可以作为表达式的值,作为函数的参数,从而使得函数与其他值的地位相等,被称为 函数为第一等公民。

function add(x, y) {
  return x + y;
}

// 将函数赋值给一个变量
var operator = add;

// 将函数作为参数和返回值
function a(op){
  return op;
}
// 调用方式与常规不同,常规方式:a(add(1,1));
a(add)(1, 1)
// 2

JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。注意只有function声明的函数才行。同时使用了function声明和表达式声明的同名函数,已表达式声明的函数为准,注意这个和重载不一样。

var f = function () {
  console.log('1');
}

function f() {
  console.log('2');
}

f() // 1

函数的属性和方法:

name属性:

函数的name属性返回函数的名字

function f1() {}
f1.name // "f1"

// 表达式声明的函数已显示函数名为主
var f2 = function () {};
f2.name // "f2"

//真正的函数名还是f3,而myName这个名字只在函数体内部可用。
var f3 = function myName() {};
f3.name // 'myName'

length 属性

函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。

function f(a, b) {}
f.length // 2
// 函数的实际调用可以添加多个参数,但是length不变,length属性用于识别方法重载(overload);

toString 属性:
函数的toString方法返回一个字符串,内容是函数的源码。

函数作用域:

作用域(scope)指的是变量存在的范围。在 ES5 的规范中,Javascript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。

函数外声明的变量是全局变量,全局变量用于全局作用域,可以在函数内部访问到。

在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。当前函数块中可以访问,但是,其余地方就无法访问了。函数内部定义的变量,会在该作用域内覆盖同名全局变量。

函数内部的变量提升,局部变量的声明会提到函数头部。

参数:

函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。

函数参数不是必需的,Javascript 允许省略参数。

function f(a, b) {
  return a;
}

f(1, 2, 3) // 1
f(1) // 1
f() // undefined

f.length // 2
//参数是按照顺序赋值的,如果像省略前面的参数,用undefined 代替。
f(undefined, 1) // undefined

参数如果传入原始类型,那么外面的变量的值不受影响,如果是对象(引用类型参数),那么参数的改变会影响原来的值。

同名参数

如果有同名的参数,则取最后出现的那个值。

function f(a, a) {
  console.log(a);
}

f(1, 2) // 2

// 同样的,f(1)中第二个参数为undefined;
f(1) // undefined

arguments 对象:

由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。

arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。

var f = function (one) {
  console.log(arguments[0]);
  console.log(arguments[1]);
  console.log(arguments[2]);
}

f(1, 2, 3)
// 1
// 2
// 3

// 函数参数一般情况下可以动态的更改
var f = function(a, b) {
  arguments[0] = 3;
  arguments[1] = 2;
  return a + b;
}

f(1, 1) // 5


//严格模式下,arguments对象是一个只读对象,修改它是无效的,但不会报错。
var f = function(a, b) {
  'use strict'; // 开启严格模式
  arguments[0] = 3; // 无效
  arguments[1] = 2; // 无效
  return a + b;
}

f(1, 1) // 2

//通过arguments对象的length属性,可以判断函数调用时到底带几个参数
function f() {
  return arguments.length;
}

f(1, 2, 3) // 3

需要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用。将arguments转换成一个array对象

var args = Array.prototype.slice.call(arguments);

// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}

//arguments对象带有一个callee属性,返回它所对应的原函数。
var f = function () {
  console.log(arguments.callee === f);
}
f() // true

闭包:
闭包就是将函数内部和函数外部连接起来的一座桥梁

function Person(name) {
  var _age;
  function setAge(n) {
    _age = n;
  }
  function getAge() {
    return _age;
  }

  return {
    name: name,
    getAge: getAge,
    setAge: setAge
  };
}

var p1 = Person('张三');
p1.setAge(25);
p1.getAge() // 25

外部通过setAge 和getAge这两个function来访问Persion的_age属性,简介达到外部访问函数内部的效果,内部函数 setAge 和getAge 相当于一个桥梁,也就是闭包。


数组

数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示。

var arr = ['a', 'b', 'c'];

//除了在定义时赋值,数组也可以先定义后赋值。
var arr = [];

arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';

// 数组中可以放入任何类型的数据
var arr = [
  {a: 1},
  [1, 2, 3],
  function() {return true;}
];


// 多维数组
var a = [[1, 2], [3, 4]];
a[0][1] // 2
a[1][1] // 4

// 数组是对象:
//本质上,数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。
typeof [1, 2, 3] // "object"

//数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...)。
var arr = ['a', 'b', 'c'];

Object.keys(arr)
// ["0", "1", "2"]

//数组的length属性,返回数组的成员数量。
var arr = [ 'a', 'b', 'c' ];
var length = arr.length // 3;
// 将length设置为2,最后一个元素会被删除
arr.length = 2;
arr['c'] // undefined;
// 将length设置为 0,那么数组会清空;
arr.length = 0;
// arr[];

//如果人为设置length大于当前元素个数,则数组的成员数量会增加到这个值,新增的位置都是空位。
var a = ['a'];
a.length = 3;
a[1] // undefined

//使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。
var a = [1, 2, 3];
delete a[1];

var a = [, , ,]; // length = 3,空位;
a[1] // undefined

//数组的某个位置是空位,与某个位置是undefined,是不一样的。如果是空位,使用数组的forEach方法、for...in结构、以及Object.keys方法进行遍历,空位都会被跳过。

//如果某个位置是undefined,遍历的时候就不会被跳过。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值