语法
语法上并无特殊之处,只是末尾的分好可以省略,执行JavaScript代码的引擎会自动在每个语句的结尾补上,但是不建议省略!!!
strict模式
1、强制使用var来声明变量
avaScript在设计之初,为了方便初学者学习,并不强制要求用var申明变量。这个设计错误带来了严重的后果:如果一个变量没有通过var申明就被使用,那么该变量就自动被申明为全局变量:
i = 10; // i现在是全局变量
在同一个页面的不同的JavaScript文件中,如果都不用var申明,恰好都使用了变量i,将造成变量i互相影响,产生难以调试的错误结果。
使用var申明的变量则不是全局变量,它的范围被限制在该变量被申明的函数体内(函数的概念将稍后讲解),同名变量在不同的函数体内互不冲突。
为了修补JavaScript这一严重设计缺陷,ECMA在后续规范中推出了strict模式,在strict模式下运行的JavaScript代码,强制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。
2、
数据类型和变量
1、number
js中number不区分整数和浮点数,统一用Number表示,其中nan表示Not a Number,当无法计算结果时用NaN表示,Infinity表示无限大
123; // 整数123
0.456; // 浮点数0.456
1.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5
-99; // 负数
NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示
Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity
2、==相等运算符
要特别注意相等运算符==。JavaScript在设计时,有两种比较运算符:
第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。
由于JavaScript这个设计缺陷,不要使用==比较,始终坚持使用===比较。
另一个例外是NaN这个特殊的Number与所有其他值都不相等,包括它自己:
NaN === NaN; // false
唯一能判断NaN的方法是通过isNaN()函数:
isNaN(NaN); // true
3、浮点数的比较
1 / 3 === (1 - 2 / 3); // false
这不是JavaScript的设计缺陷。浮点数在运算过程中会产生误差,因为计算机无法精确表示无限循环小数。要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值:
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
4、null和undefined
null表示一个“空”的值,它和0以及空字符串''不同,0是一个数值,''表示长度为0的字符串,而null表示“空”。
在其他语言中,也有类似JavaScript的null的表示,例如Java也用null,Swift用nil,Python用None表示。但是,在JavaScript中,还有一个和null类似的undefined,它表示“未定义”。
JavaScript的设计者希望用null表示一个空的值,而undefined表示值未定义。事实证明,这并没有什么卵用,区分两者的意义不大。大多数情况下,我们都应该用null。undefined仅仅在判断函数参数是否传递的情况下有用。
字符串
字符串可以使用单引号,也可以使用双引号,但是如果字符串中包含但引号,则可以使用双引号括起来,或者使用转义字符:
console.log("i'm ok!");
console.log('i\'m ok!');
1、转义字符的特殊使用
转义字符\可以转义很多字符,比如\n表示换行,\t表示制表符,字符\本身也要转义,所以\表示的字符就是\。
ASCII字符可以以\x##形式的十六进制表示,例如:
'\x41'; // 完全等同于 'A'
还可以用\u####表示一个Unicode字符:
'\u4e2d\u6587'; // 完全等同于 '中文'
2、多行字符串
ES6中,``(数字1左边的那个符号)可以使用多行字符串,其中还可以添加变量:
console.log(`多行
字符串
测试`);
var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
alert(message);
3、字符串拼接
使用+号拼接,或者使用在``中使用模板字符串,即在里面使用${}来拼接,如下:
var name = 'Jack';
var age = 20;
console.log('my name is ' + name +',我' + age + '岁了');
console.log(`my name is ${name},我${age}岁了`);
结果:
[Running] node "/Users/caoxk/Dev/JS/test/.vscode/test.js"
my name is Jack,我20岁了
my name is Jack,我20岁了
[Done] exited with code=0 in 0.078 seconds
4、字符串具有索引
要获取字符串某个指定位置的字符,使用类似Array的下标操作,索引号从0开始,如果超过索引,不会报错,会返回undefined:
s[0]; // 'H'
s[6]; // ' '
s[7]; // 'w'
s[12]; // '!'
s[13]; // undefined 超出范围的索引不会报错,但一律返回undefined
3、字符串是不可变
字符串是不可变的,不可变包含两层意义:
1、如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果;
2、JavaScript为字符串提供了一些常用方法,注意,调用这些方法本身不会改变原有字符串的内容,而是返回一个新字符串;
举个栗子:
var s = 'Test';
s[0] = 'X';
alert(s); // s仍然为'Test'
var s = 'Hello';
var lower = s.toLowerCase(); // 返回'hello'并赋值给变量lower
lower; // 'hello'
var s = 'hello, world';
s.indexOf('world'); // 返回7
s.indexOf('World'); // 没有找到指定的子串,返回-1
数组
1、JavaScript的数组可以包括任意数据类型:
例如:
[1, 2, 3.14, 'Hello', null, true];
2、array的索引的特殊之处
可以通过索引改变array中的元素,但是如果越界,不仅不会报错,还会改变array的大小,即length,中间未被赋值的元素将为undefined:
var array = [1,2,3,'4','5'];
array[10] = '10';
console.log(array);
console.log(array.length);
console.log(array[6]);
结果:
[ 1, 2, 3, '4', '5', <5 empty items>, '10' ]
11
undefined
3、操作array
尾部增删:pop、push
头部增删:unshift、shift
万能方法:splice
注意:空数组pop(在尾部删)、shift(在头部删)都不会报错,操作之后仍然为空数组
举个栗子:
var arr1 = [1, 2];
arr1.pop();arr1.pop();arr1.pop();
console.log();
var arr = [1, 2];
arr.unshift('A', 'B'); // 返回Array新的长度: 4
console.log(arr);
arr.shift(); // 'A'
console.log(arr);
arr.shift(); arr.shift(); arr.shift(); // 连续shift 3次
console.log(arr);
结果:
[ 'A', 'B', 1, 2 ]
[ 'B', 1, 2 ]
[]
splice万能方法的第一个参数为开始删除的index,第二个参数为删除的个数,后面的参数为添加的元素,举个栗子:
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.splice(0, 2); // 包括0这个index
console.log(arr);
console.log(arr2); // 返回的被截取的元素所组成的数组
arr.splice(10, 0, 'a', 'b');
console.log(arr); // 超过length时从最后一个元素开始算起
console.log(arr.length);
结果:
[ 3, 4, 5 ]
[ 1, 2 ]
[ 3, 4, 5, 'a', 'b' ]
5
注意:splice是万能增删方法,而slice是数组截取方法,其用法如下:
1、第一个参数是start索引,第二个参数是end索引(splice第二个参数是个数),但是slice的截取包含start不包含end
2、slice如果传参为空则截取整个数组
3、slice方法改变原数组
举个栗子:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var aCopy = arr.slice();
aCopy; // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
aCopy === arr; // false
默认排序:sort
自定义排序:
反转:reverse
拼接:concat
array转string:join
使用指定的字符串连接数组各个元素,如果元素不是string类型,先转换成string之后再拼接,举个栗子:
var arr = ['A', 'B', 'C', 1, 2, 3];
var result = arr.join('-'); // 'A-B-C-1-2-3'
console.log(arr);
console.log(result);
结果:
[ 'A', 'B', 'C', 1, 2, 3 ]
A-B-C-1-2-3
x、array的高阶函数
高阶函数的定义:
x、array属性相关
对象可以添加属性,array也可以,虽然在原理本质上,array中的元素是绑定到array对象的属性中,但是array添加属性后不计入到length中,举个栗子:
var array = [1,2,3,'4','5'];
array.name = '10';
console.log(array);
console.log(array.length);
结果:
[Running] node "/Users/caoxk/Dev/JS/test/.vscode/test.js"
[ 1, 2, 3, '4', '5', name: '10' ]
5
[Done] exited with code=0 in 0.06 seconds
对象
1、对象的表现形式
JavaScript的对象是一组由键-值组成的无序集合,例如:
var person = {
name: 'Bob',
age: 20,
tags: ['js', 'web', 'mobile'],
city: 'Beijing',
hasCar: true,
zipcode: null
};
person.name; // 'Bob'
person.zipcode; // null
x、js中只有实例对象,没有类对象
js也是面向对象编程,即一切皆对象。number、string、boolean、function和undefined有别于其他类型。特别注意null的类型是object,Array的类型也是object,如果我们用typeof将无法区分出null、Array和通常意义上的object——{}。
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
x、js中通过原型(prototype)来实现面向对象编程
js中没有类对象这个概念,使用_proto来继承一个对象,如下:
var Student = {
name: 'jack',
height: 170.
};
console.log('the height of ' + Student.name + 'is ' + Student.height);
var lucy = {
name: 'lucy'
};
lucy.__proto__ = Student;
console.log(lucy.height);
但是实际情况中不要直接用obj.proto去改变一个对象的原型,Object.create()方法可以传入一个原型对象,并创建一个基于该原型的新对象,但是新对象什么属性都没有,因此,我们可以编写一个函数来创建并初始化自己所需要的对象,如下:
function createStudent(name, height) {
var s = Object.create(Student);
s.name = name;
s.height = height;
return s;
}
var john = createStudent('john', 180);
console.log(john.height);
x、对象层级关系
当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined,例如:
// array
arr ----> Array.prototype ----> Object.prototype ----> null(准确来说是{}这个空对象)
// func
foo ----> Function.prototype ----> Object.prototype ----> null(准确来说是{}这个空对象)
上面的原型链的意思是:
arr这个对象的原型对象指向Array这个对象,而Array这个对象的原型对象指向的是Boject这个对象,Object对象的原型对象指向为{}这个空对象,空对象中不存在的属性,相当于未定义的变量,自然返回验证如下:
console.log(Object.prototype.prototype);
console.log(Object.prototype);
结果:
undefined
{}
网友评论