Javascript笔记(二)之语法基础介绍

版权声明:本文为小嘉丶学长原创文章,未经博主允许不得转载。 https://blog.csdn.net/fj_Author/article/details/82021722

前言

上一篇,我们简单到介绍了JavaScript和EcmaScript的区别与相同点和前端三要素:结构/样式/行为。行为部分主要是由JavaScript来负责的;

JavaScript词法结构

JavaScript是用Unicode字符集编写。
JavaScript是区分大小写的语言。
JavaScript的注释支持C语言的两种注释。
在JavaScript,标识符用来对变量和函数进行命名,以字母、下划线(_)或美元符($),只能有下划线、没有符号、英文字母开头,不能是关键字或保留子;
ES6(ECMAScript2015)中定义来了如下关键字|保留字

break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try let satic

enum
await

implements package protected
interface private public

可以使用分号结尾,也可以不使用分号作为语句结尾。提到语法规范的时候将会详细讲解jslint 和eslint规范。

类型、值和变量

1、变量

变量是可以使用var、let关键字和不使用 关键字来的定义的;

// 1、形式一
var myVariable = 1; //定义并初始化
// 2、 形式二
var myVariable1 ; //变量定义
myVariable1 = 2  // 初始化
// 3、 形式三(ES6语法)
let myVariable2 = 1; 
// 4、形式四
myVariable3  = 1; // 严格模式不支持,标准模式,如果未使用var,则为全局变量

如果你变量重复定义在ES6中将会有一个错误

SyntaxError: Identifier 'myVariable2' has already been declared

在ES5对严格模式中给一个未声明对变量赋值也会报错,但是在标准模式之中,重复定义是不会报错的。

如果不使用var来说声明变量,那么该变量就会自动被声明为全局变量。

2、类型与值

JavaScript中变量的类型分为两类:原始类型(primitive type)和对象类型(object type)。
原始类型包括:数字型、字符串、布尔值、特殊原始值(null、undefined);

按照是否可变,也可以分为可变类型和不可变类型。数字、字符串、布尔值、null、undefined是不可变类型;

词法作用域(lexical scoping):不在任何函数内定义的变量为全局变量,函数内声明的作用域有函数作用域,只在函数内可见;

字面量(直接量,literal):在代码之中直接显示的值,成为字面量或直接量;

100 //数字字面量
"xiaojia" // 字符串字面量
truefalse  //布尔字面量
null  // 空对象字面量
/88/gi  // 正则表达式字面量
{name:"xiaojia",age:26}  // 对象字面量表达式
[1,2,3,4,5]  // 数组字面量表达式

2.1、数字型(number)

数字型支持整型、浮点型。

整型支持十进制和十六进制(0x或0X开头)表示形式,ECMAScript不支持八进制,但是JavaScript支持八进制表示形式(0开头),严格模式下是禁止使用八进制的;

浮点型有两种写法,小数点形式和科学计数法形式都支持,浮点型有三个特殊都值,-Infinity(负无穷大)、Infinity(无穷大)、NaN(不是一个数,not a number)。

Number.MIN_VALUE  // 最小值
Number.MAX_VALUE  // 最大值
Number.POSITIVE_INFINITY  // 正无穷
Number.NEGATIVE_INFINITY  // 负无穷
Number.NaN // 不是一个数

在javascript之中提供了全局函数isFinite()Number.isFinite()来判断Number类型的有限性,也就是说是否是无穷大

NaN:不是一个数,是一个不可配置(non-configurable),不可写(non-writable),不可枚举(non-enumerable)的属性。在实际的编程之中,很少直接使用到了NaN,通常是在计算失败到时候,出现;

isNaN()Number.isisNaN():
NaN最特殊的地方就是NaN == NaNNaN === NaN 的返回值都是false,即NaN自身永不相等于自身。根据这个特征为们可以通过判断x!=x来判断是否是NaN,在缺少isNaN()函数的时候,为们可以使用如下方式:

var isNaN = function(value) {
    var n = parseInt(value);
    return n !== n;
};

我们可以使用全局函数isNaN()来判断是否是NaN。
案例:

isNaN(NaN);       // true
isNaN(undefined); // true
isNaN({});        // true

isNaN(true);      // false
isNaN(null);      // false
isNaN(37);        // false

// strings
isNaN("37");      // false: 可以被转换成数值37
isNaN("37.37");   // false: 可以被转换成数值37.37
isNaN("37,5");    // true
isNaN('123ABC');  // true:  parseInt("123ABC")的结果是 123, 但是Number("123ABC")结果是 NaN
isNaN("");        // false: 空字符串被转换成0
isNaN(" ");       // false: 包含空格的字符串被转换成0

// dates
isNaN(new Date());                // false
isNaN(new Date().toString());     // true

isNaN("blabla")   // true: "blabla"不能转换成数值 , 转换成数值失败, 返回NaN

在ES6之中,提供来Number.isNaN()来判断其值是否是一个NaN和其类型是否为Number。它是全局函数isNaN()函数的更强大版本

Number.isNaN = Number.isNaN || function(value) {
    return typeof value === "number" && isNaN(value);
}
Number.isNaN(NaN);        // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0)       // true

// 下面这几个如果使用全局的 isNaN() 时,会返回 true。
Number.isNaN("NaN");      // false,字符串 "NaN" 不会被隐式转换成数字 NaN。
Number.isNaN(undefined);  // false
Number.isNaN({});         // false
Number.isNaN("blabla");   // false

// 下面的都返回 false
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(37);
Number.isNaN("37");
Number.isNaN("37.37");
Number.isNaN("");
Number.isNaN(" ");

isNaN()方法适用于对象,在基于对象调用isNaN()方法时候,会先调用对象的valueOf()方法,然后确定是否可以转换为数值,如果不能则基于这个返回值再调用toString()。如果toString()方法返回的不是原始类型,结果就会报错。

valueOf()方法默认返回对象本身

isNaN({
  valueOf: function () {
    return 2;
  }
})
// false

isNaN({
  toString: function () {
    return 3;
  }
})
// false

Number({
  valueOf: function () {
    return 2;
  },
  toString: function () {
    return 3;
  }
})
// 2

注意:只要是浮点数就会存在有精度问题。

2.2、字符串(string)

2.2.1、普通字符串

字符串是有引号(双引号或单引号)引起的字符序列,引号必须成对出现。

转义字符:使用\(反斜杆)来转义某些具有特殊含义的符号或者使普通字符有特殊含义

\n 换行
\b 退格
\t 制表符
\\\ 反斜杆
\' 单引号
\" 双引号

字符串是不可变序列

2.2.2、多行字符串(ES6语法)

由于多行字符串用\n写起来比较麻烦,所以ES6新增了多行字符串的写法使用反引号(`)来表示。

例如:

var s = `这是一个
多行
字符串`;
console.log(s);

如果你的浏览器不支持ES6语法,将报SyntaxError错误:

多行字符也可以才用反斜杆来书写\

var s = "这是一个\
多行\
字符串";
console.log(s);

2.2.3、模板字符串

在ES6之前,我们如果需要把多个字符串连接起来,需要使用+号来连接字符

var name = '小嘉学长';
var age = 26;
var message = '你好, ' + name + ', 你今年' + age '岁了!';
console.log(message);

这样我们需要将很多变量连接起来,使用+比较麻烦。后来,ES6新增了一种模板语法。

var name = '小嘉学长';
var age = 26;
var message = `你好,  ${name}, 你今年${age}岁了!';
console.log(message);

2.3、布尔型(boolean)

布尔类型只有两个值true和false;

2.4、undefined和null

null(关键字)是一个特别的值,如果你使用typeof 运算符来运算,你可以得到“object“的值,可以将null认为是一个特殊的对象值

undefined是一个预定义的全局变量(它不是关键字),使用typeof运算符可以得到“undefined“对值
undefined未定义的值出现有几种情况:

  • 如果变量未定义
  • 要查询的对象或数组元素不存在
  • 函数没有返回值
  • 引用没有提供实参的形参值
  • 变量已经定义,但是为初始化

null与undefined的不同

当检测 null 或 undefined 时,注意相等(==)与全等(===)两个操作符的区别 ,前者会执行类型转换:

typeof null        // "object" (因为一些以前的原因而不是'null')
typeof undefined   // "undefined"
null === undefined // false
null  == undefined // true
null === null // true
null == null // true
!null //true
!undefined //true
isNaN(1 + null) // false
isNaN(1 + undefined) // true

2.5 Symbol类型

在ES6之中新增了Symbol数据类型,表示独一无二的值。Symbol类型使用Symbol()函数来创建,不能使用new关键字来创建,如果使用new关键字将会报如下错误

TypeError: Symbol is not a constructor
    at new Symbol (<anonymous>)

由此可见,Symbol类型是一个原始类型而不是一个对象类型。

Symbol()函数接受一个字符串参数。

let s1 = Symbol();
let s2 = Symbol('foo');
 

Symbol类型可以通过String()或toString()来转换为字符串类型

let sym = Symbol('My symbol');

String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

在ES6之前对象的属性名都是字符串,而在ES6之后,我们可以使用Symbol来定义属性名,使用Symbol值作为属性的时候,必须把Symbol放在[]之中,如果不放在方括号中,属性的键名为字符串。

注意: Symbol值作为属性名的时候,为公开属性,而不是私有属性,Symbol值可以用在switch语句之中

2.6、 类型检验

在JavaScript之中有如下4种类型检查对方法:

  • typeof
  • instanceof
  • constructor
  • toString.call()

2.6.1、typeof运算符

typeof 3;                //'number'
typeof NaN;              //'number'

typeof '3';              //'string'
typeof '';               //'string'

typeof true;             // 'boolean'
typeof Boolean(true);    // 'boolean'

typeof undefined;        // 'undefined'

typeof {};                // 'object'

typeof function fn(){};  // 'function'

typeof Symbol();         // 'symbol'

// 可见类对本质是function
typeof class c{};        // 'function'

typeof null;             // 'object'
typeof new Number(3);    // 'object'
typeof new String(3);    // 'object'
typeof [];               // 'object'
typeof /\w+/;            // 'object'
typeof new Date();       // 'object'
typeof new Error();      // 'object'
typeof new Map();        // 'object'
typeof new Set();        // 'object'

由此可见,typeof运算符对基础类型对判断还是比较准确对,但是对基础类型对保存类就无法正确检测了,只是返回一个’object’,并且对ES新增对Map和Set类型也无法检测。

数组、正则表达式、Date、Error类型都无法得到争取都结果。同样null返回类一个’object’,这是不太准确的;

虽然typeof有这样的缺点,但并不影响现有框架使用typeof;

2.6.2、constructor
constructor 我们称之为值但构造器,也就是constructor属性来检测其类型;

(3).constructor === Number;       // true

NaN.constructor === Number;       // true

''.constructor === String;        // true

true.constructor === Boolean;     // true

Symbol().constructor === Symbol;  // true

var o = {};
o.constructor === Object;         // true

var fn = function() {};
fn.constructor === Function;      // true

var ary = [];
ary.constructor === Array;        // true

var date = new Date();
date.constructor === Date;        // true

var regex = /\w+/;
regex.constructor === RegExp;     // true

var error = new Error();
error.constructor === Error;      // true

var map = new Map();
map.constructor === Map;          // true

var set = new Set();
set.constructor === Set;          // true

new Number(3).constructor === Number;         // true

new Number(NaN).constructor === Number;       // true

new String('').constructor === String;        // true

new Boolean(true).constructor === Boolean;    // true

我们可以发现,使用constructor可以完成大部分值但类型检测,但是它无法检测null和undefined的值,但是我们可以使用其他手段来检测这两个值。如果你尝试使用null和undefined去访问constructor将报如下的错误;

TypeError: Cannot read property 'constructor' of null

使用构造器的方式还可以检测自定义对象,但是如果对象涉及到继承到时候,构造器到检测就有点力不从心了;

2.6.3、instanceof运算符

涉及到继承的时候,我们可以使用instanceof来检测值的类型。instanceof适用在对象类型,对于对象类型之外对值,instanceof没有什么用处。

// 虽然typeof null的结果为'object' 但它并不是Object的实例

null instanceof Object;               // false

// 对于基础类型 instanceof操作符并不会有隐式包装

3 instanceof Number;                  // false

'3' instanceof Number;                // false

true instanceof Boolean;              // false

Symbol() instanceof Symbol;           // false

// 只对对象类型起作用

new Number(3) instanceof Number;      // true

new String('3') instanceof String;    // true

new Boolean(true) instanceof Boolean; // true

Object(Symbol()) instanceof Symbol;   // true

({}) instanceof Object;               // true

[] instanceof Array;                  // true

(function(){}) instanceof Function;   // true

/./ instanceof RegExp;                // true

new Date() instanceof Date;             // true

new Error() instanceof Error;           // true

new Map() instanceof Map;               // true

new Set() instanceof Set;               // true

我们没有办法使用instanceof来检测基础类型,但是我们可先包装成对象类型在检测,但这样毫无意义;

2.6.4、toString.call()

Object中但toString()方法可以用来检测数据类型,我们先来看看。如何获取toString()方法

// 方法一:
var toString = {}.toString;
// 方法二(推荐使用第二种):
var toString = Object.prototype.toString;

我们来看看toString方法如何来获取各种值但类型;

toString.call(undefined);     // '[object Undefined]'

toString.call(null);          // '[object Null]'

toString.call(3);             // '[object Number]'

toString.call(true);          // '[object Boolean]'

toString.call('');            // '[object String]'

toString.call(Symbol());      // '[object Symbol]'

toString.call({});            // '[object Object]'

toString.call([]);            // '[object Array]'

toString.call(function(){});  // '[object Function]'

toString.call(/\w+/);         // '[object RegExp]'

toString.call(new Date);      // '[object Date]'

toString.call(new Error);     // '[object Error]'

toString.call(new Map);       // '[object Map]'

toString.call(new Set);       // '[object Set]'

我们可以封装该方法来进行值类型判断

var _toString = Object.prototype.toString;

function is(value, typeString) {
  // 获取到类型字符串
  var stripped = _toString.call(value).replace(/^\[object\s|\]$/g, '');
  return stripped === typeString;
}

虽然上面常见类型被检测是可以正确识别的,但是它不能正确识别自定义对象类型。

2.7、类型转化

2.7.1、其他类型转换为数字型

1、字符串转数字型

Number('');         // 0
Number('3');        // 3
Number('3.14');     // 3.14
Number('3.14dfdf'); // NaN
Number('ddd3.14'); // NaN
Number('dd3.14dfdf'); // NaN
Number('99 88'); // NaN
Number(' '); // 0
Number('0'); // 0

2、boolean型转换为数字型

Number(true);     // 1
Number(false);   // 0

3、null和undefined 转换为数字型

Number(undefined);  // NaN
Number(null);      // 0

3、数组转换为数字型

Number([]);            // 0
Number([1,1,2,3,4]);   // NaN

4、日期时间转换为数字型

Number(new Date());  // 1535286362647 
// 上面都方法等价于下面都方法
var d= new Date();
d.getTime();

除此以为转换为整数型都会变为NaN;

注意:还有两个转换为int和float都方法,其结果与Number某些地方不太一样

1.parseInt();

parseInt("adsfad3dfadf4") // NaN
parseInt("3.14dfdf")     // 3
parseInt(3.14)           // 3.14
parseInt([1,2,3,4,5])    // 1
parseInt(" ")            // NaN
parseInt("")             // NaN
parseInt([])              // NaN
parseInt({})             // NaN
parseInt(null)           // NaN
parseInt(undefined)     // NaN
parseInt(true) 	       // NaN
parseInt(false)        // NaN

2.parseFloat();

parseFloat("3.14") // 3.14
parseFloat("3.14dfdf")     // 3.14
parseFloat(3.14)           // 3.14
parseFloat([1,2,3,4,5])    // 1
parseFloat(" ")            // NaN
parseFloat("")             // NaN
parseFloat([])              // NaN
parseFloat({})             // NaN
parseFloat(null)           // NaN
parseFloat(undefined)     // NaN     

2.7.2、其他类型转换为字符串类型

new String(NaN)          // [String: 'NaN']
new String(Infinity)     // [String: 'Infinity']
new String(null)         // [String: 'null']
new String(undefined)    // [String: 'undefined']
new String(true)         // [String: 'true']
new String(false)        // [String: 'false']
new String(1)            // [String: '1']
new String(3.24)         // [String: '3.24']
new String({})           // [String: '[object Object]']
new String([1,2,3,4,5])  // [String: '1,2,3,4,5']
new String([])     		 // [String: '']
new String(new Date())   // [String: 'Sun Aug 26 2018 20:48:15 GMT+0800 (CST)']
new String(new Error())  // [String: 'Error']
new String(new Set)      // [String: '[object Set]']
new String(new Map)        // [String: '[object Map]']
new String(function fn(){}) // [String: 'function fn(){}']

2.7.4、其他类型转换为布尔型

Boolean(NaN)          // fasle
Boolean(Infinity)     // true
Boolean(-Infinity)     // true
Boolean(null)         // false
Boolean(undefined)    // false
Boolean(1)            // true
Boolean(3.24)         // true
Boolean(0)            // false
Boolean(-0)            // false
Boolean({})           // true
Boolean([1,2,3,4,5])  // true
Boolean([0])         // true
Boolean([])         // 、true
Boolean(function fn(){})  // true
Boolean(" ")  // true
Boolean("")  // false

Boolean("0")      // true
Boolean("fasle")  // true

Boolean(new Date())   // true
Boolean(new Error())  // true
Boolean(new Set())    // true
Boolean(new Map())   // true

猜你喜欢

转载自blog.csdn.net/fj_Author/article/details/82021722