JavaScript(Java脚本)是一种基于对象(Object)和事件驱动( Event Driven)并具有安全性能的脚本语言,使用JavaScript可以轻松的实现与HTML的互操作,并且完成丰富的页面交互效果,它是通过嵌入或调入在标准的HTML语言中实现的,它的出现弥补了HTML的缺陷,是java与HTML折衷的选择。
JavaScript基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
基于对象:
指的是程序的内部已经为用户提供好了若干个对象,用户直接使用这些对象即可。
面向对象:
java属于面向对象的语言,面向对象是指用户自己定义类,对象需要用户自己产生。
java与JavaScript没有关系。
1、 解释性
与其他脚本语言一样,JavaScript也是一种解释性语言,它提供了非常方便的开发过程。JavaScript的基本语法结构与C、C++、Java非常相似。
但是在使用之前,与这些语言不同,它们需要先被编译,但是在运行程序的过程中需要逐行解释。javascript与HTML标识符结合使用,方便操作。
2、基于对象
它也可以看作是一种面向对象的语言,这意味着JavaScript可以使用它创建的对象。因此,许多函数可以来自脚本环境中对象方法和脚本之间的交互。
3、简单而弱的类型
它的简单性主要体现在:第一,JavaScript是一个基于Java基本语句和控制流的简单而紧凑的设计,这是一个非常好的过渡,供用户学习Java或其他C语言编程语言。
而对于具有C语言编程能力的人来说,JavaScript非常容易使用,但是其不使用严格的数据类型。
对于JavaScript来说,其语法松散,且在编译阶段并不检查错误,在运行阶段如果有错才会报错。这对于大型的项目来说,编译阶段不报错,在运行的时候才崩溃报错,是很难找出错误的。
4、事件驱动
javascript以事件驱动的方式响应用户。通过在网页中执行操作生成的操作称为事件。例如,按下鼠标,移动窗口,选择菜单等都可以视为事件。
当一个事件发生时,它可能会引起相应的事件响应并执行一些相应的脚本。这种机制称为“事件驱动”。
变量
变量是对“值”的引用,使用变量等同于引用一个值。每一个变量都有一个变量名。
var a = 1;
上面的代码先声明变量a,然后在变量a与数值1之间建立引用关系,也称为将数值1“赋值”给变量a。以后,引用变量a就会得到数值1。最前面的var,是变量声明命令。它表示通知解释引擎,要创建一个变量a。
在js中,如果先将a赋值为数值类型,然后再将一个字符串类型赋给它,由于其松散的语法特性,也能够成功运行。
如果只是声明变量而没有赋值,则该变量的值是undefined。undefined是一个JavaScript关键字,表示“无定义”。
标识符
标识符(identifier)是用来识别具体对象的一个名称。最常见的标识符就是变量名,以及后面要提到的函数名。JavaScript语言的标识符对大小写敏感,所以a和A是两个不同的标识符。
标识符有一套命名规则,不符合规则的就是非法标识符。JavaScript引擎遇到非法标识符,就会报错。
简单说,标识符命名规则如下:
第一个字符,可以是任意字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
第二个字符及后面的字符,除了字母、美元符号和下划线,还可以用数字。
以下是不符合命名格式的字符
注意:
JavaScript有一些保留字,不能用作标识符:
arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。
操作符
操作符用于数据值,操作符包括算术操作符(如加号和减号)、位操作符、关系操作符和相等操作符等。JavaScript的操作符适用于很多值,例如字符串、数字值、布尔值,甚至对象。在应用于对象时,相应的操作符会调用对象的valueOf()和(或)toString()方法,来取得可以操作的值。
算术操作符 + - * / %
一元加和减操作符主要用于基本的算术运算,也可以用于转换数据类型
一元加操作符以一个加号(+)表示,放在数值前面 应用于数值时,对数值不会产生任何影响
在对非数值应用一元加操作符时,该操作符会像Number()转型函数一样对这个值执行转换
布尔值会转换成0和1,字符串值会按照一组特殊的规则进行解析,而对象是先调用它们的valueOf()和(或)toString()方法,在转换得到的值。
一元减操作符(-)主要用于表示负数 应用与数值时,表示负数
应用于非数值时,一元减操作符与一元加操作符相同的规则,最后在将得到的数值转换为负数
可以看到一个数字类型的变量和字符/字符串得到的结果是一个新的字符串,也就是将数字类型的变量自动转化成字符,添加到原来字符的尾部。
关系操作符 <> <=>= == === != !==
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)这几个关系操作符用于对两个值进行比较。这几个操作符都返回一个布尔值
操作非数值时,遵循下列规则 如果这两个操作数都是数值,则执行数值比较 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值
如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较
如果一个操作数是对象,则调用这个对象的valueOf()方法,并用得到的结果根据前面的规则执行比较
如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较
关于操作符的更多概念,可参考学习
JavaScript操作符
语句
avaScript程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。
语句(statement)是为了完成某种任务而进行的操作,比如下面就是一行赋值语句:
var a=1+3;
这条语句先用var命令,声明了变量a,然后将1 + 3的运算结果赋值给变量a。
1 + 3叫做表达式(expression),指一个为了得到返回值的计算式。语句和表达式的区别在于,前者主要为了进行某种操作,一般情况下不需要返回值;后者则是为了得到返回值,一定会返回一个值。
凡是JavaScript语言中预期为值的地方,都可以使用表达式。比如,赋值语句的等号右边,预期是一个值,因此可以放置各种表达式。一条语句可以包含多个表达式。
javaScript对程序流程的控制跟其他编程语言是一样的,主要有3种:
(1)顺序结构;
(2)选择结构;
(3)循环结构;
顺序结构表示程序中的各操作是按照它们出现的先后顺序执行的。
输入 0个或多个;
输出 1个或多个。
选择结构表示程序的处理步骤出现了分支,它需要根据某一特定的条件选择其中的一个分支执行。选择结构有单选择、双选择和多选择三种形式。
1、if-else结构
单分支结构
if(判断条件){
}
//双分支结构
if(判断条件){
}
else{
}
//多分支结构
if(判断条件){
}
else if(){
}
else{
}
switch-case结构
switch(判断条件){
case 表达式1:
代码;
break;
case 表达式2:
代码;
break;
case 表达式3:
代码;
break;
.......
default:代码
}
循环结构表示程序反复执行某个或某些操作,直到某条件为假(或为真)时才可终止循环。
循环:
求1到100之间奇数的和
var sum=0;
for(var i=0;i<=100;i++){
if(i%2==1){
sum+=i;
}
}
console.log(sum);
继续了解请参考
js三大结构:顺序结构,选择结构,循环结构
函数,就是一个一系列JavaScript语句的集合,这是为了完成某一个会重复使用的特定功能。在需要该功能的时候,直接调用函数即可,而不必每次都编写一大堆重复的代码。并且在需要修改该功能的时候,也只要修改和维护这一个函数即可。
总之,将语句集合成函数,好处就是方便代码重用。并且,一个好的函数名,可以让人一眼就知道这个函数实现的是什么功能,方便维护。
函数的使用只需要2步:
在JavaScript中,使用函数前,必须用function关键字来定义函数。
有两种常用的函数定义方式
不带函数名
function(参数1,参数2,….,参数n)
{
//函数体语句
}
带有函数名
function 函数名(参数1,参数2,….,参数n)
{
//函数体语句
return 表达式;
}
函数( function)对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。以下是一个函数示例:
function greet(name, message) {
console.log('Hello ' + name + ',' + message);
}
greet('licai', '你好,很高兴认识你');
JavaScript中的函数不必指定是否有返回值。
JavaScriptt 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。
也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而编译器也不会报错。
之所以会这样,原因是 JavaScriptt 中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓;如果包含多个元素,也没有问题。
如果在 JavaScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。实例如下:
JavaScript内部也提供了大量的内置函数,关于内置函数概念可参考
JavaScript 入门
现实生活中︰万物皆对象,对象是一个具体的事物,看得见摸得着的实物。例如,一本书、一辆汽车、一个人可以是“对象”,一个数据库、一张网页、一个与远程服务器的连接也可以是“对象”。
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的。
属性∶事物的特征,在对象中用属性来表示。
方法∶事物的行为,在对象中用方法来表示。
创建对象(object)有三种方式
以下是三种创建对象的方式
Math 是一个内置对象,它拥有一些数学常数属性和数学函数方法。Math 不是一个构造函数。所以我们不需要new来调用而是直接使用里面的属性和方法即可。
日期对象是一个构造函数,必须使用new来创建我们的日期对象。
创建时间对象,并且打印当前时间
var date = new Date(); //创建时间对象
console.log(date); //输出 Tue Aug 10 2021 22:55:00 GMT+0800 (中国标准时间)
字符串,是程序设计中经常使用的一种数据类型,在每一种编程语言中都非常非常的重要。
字符串对象string有很多方法,例如match()方法、search()方法、replace()方法等。
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。字符串索引值从0开始。
使用字符串对象进行增、删、改、查的操作
关于字符对象的更深入的了解,可参考
JavaScript之对象
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
创建数组有以下两种方法,一是new创建数组,二是数组字面量创建数组。我们常用数组字面量创建数组。如下所示
//方式一new
var colors = new Array('red', 'blue', 'green');
//方式二字面量
var colors = ['red', 'blue', 'green']; // 创建一个包含 3 个字符串的数组
console.log(colors[1]);
colors[3] = 'brown';
console.log(colors.length);
var names = []; // 创建一个空数组
var hyBird = [1, 2, 'haha', {firstName: 'Yong', lastName: 'Wang'}]; //不推荐!
console.log(hyBird[3].firstName);
常用的数组方法如下:
var colors = ['red', 'green', 'blue'];
console.log(colors.join(',')); //red,green,blue
console.log(colors.join('||')); //red||green||blue
使用连接字符串,将所有的数组元素通过连接字符串形成一个整体的字符串
栈是一种 LIFO(Last-In-First-Out,后进先出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入)和移除(叫做弹出),只发生在一个位置——栈的顶部。
JavaScript为数组专门提供了 push() 和 pop() 方法,以便实现类似栈的行为。可以轻易实现将开头字符或者结尾字符删除及添加。
var colors = []; // 创建一个数组
var count = colors.push('red', 'green'); // 末尾推入两项
console.log(count); //还有2个元素
colors.push('black'); // 末尾推入另一项
console.log(colors); //还有3个元素
var item = colors.pop(); // 末尾弹出最后一项
console.log(item); //'black'
console.log(colors); //还有2个元素
队列数据结构的访问规则是 FIFO(First-In-First-Out,先进先出),队列在列表的末端添加项,从列表的前端移除项。
由于 push() 是向数组末端添加项的方法,因此要模拟队列只需一个从数组前端取得项的方法。实现这一操作的数组方法就是 shift() ,它能够移除数组中的第一个项并返回该项,同时将数组长度减1。
同时,JavaScript还为数组提供了一个 unshift() 方法。它能在数组前端添加任意个项并返回新数组的长度。
push、pop、 unshift、shift的综合应用
var colors = new Array(); //创建一个数组
colors.push('red', 'green'); //推入两项
console.log(colors); //2
count = colors.push('black'); //推入另一项
console.log(colors); //3
var item = colors.shift(); // 前端弹出第一项,并记录下弹出的这一项
console.log(item); //'red'
console.log(colors);
var count = colors.unshift('purple', 'white'); // 推入另外两项
console.log(colors);
count = colors.unshift('green'); // 推入另一项
console.log(colors);
var item = colors.pop(); //后端弹出最后一项, 并记录
console.log(item); //'green'
console.log(colors);
总结:由上可知, push、pop操作在数组末尾,而 unshift、shift操作在数组首部;push、unshift压入而pop、shift弹出。
slice()
slice方法,可以传入两个参数,第一个参数表示起始位置,第二个参数表示终止位置,即slice(start,end),但是注意,这里是左闭右开,也就是说截取到的数组元素下标包括start,不包括end,这个方法不会改变原数组
var color = ['red', 'green', 'blue','white','green','black'];
let new_color = color.slice(0,2) //从arr中下标为0的开始,截取到下标为2的,但不包括下标为2的
console.log("截取下来的是:" + new_color)
console.log("原数组是:" + color)
可以看到,slice() 方法并没有影响原始数组。
splice()
splice方法可传入的参数有三个,第一个是起始位置(必需),第二个是删除几个,第三个是在原数组中截取下来的位置添加什么,这个方法会改变原数组
删除:可以删除任意数量的项,只需指定 2 个参数:要删除的第一项的位置和要删除的项数。 例如, splice(0,2)会删除数组中的前两项。
插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。例如, splice(2,0,‘red’,‘green’)会从当前数组的位置 2 开始插入字符串 ‘red’ 和 ‘green’ 。
替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如, splice (2,1,‘red’,‘green’)会删除当前数组位置 2 的项,然后再从位置 2 开始插入字符串 ‘red’ 和 ‘green’ 。
var colors = ['red', 'green', 'blue'];
var removed = colors.splice(0,1); // 删除第一项
console.log(colors); // green,blue
console.log(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, 'yellow', 'orange'); // 从位置 1 开始插入两项
console.log(colors); // green,yellow,orange,blue
console.log(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, 'red', 'purple'); // 插入两项,删除一项
console.log(colors); // green,red,purple,orange,blue
console.log(removed); // yellow,返回的数组中只包含一项
TypeScript给JavaScript加上可选的类型系统,给JavaScript加上静态类型后,就能将调试从运行期提前到编码期,诸如类型检查、越界检查这样的功能才能真正发挥作用。TypeScript的开发体验远远超过以往纯JavaScript的开发体验,无需运行程序即可修复潜在bug。
TypeScript支持未来的ES6甚至ES7。在TypeScript中,可以直接使用ES6的最新特性,在编译时它会自动编译到ES3或ES5。
TypeScript可以构建大型程序,并在任何浏览器、任何计算机和任何操作系统上运行,且是开源的。
安装好NodeJS后,以管理员身份运行终端,使用**npm -g install ts-node typescript
**命令进行全局安装
在vscode环境中,安装以下插件TSLint、TypeScript Hero、Bracket Pair Colorizer
等
ES6新增加了两个重要的 JavaScript 关键字: let 和 const。
let 声明的变量只在 let 命令所在的代码块内有效。
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量。
let和const的相同点:
let和const的不同点:
如:
打个比方说:
let x = 66;
x = 4;
这样子是可以的,因为let声明的变量是可以修改或者重新定义的。
再比如:
const x = 4;
x = 5;
这是错误的,因为const声明的变量是不可修改并且必须马上赋初值
参考
let和const的区别
将对象、数组中的元素拆分到指定变量中,以方便使用
交换变量
let a = 1;
let b = 2;
[a, b] = [b, a];
a; // => 2
b; // => 1
[a,b] = [b,a]
是解构赋值,右边,创建了一个数组[b, a],即[2,1]。这个数组2被赋值了给a,1被赋值给了b。
虽然这种方式也创建了临时数组,但这种方式给看起来至少更简洁,使用解构咱们还可以交换2个以上的变量。
解构数组
//解构数组
let input = [89, 64, 2018, 10];
let [first, second] = input;//注意使用[]
console.log(first); // 89
console.log(second); // 64
let [one, ...others] = input; //剩余变量
console.log(...others);
//展开
let newArr = [89, ...others, 18];
console.log(newArr);
解构对象
//解构对象
let o = {
a: "foo",
b: 12,
c: "bar"
};
let {a, b} = o;//注意使用{},且变量名需与对象中道属性名一致
console.log(a, b);
具体参考:
ES6 数组的解构赋值
数组解构、对象解构
使用完整函数定义
//命名函数,有完整的参数和返回类型。可以不用,TS将自动进行类型推断但推荐使用!
function add(x: number, y: number): number {
return x + y;
}
//匿名函数
let myAdd = function(x: number, y: number): number { return x + y; };
console.log(myAdd(1, '2'));//error
console.log(myAdd(1));//error
console.log(typeof myAdd(1, 2));//number
运行结果
箭头函数
使用ES6箭头函数语法定义函数,将原函数的“function”关键字和函数名都删掉,并使用“=>
”连接参数列表和函数体。
var fn1 = (a, b) => {
return a + b
}
(a, b) => {
return a + b
}
箭头函数相当于匿名函数
当函数参数只有一个,括号可以省略;但是没有参数时,括号不可以省略。
// 无参
var fn1 = function() {}
var fn1 = () => {}
// 单个参数
var fn2 = function(a) {}
var fn2 = a => {}
// 多个参数
var fn3 = function(a, b) {}
var fn3 = (a, b) => {}
// 可变参数
var fn4 = function(a, b, ...args) {}
var fn4 = (a, b, ...args) => {}
如果返回一个对象,需要特别注意,如果是单表达式要返回自定义对象,不写括号会报错,因为和函数体的{ … }有语法冲突。
注意,用小括号包含大括号则是对象的定义,而非函数主体
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:
箭头函数内部的this是词法作用域(块级作用域),由上下文确定。(词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变 。)
类是属性(有些什么)和函数(能干什么)的集合,是生成对象(Object)或类实例的模板。
类的定义和使用
我们使用class关键字来定义一个类,我们可以给类添加属性和方法。
//类的定义和使用
class MyInfo { //class是关键字,类名默认全部大写首字母
name: string; //属性
weather: string; //属性
constructor(name: string, weather: string){ //构造函数,一般用于初始化。如果没有,TS会自动生成一个,以备用new创建类实例时调用。
this.name = name;
this.weather = weather;
}
printInfo(): void { //其它函数,无返回值
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this.weather}.`);
}
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象,即该类的实例
myData.printInfo();
类的属性和函数的访问权限
类中的属性和函数都有访问权限,默认为public即全局可访问,其次为protected即可在类的内部和其子类的内部可访问,最后为private,只能在该类内部可访问。
//访问权限
class MyInfo { //class是关键字,类名默认全部大写首字母
public name: string; //public属性,可省略
private _weather: string; //私有属性,习惯以_开头进行命名
constructor(name: string, weather: string){ //构造函数,一般用于初始化
this.name = name;
this._weather = weather;
}
printInfo(): void { //其它函数
this._test();
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this._weather}.`);
}
private _test(): void {
console.log('You can not call me outside!');
}
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData._weather); //error!
myData._test(); //error
myData.printInfo();
类的继承
在ES6中,我们使用extends关键字来实现继承。在TS中,我们同样这么做。
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
}
}
class Student extends Person {
stuId: string
constructor(name: string, age: number, stuId: string) {
super(name, age);
this.stuId = stuId;
}
sayHello() {
super.sayHello();
console.log("I am a student!");
}
}
const s1 = new Student("xiaoming", 21, "W12138");
s1.sayHello();
在Person类的基础上面,通过继承方式实现了Student类,并且还增加了一个新属性stuId。
在Student构造函数中,使用super(…)调用父类的构造函数,在Student类里面重写了sayHello方法,里面通过super.sayHello()调用父类的sayHello.
使用继承,提高了代码的利用率,不必重复写一些冗余代码,在设计模式中有重要的地位。
存取器
TS的存取器类似JS使用Object.defineProperty设置setter,getter。当用户需要对对象属性的赋值取值操作进行额外处理的时候,可以借助存取器。
class Person {
firstName: string
lastName: string
private _fulllName: string
constructor(fn: string, ln: string) {
this.firstName = fn;
this.lastName = ln;
}
get fullName () {
this._fulllName = this.firstName + this.lastName;
return this._fulllName;
}
set fullName (name: string) {
let arr: string[] = name.split(" ");
this.firstName = arr[0];
this.lastName = arr[1];
}
}
const p = new Person("c", "yl");
console.log(p.fullName);
p.fullName = "xiao ming"
console.log(p.firstName, p.lastName);
当我们使用实例.fullName时实际上调用的get fullName函数,同样的使用实例.fullName = '…'时实际调用的是set fullName(…)。
具体参考
TypeScript – ts的类
本文主要介绍了JS和TS的基本语法知识,掌握了对象、数组、类的基本概念;通过ES6的标准,使得代码编写的更加规范,有利于在编译过程中排错。
本次总体梳理了以下学习JS和TS基本知识框架,对JS和TS也更加熟悉,不过由于是初学者,难免有些不当之处,敬请指教。
JavaScript——简介
javascript是什么?有哪些特点?
JavaScript基本语法
JavaScript操作符
JavaScript 入门
js三大结构:顺序结构,选择结构,循环结构
JavaScript之对象
String 类的replace方法替换字符串“无效”、“不起作用”原因
slice()和splice()
let和const的区别
ES6 数组的解构赋值
数组解构、对象解构
TypeScript – ts的类