目录
1. 初识JavaScript
1.1 JavaScript是什么
JavaScript(简称JS)
- 是世界上最流行的编程语言之一。
- 是一个脚本语言,通过解释器运行。
- 主要在客户端(浏览器)上运行,现在也可以基于node.js在服务器端运行。
JavaScript最初只是为了完成简单的表单验证(验证数据合法性),结果后来不小心就火了。
当前JavaScript已经成为了一个通用的编程语言。
JavaScript能做的事情:
- 网页开发(更复杂的特效和用户交互)
- 网页游戏开发
- 服务器开发(node.js)
- 桌面程序开发(Electron,VSCode就是这么来的)
- 手机app开发
1.2 发展历史
JavaScript之父 布兰登*艾奇(Brendan Eich)
1.3 JavaScript和HTML和CSS之间的关系
- HTML:网页的结构(骨)
- CSS:网页的表现(皮)
- JavaScript:网页的行为(魂)
1.4 JavaScript运行过程
- 编写的代码是保存在文件中,也就是存储在硬盘(外存上)。
- 双击.html文件浏览器(应用程序)就会读取文件,把文件内容加载到内存中(数据流向:硬盘->内存)。
- 浏览器会解析用户编写的代码,把代码翻译成二进制的,能让计算机识别的指令(解释器的工作)。
- 得到的二进制指令会被CPU加载并执行(数据流向:内存->CPU)。
浏览器分成渲染引擎+JS引擎。
- 渲染引擎:解析HTML+CSS,,俗称“内核”。
- JS引擎:也就是JS解释器,典型的就是Chrome中内置的V8。
JS引擎逐行读取JS代码内容,然后解析成二进制指令,再执行。
1.5 JavaScript的组成
- ECMAScript(简称ES):JavaScript语法。
- DOM:页面文档对象模型,对页面中的元素进行操作。
- BOM:浏览器对象模型,对浏览器窗口进行操作。
光有JS语法,只能写一些基础的逻辑流程。
但是想要完成跟复杂的过程,完成和浏览器以及页面的交互,那么久需要DPM API和BOM API。
这主要指在浏览器端运行的JS,如果是运行在服务器端的JS,则需要使用node.js的API。
就不要需要关注DOM和BOM。
重要概念:ECMAScript
这是一套“标准”,无论是啥样的JS引擎都需要遵守这个标准来实现。
2. 前置知识
2.1 第一个程序
<script>
alert("你好!");
</scrip
JavaScript代码可以嵌入到HTML的script标签中。
2.2 JavaScript的书写形式
2.2.1 行内式
直接嵌入到HTML元素内部。
<input type="button" value="点我一下" onclick="alert('haha')">
注意,JS中字符串常量可以使用单引号表示,也可以使用双引号表示。
HTML中推荐使用双引号,JS中推荐使用单引号。
2.2.2 内嵌式
写到script标签中
<script>
alert("haha");
</script>
2.2.3 外部式
写到单独的.js文件中。
<script src="hello.js"></script>
alert("hehe");
注意,这种情况下script标签中间不能写代码,必须空着(写了代码也不会执行)。
适合代码多的情况。
2.3 注释
单行注释//【建议使用】
多行注释/**/
// 我是单行注释
/*
我是多行注释
我是多行注释
我是多行注释
*/
使用ctrl+/切换注释
多行注释不能嵌套,形如这种代码就会报错。
/*
/*
我是多行注释
我是多行注释
我是多行注释
*/
*/
2.4 输入输出
输入:prompt
弹出一个输入框
// 弹出一个输入框
prompt("请输入您的姓名:");
输出:alert
弹出一个警示对话框,输出结果。
// 弹出一个输出框
alert("hello");
输出:console.log
在控制台打印一个日志(供程序员看)
// 向控制台输出日志
console.log("这是一条日志");
注意:在VSCode中直接输入“log”再按tab键,就可以快速输入“console.log”
需要打开浏览器的开发者工具(F12)=>Console标签页,才能看到结果。
这样的输出一般不是给普通用户观看的,而是给程序员看的。
重要概念:日志
日志是程序员调试程序的重要手段。
重要概念:
console是一个js中的“对象”。
. 表示取对象中的某个属性或者方法,可以直观理解成“的”。
console.log就可以理解成;使用“控制台”对象“的”log方法。
3. 语法概览
JavaScript虽然一些设计理念和Java相去甚远,但是在基础语法层面上还是有一些相似之处的,有了Java的基础很容易理解JavaScript的一些基本语法。
3.1 变量的使用
3.1.1 基本用法
创建变量(变量定义/变量声明/变量初始化)
var name = 'zhangsan';
var age = 20;
var是JS中的关键字,表示这是一个变量。
=在JS中表示“赋值”,相当于把数据放到内存的盒子中.=两侧建议有一个空格。
每个语句最后都带有一个;结尾.JS中可以省略;但是建议还是加上。
注意,此处的;为英文分号.JS中所有的标点都是英文标点。
初始化的值如果是字符串,那么就要使用单引号或者双引号引起来。
初始化的值如果是数字,那么直接赋值即可。
使用变量
console.log(age); // 读取变量内容
age = 30; // 修改变量内容
为什么动漫中的角色都要先喊出技能名字再真正释放技能?
就是因为变量要先声明才能使用。
代码示例:弹框提示用户输入信息,再弹框显示。
var name = prompt("请输入姓名:");
var age = prompt("请输入年龄:");
var score = prompt("请输入分数");
alert("您的姓名是: " + name);
alert("您的年龄是: " + age);
alert("您的分数是: " + score);
也可以把三个内容合并成一次弹框
var name = prompt("请输入姓名:");
var age = prompt("请输入年龄:");
var score = prompt("请输入分数");
alert("您的姓名是: " + name + "\n" + "您的年龄是: " + age + "\n" + "您的分数是: " +
score + "\n");
- +表示字符串拼接,也就是把两个字符串首尾相接变成一个字符串。
- \n表示换行。
JavaScript中还支持使用let定义变量。用法和var基本类似,用法上的差异此处展示不讨论。
3.1.2 理解动态类型
(1)JS的变量类型是程序员运行过程中才确定的(运行到=语句才会确定类型)
var a = 10; // 数字
var b = "hehe"; // 字符串
(2)随着程序运行,变量的类型可能会发生改变。
var a = 10; // 数字
a = "hehe"; // 字符串
这一点和C Java这种静态语言类型差异较大。。
C,C++,Java,Go等语言是静态类型语言,一个变量在创建的时候类型就确定了,不能在运行时发生改变。
如果尝试改变,就会直接编译报错。
3.2 基本数据类型
JS中内置的几种类型:
- number:数字,不区分整数和小数。
- Boolean:true真,false假。
- String:字符串类型。
- undefined:只有唯一的值undefined。表示未定义的值。
- null:只有唯一的值null,表示空值。
3.2.1 number数字类型
JS中不区分整数和浮点数,统一使用“数字类型”来表示。
数字进制表示
计算机中都是使用二进制来表示数据,而人平时都是使用十进制。
因为二进制在使用过程中不太方便。(01太多会看花眼)。
所以日常在使用二进制数字时往往使用八进制和十六进制来表示二进制数字。
var a = 07; // 八进制整数, 以 0 开头
var b = 0xa; // 十六进制整数, 以 0x 开头
var c = 0b10; // 二进制整数, 以 0b 开头
注意:
- 一个八进制数字对应三个二进制数字。
- 一个十六进数字对应四个二进制数字。(两个十六进制数字就是一个字节)。
各种进制之间的转换,不需要手工计算,直接使用计算器即可。
特殊的数字值
- Infinity:无穷大,大于任何数字。表示数字已经超过了JS能表示的范围。
- -Infinity:负无穷大。小于任何数字。表示数字已经超过了JS么么和表示的范围。
- NaN:表示当前的结果不是一个数字。
var max = Number.MAX_VALUE;
// 得到 Infinity
console.log(max * 2);
// 得到 -Infinity
console.log(-max * 2);
// 得到 NaN
console.log('hehe' - 10);
注意:
- 负无穷大和无穷小不是一回事,无穷小无限趋近于0.值为1/Infinity。
- ‘hehe’+10得到的不是NaN,而是‘hehe10’,会把数字隐式转换成字符串,再进行字符串拼接。
- 可以使用isNaN函数判定是不是一个非数字。
console.log(isNaN(10)); // false
console.log(isNaN('hehe' - 10)); // true
3.2.2 String字符串类型
基本规则
字符串字面值需要使用引号引起来,单引号双引号均可。
var a = "haha";
var b = 'hehe';
var c = hehe; // 运行出错
如果字符串本来已经包含引号怎么办?
var msg = "My name is "zhangsan""; // 出错
var msg = "My name is \"zhangsan\""; // 正确, 使用转义字符. \" 来表示字符串内部的引
号.
var msg = "My name is 'zhangsan'"; // 正确, 搭配使用单双引号
var msg = 'My name is "zhangsan"'; // 正确, 搭配使用单双引号
转义字符
有些字符不方便直接输入,于是要通过一些特殊方式来表示。
- \n
- \\
- \'
- \''
- \t
求长度
使用String的length属性即可。
var a = 'hehe';
console.log(a.length);
var b = '哈哈';
console.log(b.length);
结果:
4
2
单位为字符的数量
字符串拼接
使用+进行拼接
var a = "my name is ";
var b = "zhangsan";
console.log(a + b);
注意,数字和字符串也可以进行拼接
var c = "my score is ";
var d = 100;
console.log(c + d);
注意,要认准相加的变量到底是字符串还是数字
console.log(100 + 100); // 200
console.log('100' + 100); // 100100
3.2.3 Boolean布尔类型
表示“真”和“假”
Boolean原本是数学中的概念(布尔函数)
在计算机及中Boolean意义重大,往往要搭配条件/循环完成逻辑判断。
Boolean参与运算时当做0和1来看待。
console.log(true + 1);
console.log(false + 1)
这样的操作是不科学的,实际开发中不应该这么写。
3.2.4 undefined未定义数据类型
如果一个变量没有被初始化过,结果就是underlined,是underlined类型。
var a;
console.log(a)
underlined和字符串进行相加,结果进行字符串拼接。
console.log(a + "10"); // undefined10
underlined和数字进行相加,结果为NaN。
console.log(a + 10);
3.2.5 null空值类型
null表示当前的变量是一个“空值”。
var b = null;
console.log(b + 10); // 10
console.log(b + "10"); // null10
注意:
null和underlined都表示取值非法的情况,但是侧重点不同。
null表示当前的值为空。(相当于有一个空的盒子)
underlined表示当前的变量未定义。(相当于连盒子都没有)
3.3 运算符
算数运算符
- +
- -
- *
- /
- %
赋值运算符&复合赋值运算符
- =
- +=
- -=
- /=
- %=
自增自减运算符
- ++:自增1
- --:自减1
比较运算符
- <
- >
- <=
- >=
- ==比较相等(会进行隐式类型转换)
- !=
- ===比较相等(不会进行隐式类型转换)
- !==
逻辑运算符
用于计算多个boolean表达式的值。
- &&与:一假则假
- ||或:一真则真
- !非
位运算
- $按位与
- |按位或
- ~按位取反
- ^按位异或
移位运算
- <<左移
- >>有符号右移(算术右移)
- >>>无符号右移(逻辑右移)
4. 条件语句
4.1 if语句
4.1.1 基本语法格式
条件表达式为true,则执行if的{}中的代码
// 形式1
if (条件) {
语句
}
// 形式2
if (条件) {
语句1
} else {
语句2
}
// 形式3
if (条件1) {
语句1
} else if (条件2) {
语句2
} else if .... {
语句...
} else {
语句N
}
练习案例:
代码示例1:判定一个数字是奇数还是偶数
var num = 10;
if (num % 2 == 0) {
console.log("num 是偶数");
} else {
console.log("num 是奇数");
}
注意!不能写成num%2==1就是奇数,负的奇数%2结果可能就是-1.
代码示例2:判定一个数字是正数还是负数。
var num = 10;
if (num > 0) {
console.log("num 是正数");
} else if (num < 0) {
console.log("num 是负数");
} else {
console.log("num 是 0");
}
代码示例3:判定某一年份是否是闰年
var year = 2000;
if (year % 100 == 0) {
// 判定世纪闰年
if (year % 400 == 0) {
console.log("是闰年");
} else {
console.log("不是闰年");
}
} else {
// 普通闰年
if (year % 4 == 0) {
console.log("是闰年");
} else {
console.log("不是闰年");
}
}
4.1.2 三元表达式
是 if else 的简化写法
条件?表达式1:表达式2
条件为真,返回表达式1的值,条件为假,返回表达式2的值。
注意,三元表达式的优先级是比较低的。
4.2 Switch
更适合多分支的场景。
switch (表达式) {
case 值1:
语句1;
break;
case 值2:
语句2:
break;
default:
语句N;
}
用户输入一个整数,提示今天是星期几
var day = prompt("请输入今天星期几: ");
switch (parseInt(day)) {
case 1:
console.log("星期一");
break;
case 2:
console.log("星期二");
break;
case 3:
console.log("星期三");
break;
case 4:
console.log("星期四");
break;
case 5:
console.log("星期五");
break;
case 6:
console.log("星期六");
break;
case 7:
console.log("星期日");
break;
default:
console.log("输入有误");
}
5. 循环语句
重复执行某些循环
5.1 while 循环
while (num <= 10) {
console.log(num);
num++;
}
执行过程:
- 先执行条件语句。
- 条件为true,执行循环体代码。
- 条件为false,直接结束循环。
代码示例1:打印1-10
var num = 1;
while (num <= 10) {
console.log(num);
num++;
}
代码示例2:计算5的阶乘
var result = 1;
var i = 1;
while (i <= 5) {
result *= i;
i++;
}
console.log(result)
5.2 continue
结束这次循环
吃五个李子,发现第三个李子里有一只虫子,于是扔掉这个,继续吃下一个李子。
var i = 1;
while (i <= 5) {
if (i == 3) {
i++;
continue;
}
console.log("我在吃第" + i + "个李子");
i++;
}
我在吃第1个李子
我在吃第2个李子
我在吃第4个李子
我在吃第5个李子
代码示例:找到100-200中所有3的倍数。
var num = 100;
while (num <= 200) {
if (num % 3 != 0) {
num++; // 这里的 ++ 不要忘记! 否则会死循环.
continue;
}
console.log("找到了 3 的倍数, 为:" + num);
num++;
}
5.3 break
结束整个循环
吃五个李子,发现第三个李子里有半个虫子,于是剩下的也不吃了。
var i = 1;
while (i <= 5) {
if (i == 3) {
break;
}
console.log("我在吃第" + i + "个李子");
i++;
}
我在吃第1个李子
我在吃第2个李子
代码示例:找到100-200中的第一个3的倍数
var num = 100;
while (num <= 200) {
if (num % 3 == 0) {
console.log("找到了 3 的倍数, 为:" + num);
break;
}
num++;
}
// 执行结果
找到了 3 的倍数, 为:102
5.4 for循环
for (表达式1; 表达式2; 表达式3) {
循环体
}
- 表达式1:用于初始化循环变量。
- 表达式2:循环条件。
- 表达式3:更新循环变量。
执行过程:
- 先执行表达式1,初始化循环变量。
- 再执行表达式2,判定循环条件。
- 如果条件为false,结束循环。
- 如果条件为true,则执行循环体代码。
- 执行表达式3,更新循环变量。
代码示例1:打印1-10的数字
for (var num = 1; num <= 10; num++) {
console.log(num);
}
代码示例2:计算5的阶乘
var result = 0;
for (var i = 1; i <= 5; i++) {
result *= i;
}
console.log("result = " + result);
6. 数组
6.1 创建数组
使用new关键字创建。
// Array 的 A 要大写
var arr = new Array();
使用字面量方式创建(常用)。
var arr = [];
var arr2 = [1, 2, 'haha', false]; // 数组中保存的内容称为 "元素"
注意:JS的数组不要求元素是相同类型
这一点和C,C++,java等静态类型的语言差别很大,但是Python,PHP等动态语言也是如此。
6.2 获取数组元素
使用下标的方式访问数组元素(从0开始)
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '小猫凯迪';
console.log(arr);
如果下标超出范围读取元素,则结果为underlined
console.log(arr[3]); // undefined
console.log(arr[-1]); // undefined
注意:不要给数组名直接赋值,此时数组中的所有元素都没了。
相当于本来arr是一个数组,重新赋值后就变成了字符串了。
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
arr = '小猫凯迪';
6.3 新增数组元素
1. 通过修改length新增
相当于在末尾新增元素,新增的元素默认值为underlined。
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
2. 通过下标新增
如果下标超出范围赋值元素,则会给指定位置插入新元素。
var arr = [];
arr[2] = 10;
console.log(arr)
此时这个数组的【0】和【1】都是underlined。
3. 使用push进行追加元素
代码示例:给定一个数组,把数组中的奇数放到一个newArr中。
var arr = [9, 5, 2, 7, 3, 6, 8];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
newArr.push(arr[i]);
}
}
console.log(newArr);
6.4 删除数组中的元素
使用splice方法删除元素
var arr = [9, 5, 2, 7];
// 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个
arr.splice(2, 1);
console.log(arr);
// 结果
[9, 5, 7]
目前咱们已经用到了数组中的一些属性和方法。
arr.length,length使用的时候不带括号,此时length就是一个普通的变量(称为成员变量,也叫属性)。
arr.push(),arr.splice()使用的时候带括号,并且可以传参数,此时是一个函数(也叫做方法)。
7. 函数
7.1 语法格式
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
- 函数定义并不会执行函数体内容,必须要调用才会执行,调用几次就会执行几次。
function hello() {
console.log("hello");
}
// 如果不调用函数, 则没有执行打印语句
hello();
- 调用函数的时候进入函数内部执行,函数结束时回到调用位置继续执行,可以借助调试器来观察。
- 函数的定义和调用的先后顺序没有要求。(这一点和变量不同,变量必须先定义再使用)。
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
7.2 关于参数个数
实参和形参之间的个数可以不匹配,但是实际开发一般要求实参和形参个数要匹配。
(1)如果实参个数比形参个数多,则多出的参数不参与函数运算。
sum(10, 20, 30); // 30
(2)如果实参个数比形参个数少,则此时多出来的形参值为underlined。
sum(10); // NaN, 相当于 num2 为 undefined.
JS的函数传参比较灵活,这一点和其他语言差别较大,事实上这种灵活性往往不是好事。
7.3 函数表达式
另外一种函数的定义方式
var add = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add(10, 20)); // 30
console.log(add(1, 2, 3, 4)); // 10
console.log(typeof add); // function
此时形如function(){}这样的写法定义了一个匿名函数,然后将这个匿名函数用一个变量来表示。后面就可以通过这个add变量来调用函数了。
JS中函数是一等公民,可以用变量保存,也可以作为其他函数的参数或者返回值。
7.4 作用域
某个标识符名字在代码中的有效范围。
在ES6标准之前,作用域主要分成两个:
- 全局作用域:在整个script标签内,或者单独的js文件中生效。
- 局部作用域/函数作用域:在函数内部生效。
// 全局变量
var num = 10;
console.log(num);
function test() {
// 局部变量
var num = 20;
console.log(num);
}
function test2() {
// 局部变量
var num = 30;
console.log(num);
}
test();
test2();
console.log(num);
// 执行结果
10
20
30
10
创建变量时如果不写var,则得到一个全局变量。
function test() {
num = 100;
}
test();
console.log(num);
// 执行结果
100
另外,很多语言的局部变量作用域是按照代码块(大括号)来划分的,js在ES6之前不是这样的。
if (1 < 2) {
var a = 10;
}
console.log(a);
7.5 作用域链
背景:
- 函数可以定义在函数内部。
- 内层函数可以访问外层函数的局部变量。
内部函数可以访问外部函数的变量,采取的是链式查找的方式,从内到外依次进行查找。
var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
// 执行结果
20
执行console.log(num)的时候,会先在test2的局部作用域中查找num,如果没找到,则继续去test1中查找,如果还没找到,就会去全局作用域查找。
8. 对象
8.1 基本概念
对象是指一个具体的事物。
“电脑”不是对象,而是一个泛指的类别,而“我的联想笔记本”就是一个对象。
在JS中,字符串,数值,函数,数组都是对象。
每个对象中包含若干的属性和方法。
- 属性:事物的特征。
- 方法:事物的行为。
对象需要保存的属性有多少个,虽然数组也能用于保存多少个数据,但是不够好。
JavaScript的对象和Java的对象概念上基本一致,只是具体的语法表现形式差别较大。
8.1.1 使用 字面量 创建对象【常用】
使用{}创建对象
var a = {}; // 创建了一个空的对象
var student = {
name: '张三',
height: 175,
weight: 170,
sayHello: function() {
console.log("hello");
}
}
- 使用{ }创建对象。
- 属性和方法使用键值对的形式来组织。
- 键值对之间使用,分割,最后一个属性后面的,可有可无。
- 键和值之间使用:分割。
- 方法的值是一个匿名函数。
使用对象的属性和方法:
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
8.1.2 使用new Object创建对象
var student = new Object(); // 和创建数组类似
student.name = "张三";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {
console.log("hello");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
注意,使用{ }创建的对象也可以随时使用student.name=“张三”;这样的方式来新增属性。
8.1.3 使用 构造函数 来创建对象
前面的创建对象方式只能创建一个对象,而使用构造函数可以很方便的创建多个对象。
例如:创建几个猫咪对象。
var mimi = {
name: "咪咪",
type: "中华田园喵",
miao: function () {
console.log("喵");
}
};
var xiaohei = {
name: "小黑",
type: "波斯喵",
miao: function () {
console.log("猫呜");
}
}
var ciqiu = {
name: "刺球",
type: "金渐层",
miao: function () {
console.log("咕噜噜");
}
}
此时写起来就比较麻烦,使用构造函数可以把相同的属性和方法的创建提取出来,简化开发过程。
基本语法:
function 构造函数名(形参) {
this.属性 = 值;
this.方法 = function...
}
var obj = new 构造函数名(实参);
注意:
- 在构造函数内部使用this关键字来表示当前正在构建的对象。
- 构造函数的函数名首字母一般是大写的。
- 构造函数的函数名可以是名词。
- 构造函数不需要return。
- 创建对象的时候必须使用new关键字。
this相当于“我”
使用构造函数重新创建猫咪对象
function Cat(name, type, sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound); // 别忘了作用域的链式访问规则
}
}
var mimi = new Cat('咪咪', '中华田园喵', '喵');
var xiaohei = new Cat('小黑', '波斯喵', '猫呜');
var ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
console.log(mimi);
mimi.miao();
8.2 理解new关键字
new的执行过程:
- 先在内存中创建一个空的对象{ }
- this指向刚才的空对象(将上一步的对象作为this的上下文)
- 执行构造函数的代码,给对象创建属性和方法。
- 返回这个对象(构造函数本身不需要return,由new代劳了)。
8.3 JavaScript的对象和Java的对象的区别
1.JavaScript没有“类”的概念
对象其实就是“属性+方法”。
类相当于把一些具有共性的对象的属性和方法单独提取了出来,相当于一个“月饼模子”。
在JavaScript中的“构造函数”也能起到类似的效果。
而且即使不是用构造函数,也可以随时的通过{ }方式指定出一些对象。
在ES6中也引入了class关键字,就能按照类似于Java的方式创建类和对象了。
2. JavaScript对象不区分“属性”和“方法”
JavaScript中的函数是“一等公民”,和普通的变量一样,存储了函数的变量能够通过( )来进行调用执行。
3. JavaScript对象没有private/public等访问控制机制。
对象中的属性都可以被外界随意访问。
4.JavaScript对象没有“继承”
继承本质就是“让两个对象建立关联”。或者说是让一个对象能够重用另一个对象的属性/方法。
JavaScript中使用“原型”机制实现类似的效果。
例如:创建一个cat对象和dog对象,让这两个对象都能使用Animal对象中的eat方法。
通过_proto_属性来建立这种关联关系(proto翻译作“原型”)。
当eat方法被调用的时候,先在自己的方法列表中寻找,如果找不到,就去找原型中的方法,如果原型中找不到,就去原型的原型中去寻找……最后找到Object哪里,如果还找不到,那就是未定义了。
5. JavaScript没有“多态”
多态的本质在于“程序员不必关注具体的类型,就能使用其中的某个方法”。
C++/java等静态类型的语言对于类型的约束和校验比较严格。因此通过了子类继承父类,并重写父类的方法的方式来实现多态的效果。
但是在JavaScript中本身就支持动态类型,程序员在使用对象的某个方法的时候本身也不许哟啊对对象的类型做出明确的区分,因此并不需要在语法层面上支持多态。
例如:
在Java中已经学过ArrayList和LinkedList,为了让程序员方便,往往写作List<String> list = newArrayList<>( )
然后我们可以写一个方法:
void add(List<String> list, String s) {
list.add(s);
}
我们不必关注list是ArrayList还是LInkedList,只要是List就行,因为List内部带有add方法。
当我们使用JavaScript的代码的时候
function add(list, s) {
list.add(s)
}
add对于List这个参数的类型本身就没有任何限制,只要list这个对象有add方法即可,就不必像Java那样先继承再重写绕一个圈子。