目录
1.0如果想将JavaScript写到一对head标签中,并且需要在JavaScript代码中操作界面上的元素,就必须要加上:
47.0 JavaScript isPrototypeOf属性
1.0如果想将JavaScript写到一对head标签中,并且需要在JavaScript代码中操作界面上的元素,就必须要加上:
window.onload = function () {
操作界面元素的JavaScript代码
}
2.0 JavaScript常用的输出方式
语法 | 注意 |
alert(需要输出的内容) | 1.0如果输出的是非数字要加双引号或单引号括起来; 2.0JavaScript严格区分大小写 3.0每一句JavaScript代码后面都要添加一个英文的分号 |
confirm(需要输出的内容) | |
prompt(需要输出的内容) |
语法 | 注意 |
document.write(需要输出的内容) | 1.0如果输出的是非数字要加双引号或单引号括起来; |
语法 | 注意 |
console.log(需要输出的内容) | 普通输出 |
console.warn(需要输出的内容) | 警告输出 |
console.error(需要输出的内容) | 错误输出 |
3.0JavaScript中的常量
类型 | 解释 |
整型常量 | 正数,如1 , 22 , 55 , 56 |
实型常量 | 小数,如1.2 , 223.3 |
字符串常量 | 字符串常量就是用双引号或单引号括起来的内容,如"123", "abc" |
布尔常量 | 布尔常量即真和假 true和false |
自定义常量 | 在ES6中新增的, const 常量名 = 常量值 自定义常量被定义后就不可以再更改. |
4.0JavaScript的变量
类型 | 解释 | 语法 |
变量 | 变量表示一些可以被更改的数据 | 变量声明: ES6之前 var 变量名; ES6之后 let 变量名; |
注: let声明的变量是唯一的,如果重新定义同名的变量,会报错. var 声明的变量如果重新声明,后面的会覆盖前面的,不会报错.
通过var定义的变量,可以先使用,后定义(预解析),let则不能先使用后定义.
5.0JavaScript的关键字和保留字
abstract | arguments | boolean | break | byte |
case | catch | char | class* | const |
continue | debugger | default | delete | do |
double | else | enum* | eval | export* |
extends* | false | final | finally | float |
for | function | goto | if | implements |
import* | in | instanceof | int | interface |
let | long | native | new | null |
package | private | protected | public | return |
short | static | super* | switch | synchronized |
this | throw | throws | transient | true |
try | typeof | var | void | volatile |
while | with | yield |
6.0JavaScript的标识符命名规则
只能有英文字母,阿拉伯数字,下划线,美元符号组成,但不能以数字开头,且严格区分大小写,不能使用关键字和保留字作为标识符.
7.0HTML和JavaScript的注释
HTML | <!-- --> |
JavaScript | 单行注释 // 多行注释 /* */ |
注:多行注释不能嵌套多行注释,多行注释可以嵌套单行注释;单行注释可以嵌套单行注释或多行注释,但必须是同一行.
8.0检测JavaScript的数据类型
typeof 需要检测的数据 | 如: let res = tpyeof 123 将123的数据类型保存在res的变量中 |
9.0JavaScript基本数据类型
数据类型 | 解释 |
Number数值类型 | 在JavaScript中 整数 和小数都属于number数值类型注:NaN属于Number类型 |
Boolean 布尔类型 | 在JavaScript中布尔类型只有false和true两个取值 |
String 字符串类型 | 通过单引号或双引号括起来的内容都属于字符串类型 |
Undefined 未定义类型 | 在JavaScript中未定义类型比较特殊,只有一个取值undefined |
Null 空类型 |
注:NaN属于Number类型
数据类型 | 解释 |
Object 对象类型 |
10.0 基本数据类型转换为字符串类型
数据类型 | 转换为字符串类型String |
Number数值类型 | 变量名称.toString() String(常量 or 变量) 常量/变量 + " "/' ' |
Boolean 布尔类型 | 变量名称.toString() String(常量 or 变量) 常量/变量 + " "/' ' |
Undefined 未定义类型 | String(常量 or 变量) 常量/变量 + " "/' ' |
Null 空类型 | String(常量 or 变量) 常量/变量 + " "/' ' |
11.0 基本数据类型转换为数值类型
数据类型 | 转换为数值类型 |
String 字符串类型 | Number(常量 or 变量) 注:如果字符串为空/无数据/都为空格,则转换后的值为0,字符串中有字母,这转换后的数值为NaN,字符串为数字则正常转换.
通过 +/- (正负号) 将字符串类型转换为数值类型,但对于纯数字的字符串 - (负号)会改变数值的正负性 ,带其他字符的字符串则被转换为 NaN 注: 常量字符串也可以通过这种方式转换(如: let a = +"123" 常量字符串123,会被转换为数值123)
parseInt(需要转换的字符串) or parseFloat(需要转换的字符串) 该方法都是从左到右开始提取数字,遇到非数字则停止提取
|
Boolean 布尔类型 | Number(常量 or 变量) true 转换后为 1 false 转换后为 0
通过 +/- (正负号) 将字布尔类型转换为数值类型, +(正号):true 被转换为 1 ; false 被转换为 0 -(负号)则相反
parseInt(布尔类型) or parseFloat(布尔类型),其被转换为 NaN |
Undefined 未定义类型 | Number(常量 or 变量) 转换之后为 NaN
通过 +/- (正负号) 将未定义类型转换为数值类型, 其被转换为 NaN
parseInt(undefined) or parseFloat(undefined),其被转换为 NaN |
Null 空类型 | Number(常量 or 变量) 转换后为 0
通过 +/- (正负号) 将空类型转换为数值类型, 其被转换为 0
parseInt(null) or parseFloat(null),其被转换为 NaN |
注:parseInt() or parseFloat() 无论括号中是何种数据类型,都会被当做字符串来处理
12.0基本数据类型转换为布尔类型 Boolean(常量 or 变量)
数据类型 | 转换为布尔类型 |
Number数值类型 | Boolean(数值) 只有数值为0,才会被转换为false, 注:如果是NaN也会被转换为 false |
String字符串类型 | Boolean(字符串),只要字符串有内容(空格也算内容),则被转换为true |
Undefined 未定义类型 | Boolean(undefined),被转换为 false |
Null 空类型 | Boolean(null), 被转换为 false |
注: 空字符串/0/undefined/null/NaN 都会被转换为 false,其它的都会被转换为 true.
13.0JavaScript算术运算符
任何数据与NaN进行运算结果都是NaN.
加法:任何数据与字符串相加,都会先把数据转换成字符串类型,最后再做字符串拼接.
减法:任何数据与字符串相减,都会先把字符串转换为数值类型,再运算.
除法/乘法:与减法的注意点一样.
取模: m%n = 余数 如果 m>n 则正常取余;如果 m<n 则结果是m;如果n为0,则结果为NaN; 注取余结果的正负性取决于m.
14.0关系运算符注意点
null == 0 | false |
undefined == 0 | false |
null == undefined | true |
NaN == NaN | false |
注:要判断某个数字是否为NaN可以通过函数来判断 如:
任何数据和NaN进行比较,返回值都是false |
== | 只会判断取值是否相等,不会判断数据类型是否相等,只要取值相等,返回值就位true |
=== | 不仅会判断取值是否相等,并且会判断数据类型是否相等,只有取值和数据类型都相等,返回值才为true |
!= | 只会判断取值是否相等,不会判断数据类型是否相等,只要取值不相等,返回值就位true |
!== | 不仅会判断取值是否相等,并且会判断数据类型是否相等,取值或数据类型只要有一项不相等,返回值就为true |
15.0JavaScript逻辑运算符
逻辑运算符名称 | 语法 | 返回值 | 特点 |
逻辑与 && | 条件表达式A && 条件表达式B | true false | 一假则假
在逻辑与中,若参与运算的不是布尔类型,返回值有一个特点: 如果条件A不成立,那么就返回条件A 如果条件A成立,无论条件B是否成立都返回条件B
逻辑与运算存在逻辑短路现象,当条件A为假,则条件B就不参与运算了 |
逻辑或 || | 条件表达式A || 条件表达式B | true false | 一真则真
在逻辑或中,若参与运算的不是布尔类型,返回值有一个特点: 如果条件A成立,那么就返回条件A 如果条件A不成立,无论条件B是否成立都返回条件B
逻辑或运算存在逻辑短路现象,当条件A为真,则条件B就不参与运算了 |
逻辑非 ! | ! 条件表达式 | true false | 真变假,假变真 |
注:逻辑运算符的优先级是左结合性(从左到右的运算),逻辑运算符的优先级 && 高于 ||
16.JavaScript逗号运算符
逗号运算符的作用是用来简化代码
- 逗号运算符的结合性是左结合(从左到右的运算)
- 逗号运算符是所有运算符中优先级最低的运算符
- 逗号运算符的运算结果就是最后一个表达式的结果.
var a = ((1+1),(2+3),(5+5)); console.log(a); //输出结果为 10
17.0JavaScript三目运算符
条件表达式 ? 结果A : 结果B | 条件表达式为真,则返回结果A,条件表达式为假,则返回结果B |
18.0JavaScript数组
数组:引用数据类型(对象类型)
语法:let/var 变量名 = new Array(size) size:数组的长度.
创建数组的方式
let / var 变量名 = new Array(size) | 创建一个指定大小的数组 |
let / var 变量名 = new Array() | 创建一个空数组 |
let / var 变量名 = new Arrary(数据1,数据2,数据3, ...) | 创建一个带数据的数组 |
let / var 变量名 = [] | 创建一个空数组 |
let / var 变量名 = [数据1,数据2,数据3, ...] | 创建一个带数据的数组 |
数组解构赋值:
var ls = [1,2,3]; var a,b,c; [a,b,c] = ls; // a=1 b=2 c=3
注意:
1.在数组的解构赋值中,等号左边的格式可以和等号右边的格式不一样,也能被完全解析
var a,b,c; [a,b,c] = [1,2,[3,4]]; // a=1 b=2 c=[3,4]
2.在数组的解构赋值中,等号左右两边的个数可以不一样.
var a,b,c,d; [a,b] = [1,2,3,4,5]; // a=1 b=2 [a,b,c,d] = [1,2,3]; // a=1 b=2 c=3 d=undefined
3.在数组的解构赋值中,若右边个数大于左边的个数,可以给左边的变量指定赋值.
var a,b,c,d; [a,b,c=666,d=123] = [1,2]; // a=1 b=2 c=666 d=123 [a,b,c=666,d=123] = [1,2,3]; // a=1 b=2 c=3 d=123 设置的默认值被覆盖
4.在数组的解构赋值中,可以利用ES6新增加等扩展运算符来打包剩余的数据. 注:扩展运算符只能写在最后
扩展运算符 扩展运算符 ... var a,b; [a, ...b] = [1,2,3]; // a=1 b=[2,3]
注意点:
- 如果数组对应的索引中没有存储数据,默认存储的是undefined;
- 访问了数组中不存在的索引,不会报错,会返回undefined;
- 当数组的存储空间不够用,数组会自动扩容
- 数组中可以存储不同类的数据类型.
- 数组分配的存储空间不一定是连续的.
19.0数组的增删改查
-
修改
定义和用法
splice() 方法从数组中添加/删除数据,然后返回被删除的数组。
注释:该方法会改变原始数组。
语法
array.splice(index,howmany,item1,.....,itemX)
参数 | 描述 |
---|---|
index | 必需。整数,规定添加/删除项目的起始位置,使用负数可从数组结尾处规定位置。 |
howmany | 必需。要删除/添加的数据数量。如果设置为 0,则不会删除/添加数据。 |
item1, ..., itemX | 可选。向数组添加的数据。 |
返回值
类型 | 描述 |
---|---|
Array | 如果存在被删除的数据,返回被替的数据,如果没有则返回一个空数组 |
var array = [1,2,3,5];
console.log(array.splice(0, 1)); // array[1] 返回被删除的元素 原始数组变为[2,3,5]
console.log(array.splice(10, 2)); // array[] 返回一个空数组 原始数组变为[1,2,3,5]
说明
splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值(item1, ..., itemX)来替换那些被删除的元素。
2.在数组最后增加一条数据
定义和用法
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
语法
array.push(item1,item2 ..., itemX)
参数 | 描述 |
---|---|
item1 | 必需。要添加到数组的第一个元素。 |
item2 | 可选。要添加到数组的第二个元素。 |
itemX | 可选。可添加多个元素。 |
var array = [1,2,3];
console.log(array.push(123456)); //返回 4
返回值
返回数组array的新长度。
说明
push() 方法可把它的参数顺序添加到 array 的尾部。它直接修改 array,而不是创建一个新的数组。push() 方法和 pop() 方法使用数组提供的先进后出栈的功能。
提示和注释
注释:该方法会改变数组的长度。
提示:要想数组的开头添加一个或多个元素,可以使用 unshift() 方法。
3.在数组最前面增加数据
使用unshift() 方法 用法与push() 方法一样,返回值也是新数组的长度.
4.删除数组最后一条数据
使用pop()方法,返回值为所删除的数据
5.删除数组最前面一条数据
使用shift()方法,返回值为所删除的数据
6.删除数组指定索引数据
splice() 方法 splice(index,1) index 需要删除的数据的索引下标
方法 | 描述 | 返回值 |
splice() | 在数组的指定位置,增加/删除/替换数据 | 如果存在被删除的数据,返回被删除的数据,如果没有则返回一个空数组 |
push() | 在数组末尾增加数据 | 返回数组的新长度 |
unshift() | 在数组最前面增加数据 | 返回数组的新长度 |
pop() | 删除数组最后一条数据 | 返回值为所删除的数据 |
shift() | 删除数组最前面一条数据 | 返回值为所删除的数据 |
7.清空数组
let array = [1,2,3,5,6,7,8];
/*方法一*/
array = [];
/*方法二*/
array.length = 0;
/*方法三*/
array.splice(0,array.length);
8.将数组转换为字符串
let array = [1,2,3,5,6];
let str = array.toString(); // 1,2,3,4,5,6
9.将数组转换为指定格式的字符串
let array = [1,2,3,5,6];
/*join()方法默认情况下无任何参数,实际上就是调用toString()方法*/
let str = array.join(); // 1,2,3,5,6
/*join()方法传递了参数,就会将传递的参数作为元素和数组元素的连接符号*/
let str = array.join("*"); // 1*2*3*5*6
10.将两个或多个数组拼接为一个数组
注:数组不能使用加号+进行数组的拼接.
方法一:concat()方法用于数组的拼接.
语法:
array.concat(数组1,数组2,数组3...)
返回值:返回一个新数组,且不改变原来的数组.
方法二: ES6新增加的方法
扩展运算符(...):扩展运算符在解构赋值中(等号的左边),表示将剩余的数据打包成一个新的数组.
扩展运算符在等号的右边,表示将数组中的所有数据解开,放到对应的位置中.
let array1 = [1,2,3];
let array2 = [7,8,9];
let array = [...array1, ...array2] // Array(6) [ 1, 2, 3, 7, 8, 9 ]
20.0 将数组反转
reverse()方法:
let array = [1,2,3]; let str = array.reverse(); console.log(str); // Array(3) [ 3, 2, 1 ] console.log(array); // Array(3) [ 3, 2, 1 ]
注:reverse()方法会修改原有的数组
21.0 数组的切片
slice()方法:
array.slice(start,end)
参数 描述 start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。 end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。 返回值
返回一个新的数组,包含从 start 到 end (不包括该元素)的 array中的元素。
注:slice()方法不会修改原数组,而是返回一个新数组。如果想删除数组中的一段元素,应该使用方法 array.splice()。
22.0 查找元素在数组中的位置
indexOf()方法
array.indexOf(value,startindex)
参数 描述 value 必需。规定需检索的字符串值。 startindex 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 array.length - 1。如省略该参数,则将从字符串的首字符开始检索。 返回值:如果数组中存在该元素,则返回该元素对应的位置,如果数组中不存在该元素,则返回 -1。
注:indexOf()方法默认从左到右查找,找到第一个符合条件的就会停止查找.lastIndexOf(value,startindex)方法默认从右到左查找
23.0 判断数组是否包含某个元素
- 通过index(value)value和lastIndexOf(value)的结果来判断,返回值为-1则不存在.
- ES6方法:array.includes(value),返回值为true或false
24.0 数组清零
fill() 方法用于将一个固定值替换数组的元素。
语法
array.fill(value, start, end)
参数
参数 描述 value 必需。填充的值。 start 可选。开始填充位置。 end 可选。停止填充位置 (默认为 array.length) 返回值:返回一个数组,会改变原来的数组.
25.0 arguments的作用
保存所有传递给函数的实参
function getSum() {
// console.log(arguments);
let res = 0;
for(let i=0;i<arguments.length;i++){
res += arguments[i];
}
return res;
}
res = getSum(10,20,30);
console.log(res); // 60
26.0 函数扩展运算符
扩展运算符在等号的左边,将剩余数据全部打包到一个新数组中 注:只能写在最后 |
|
扩展运算符在等号的右边,将数组中的数据展开 |
|
扩展运算符在函数形参列表中,将传递给函数的所有实参打包到一个数组中 注:只能写在形参列表的最后 |
|
27.0 函数默认形参
函数的默认形参为:undefined
- 在ES6之前可以通过逻辑运算符给形参指定默认值
逻辑或 || | 条件表达式A || 条件表达式B | true false | 一真则真
在逻辑或中,若参与运算的不是布尔类型,返回值有一个特点: 如果条件A成立,那么就返回条件A 如果条件A不成立,无论条件B是否成立都返回条件B
逻辑或运算存在逻辑短路现象,当条件A为真,则条件B就不参与运算了 |
function getSum(a,b,c) {
a = a || 10;
b = b || 20;
console.log(a, b, c);
}
getSum(); // a = 10 b = 20 c = undefined
2. 在ES6之后
在ES6之后可以直接给形参指定默认值
function getSum(a=10,b=20,c) {
console.log(a, b, c);
}
getSum(); // a = 10 b = 20 c = undefined
注:在ES6之后函数形参的指定值还可以从其他函数中获取
function getSum(a=10,b=20,c=getSum1()) {
console.log(a, b, c);
}
function getSum1(){
return "JavaScript";
}
getSum(); //a = 10 b = 20 c = JavaScript
28.0 匿名函数
定义:没有名称的函数
注:匿名函数不能只定义不使用
作为其它函数的参数 |
|
作为其它函数的返回值 |
|
作为一个立即执行的函数 | 注:匿名函数如果要立即执行,就必须使用括号()将匿名函数包裹起来 |
29.0 箭头函数 (ES6新增的函数)
ES6之前 | 支持预解析 | 不支持预解析 |
ES6之后 | 不支持预解析 | 注:
|
30.0 JavaScript变量作用域
- 通过var定义的变量,可以重复定义同名的变量,且后定义的会覆盖先定义的.
- 通过let定义的变量,在"相同的作用域内",不可以重复定义同名的变量.
- 通过var定义的变量可以先使用后定义(预解析),但通过let定义的变量不可用先使用后定义.
- 无论是var/let定义的变量,在{}外面都是全局变量.
- 但将var定义的变量放到一个{}内,还是一个全局变量,将let定义的变量放到一个{}内,它是一个局部变量.
- 在JavaScript中,函数{}内的作用域为局部作用域
- 在ES6中,只要{}没有和函数结合在一起,都应该是块级作用域
- 无论是块级作用域还是局部作用域,省略了变量前的var/let,都会变成一个全局变量.
- 在块级作用域中通过var定义的变量是全局变量,通过let定义的变量是局部变量,
- 在局部作用域中用var/let定义的变量是局部变量.
31.0JavaScript作用域链
ES6之前:
- 在ES6之前定义变量通过var
- 在ES6之前没有块级作用域,只有全局作用域和局部作用域
- 在ES6之前,函数大括号{}外的都是全局作用域
- 在ES6之前函数大括号{}内的都是局部作用域
ES6之前的作用域链
- 全局作用域,被称为0级作用域
- 定义函数开始的作用域就是1级,2级,3级...作用域
- JavaScript会将这些作用域链接成一个链条,这个链条就是作用域链 0--> 1 --> 2 -->3
- 除开0级作用域外,当前作用域级别等于上一层+1
变量在作用域链的查找规则
- 先在当前作用域中查找,如果找到则使用当前作用域中的
- 如果在当前作用域中没有找到,就去上一级作用域中查找
- 以此类推,直到0级作用域为止,如果0级作用域也找不到,则会报错
ES6:
- ES6定义变量通过let
- ES6除了全局作用域,局部作用域,还新增加了块级作用域
- ES6虽然新增加了块级作用域,但通过let定义的变量,并没有差异
ES6作用域链
- 全局作用域,被称为0级作用域
- 定义函数或者代码块都会开启的作用域就是1级,2级,3级...作用域
- JavaScript会将这些作用域链接成一个链条,这个链条就是作用域链 0--> 1 --> 2 -->3
- 除开0级作用域外,当前作用域级别等于上一层+1
变量在作用域链的查找规则
- 先在当前作用域中查找,如果找到则使用当前作用域中的
- 如果在当前作用域中没有找到,就去上一级作用域中查找
- 以此类推,直到0级作用域为止,如果0级作用域也找不到,则会报错
32.0 创建对象
给对象添加属性 : 对象名称.属性名称 = 值
给对象添加行为: 对象名称.行为名称 = 函数
let 对象名称 = new Object(); |
|
let 对象名称 = {}; |
|
let 对象名称 = {属性名称:值, 行为名称:函数} |
|
33.0 JavaScript的函数和方法的区别
函数:函数是没有和其它的类显示的绑定在一起的.
方法:方法是显示的和其它的类显示的绑定在一起的.
区别:
- 函数可以直接调用;但方法不可用直接调用,只能通过对象来调用.
- 函数和方法内部都有一个this语句.(谁调用了当前的函数或方法,当前的this就是谁)
- 函数内部的this输出的是window,方法内部的this输出的是当前调用的那个对象
34.0 工厂函数
定义:工厂函数专门用于创建对象的函数,
function student(name,age) {
let obj = new Object();
obj.name = name;
obj.age = age;
obj.say = function () {
console.log("hello" + obj.name);
};
return obj;
}
let res1 = student("小明",18);
let res2 = student("张三",20);
console.log(res1);
console.log(res2);
35.0 构造函数
定义:构造函数和工厂函数一样,都是专门用于创建对象的,构造函数本质上是工厂函数的简写.
构造函数与工厂函数的区别:
- 构造函数的函数名首字母必须大写
- 构造函数只能通过new来调用
function Student(name,age) {
//系统默认在此处自动添加 let obj = new Object();
this.name = name;
this.age = age;
this.say = function () {
console.log("hello" + this.name);
}
// 系统自动在末尾添加 return this;
}
let res1 = new Student("小明",18);
let res2 = new Student("小米",20);
console.log(res1);
console.log(res2);
console.log(res1.say === res2.say); // false 不共用一个存储空间
注:
- 当我们 let res1 = new Student("小明",18); 系统默认在构造函数里面自动添加 let obj = new Object();
- 会自动将刚才创建的对象赋值给this
- 会在构造函数的末尾自动添加return this;
function mysay() {
console.log("hello word");
}
function Student(name,age) {
this.name = name;
this.age = age;
this.say = mysay;
}
let res1 = new Student("小明",18);
let res2 = new Student("小米",20);
console.log(res1.say === res2.say); // true 共用一个存储空间
优化一
let obj = {
say:function () {
console.log("hello word");
}
}; //创建一个对象,用于解决占用全局命名匮乏的问题
function Student(name,age) {
this.name = name;
this.age = age;
this.say = obj.say;
}
let res1 = new Student("小明",18);
let res2 = new Student("小米",20);
console.log(res1.say === res2.say); // true 共用一个存储空间
优化二
function Student(name,age) {
this.name = name;
this.age = age;
}
Student.prototype = {
say:function () {
console.log("hello word");
}
};
let res1 = new Student("小明",18);
let res2 = new Student("小米",20);
console.log(res1.say === res2.say); // true 共用一个存储空间
prototype用于添加保存公共的函数或公共的变量
语法 object.prototype.name=value
object.prototype = {属性:值,方法} 用逗号隔开
注:
- 存储在prototype中的方法可以被对应的构造函数创建出来的所有对象共享prototype
- prototype中除了可以存储方法,也可以存储属性
- prototype如果出现和构造函数同名的方法或属性,对象在访问的时候,访问到的是构造函数中的方法或属性.
prototype应用场景
- prototype中一般情况下用于存储所有对象都拥有的一些共同属性或方法,如果是对象特有的属性或方法,则应该存储在构造函数中
36.0 对象三角恋关系
- 每一个"构造函数"中都有一个默认属性prototype, prototype属性保存着一个对象,这个对象被称之为"原型对象"
- 每个"原型对象"中都有一个默认属性constructor, constructor属性指向当前原型对象对应的那个"构造函数"
- 通过构造函数创建出来的对象,被称为"实例对象",每个实例对象中都有一个默认属性,该属性被称为 __proto__, __proto__指向创建它的那个构造函数的原型对象
![](https://img-blog.csdnimg.cn/20191010193928860.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjc4MjIy,size_16,color_FFFFFF,t_70)
37.0 Function函数
- JavaScript中函数时引用类型(对象类型),既然是对象,那也是通过构造函数创建出来的,所有函数都是通过Function构造创建出来的对象.
- JavaScript中只要是函数就有prototype属性,"Function函数"的prototype属性指向"Function原型对象"
- JavaScript中只要是"原型对象"就会有constructor属性,"Function原型对象"的constructor指向它对应的构造函数
38.0 Object函数
![Object函数](https://img-blog.csdnimg.cn/20191010194856952.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNjc4MjIy,size_16,color_FFFFFF,t_70)
39.0 函数对象完整关系
注意点:
- Function函数时所有函数的祖先函数
- 所有构造函数都有prototype属性
- 所有原型对象都有constructor属性
- 所有函数都是对象
- 所有对象都有一个__proto__属性
40.0原型链
注:在给一个对象设置不存在的属性值的时候,不会去原型对象中查找,它会给当前对象新增加一个不存在的属性.
function Student(name,age) { this.name = name; this.age = age; } Student.prototype = { constructor:Student, say:function () { console.log("hello word"); }, sex:"女", }; let res1 = new Student("小明",18); res1.sex = "男"; console.log(res1.sex); //男 console.log(res1.__proto__.sex); //女
41.0 JavaScript继承性
方法一
语法:
构造函数名.prototype = new 被继承的构造函数名;
构造函数名.prototype.constructor = 构造函数名
function Person() { this.name = null; this.age = 0; this.say = function () { console.log(this.name,this.age); } } Student.prototype = new Person(); //Student()构造函数继承了Person()构造函数的name,age属性和say()方法 Student.prototype.constructor = Student; function Student() { this.sex = null; this.score = 100; this.test = function () { console.log("test"); } } let zhang = new Student(); zhang.name = "zhang"; zhang.age = 18; zhang.say(); zhang.test();
方法二
注:bind方法,call方法,apply方法,都是用于修改函数或方法中的this的
bind方法,call方法,apply方法
方法 作用 语法 示例 bind修改函数或方法中this所指定的对象,并且会返回一个修改之后的新的函数,
bind方法除了可以修改this,还可以传递参数,但参数必须写在this对象的后面.
let 新建对象名 = 对象名1.bind(对象名2,参数)
注:参数用逗号隔开
function text(a,b) { console.log(a, b); console.log(this); } let obj = { name :"张三", age:18, }; let fn = text.bind(obj,10,20); fn();
call
修改函数或方法中this所指定的对象,且会立刻调用修改之后的函数,
bind方法除了可以修改this,还可以传递参数,但参数必须写在this对象的后面.
对象名1.call(对象名2,参数)
注:参数用逗号隔开
text.call(obj,10,200);
apply
修改函数或方法中this所指定的对象,且会立刻调用修改之后的函数,
apply方法除了可以修改this,还可以传递参数,但参数必须写在this对象的后面,且通过数组的形式传递.
对象名1.apply(对象名2,[参数])
注:参数放到数组里
text.apply(obj,[10,200]);
function Person(Myname,Myage) { this.name = Myname; this.age = Myage; this.say = function () { console.log(this.name,this.age); } } function Student(Myname,Myage,Myscore) { Person.call(this,Myname,Myage); //方法二弥补了方法一继承时无法传参的情况 this.sex = null; this.score = Myscore; this.test = function () { console.log("test"+this.score); } } let stu = new Student("张三",18,100); // 等价于如下语句 /* let stu = new Student(); stu.name = "张三"; stu.age = 18; stu.score = 100;*/ stu.say(); stu.test();
方法三
方法三:主要是用于解决方法二,无法继承原型对象中的属性和方法的问题.
注:要想使用Person原型对象中的属性和方法,那么就必须要将Student的原型对象修改为Person的原型对象
function Person(Myname,Myage) { this.name = Myname; this.age = Myage; /*this.say = function () { console.log(this.name,this.age); }*/ } // 将say方法独立出来 Person.prototype.say =function () { console.log(this.name,this.age); } ; // 将Student的原型对象修改为Person的原型对象 Student.prototype = Person.prototype; Student.prototype.constructor = Student; function Student(Myname,Myage,Myscore) { Person.call(this,Myname,Myage); this.sex = null; this.score = Myscore; this.test = function () { console.log("test"+this.score); } } let stu = new Student("张三",18,100); /*stu.name = "张三"; stu.age = 18; stu.score = 100;*/ stu.say(); stu.test();
方法四
解决方法三由于修改了Person原型对象的constructor的属性,所以破坏了Person的三角恋关系,由于Person和Student的原型对象都是同一个,所以给Student的元素添加方法,Person也会新增加方法.
function Person(Myname,Myage) { this.name = Myname; this.age = Myage; /*this.say = function () { console.log(this.name,this.age); }*/ } // 将say方法独立出来 Person.prototype.say =function () { console.log(this.name,this.age); } ; Student.prototype = new Person(); //Student.prototype = Person.prototype; Student.prototype.constructor = Student; function Student(Myname,Myage,Myscore) { Person.call(this,Myname,Myage); this.sex = null; this.score = Myscore; this.test = function () { console.log("test"+this.score); } } Student.prototype.run=function () { console.log("run"); }; let per = new Person(); let stu = new Student("张三",18,100); /*stu.name = "张三"; stu.age = 18; stu.score = 100;*/ per.run(); //报错
方法:
- 在子类的构造函数中通过call借助父类的构造函数 Person.call(this,Myname,Myage);
- 将子类的原型函数对象修改为父类的实例对象 Student.prototype = new Person(); Student.prototype.constructor = Student;
42.0JavaScript多态
强类型语言:一般编译语言都是强类型语言,要求变量的定义要严格符合定义
弱类型语言:一般解释语言都是弱类型语言,不会严格要求变量的使用要严格符合定义
多态在编程语言中的体现:父类型变量保存子类型对象,父类型变量当前保存的对象不同,产生的结果也不同.
43.0JavaScript类和对象
在ES6前通过构造函数来定义类,从ES6开始,通过关键字class来定义类
语法:
注:不能通过static直接定义静态属性(大多数浏览器不支持),需要通过 类名.属性名 = 属性值 Person.sex = "男"
class Person{ //实例属性 name = "张三"; //不是Es6推荐的写法 age = 18; //实例方法 say(){ console.log(this.name,this.age); } //静态属性/方法通过类名调用 如 Person.num Person.run() //静态属性 static num = 123; // 火狐浏览器不支持此方法 //静态方法 static run(){ console.log("run"); } } let per = new Person(); //创建实例对象 per.say(); console.log(Person.num);//调用静态属性 console.log(Person.run());//调用静态方法
class Person{ //当通过new创建对象的时候,系统会自动调用constructor constructor(myName,myAge){ this.name = myName; this.age = myAge; } say(){ console.log(this.name, this.age); } } let per = new Person("张三",18); per.say();
在原型对象中保存属性和方法
方法一:
Person.prototype.sex = "男";
Person.prototype.hi = function () {
console.log("hello");
};
方法二:
44.0 JavaScriptES6继承
语法 class 类名 extends 被继承的类名{}
示例
class Person{
constructor(myName,myAge){
this.name = myName;
this.age = myAge;
}
say(){
console.log(this.name,this.age);
}
}
//以下代码含义:告诉浏览器Student这个类将继承Person这个类
class Student extends Person{
constructor(myName,myAge,myScore){
//在子类中通过call/apply方法借助父类的构造函数
super(myName,myAge);//等效于 Person.call(this,myName,myAge);
this.score = myScore;
}
study(){
console.log("study");
}
}
let stu = new Student("小明",18,100);
console.log(stu);
stu.say() // 小明 18
45.0 获取对象类型
实例对象名.constructor.name
示例
class Person{
constructor(myName,myAge){
this.name = myName;
this.age = myAge;
}
say(){
console.log(this.name,this.age);
}
}
let obj = new Object();
let arr = new Array();
let p = new Person();
console.log(typeof obj, typeof arr, typeof p); // Object Object Object
console.log(obj.constructor.name); // Object
console.log(arr.constructor.name); // Array
console.log(p.constructor.name); // Person
46.0 JavaScript instanceof关键字
instanceof关键字:用于判断"对象",是否是指定构造函数的"实例"
语法: 实例对象名称 instanceof 对象名称
class Person{
constructor(myName){
this.name = myName;
}
}
class Student{
constructor(myAge){
this.age = myAge;
}
}
let per = new Person();
let stu = new Student();
console.log(per instanceof Person); // true
console.log(stu instanceof Person); // false
注意点:只要构造函数的原型对象出现在实例对象的原型链中都会返回true
function Person(myName,myAge) { this.name = myName; this.age = myAge } function Student(myName,myAge,myScore) { Person.call(this,myName,myAge); this.score = myScore; } Student.prototype = new Person(); Student.prototype.constructor = Student; let stu = new Student(); console.log(stu instanceof Person); //true
47.0 JavaScript isPrototypeOf属性
isPrototypeOf属性:用于判断一个对象是否是另一个对象的原型
class Person{
constructor(myName,myAge){
this.name = myName;
this.age = myAge;
}
}
class Student{
constructor(myScore){
this.score = myScore;
}
}
let per = new Person();
console.log(Person.prototype.isPrototypeOf(per));//true
console.log(Student.prototype.isPrototypeOf(per)); //false
注意点:只要调用者在传入对象的原型链上都会返回true
function Person(myName,myAge) { this.name = myName; this.age = myAge } function Student(myName,myAge,myScore) { Person.call(this,myName,myAge); this.score = myScore; } Student.prototype = new Person(); Student.prototype.constructor = Student; let per = new Person(); let stu = new Student(); console.log(Person.prototype.isPrototypeOf(stu));//true
48.0 判断某一个对象是否拥有某一个属性
注: in 只要类中或原型对象中有该属性,就返回true
function Person(myName) {
this.name = myName;
}
function Teacher(myName,myPosition) {
Person.call(this,myName);
this.position = myPosition;
}
Teacher.prototype = new Person();
Teacher.prototype.constructor = Teacher;
class Student{
constructor(myScore){
this.score = myScore;
}
}
let per = new Person();
let stu = new Student();
let tea = new Teacher();
console.log("name" in per); //true
console.log("score" in stu); //true
console.log("name" in stu); //false
//存在继承关系
console.log("name" in tea); // true
49.0 判断某一个对象自身是否拥有某一个属性
hasOwnProperty()方法只会去它的类中寻找属性,不会去原型对象中去寻找
function Person(myName) {
this.name = myName;
}
function Teacher(myName,myPosition) {
Person.call(this,myName);
this.position = myPosition;
}
Teacher.prototype = new Person();
Teacher.prototype.constructor = Teacher;
Person.prototype.height = 180;
let per = new Person();
let tea = new Teacher();
console.log(per.hasOwnProperty("name")); //true
console.log(per.hasOwnProperty("height")); //false height为类中原型对象的属性
console.log(tea.hasOwnProperty("name")); //true
50.0对象的增删改查
class Person{}
let per = new Person();
//添加属性/方法
per.name = "张三"; // per["name"] = "张三"
per.say = function(){
console.log("hello");
};
per["run"] = function(){
console.log("run");
};
//删除属性/方法
delete per.name; // delete per["name"]
delete per.say; // delete per["say"]
//修改属性/方法 ----> 同名属性/方法的覆盖 与添加属性的方法一样
//查询属性/方法 ----> 实例对象名.属性名/方法名 实例对象名["属性名/方法名"]
51.0 对象遍历
在JavaScript中可以通过高级for循环来遍历对象
语法:
for(let key for obj){}
class Person{
constructor(myName,myAge){
this.name = myName;
this.age = myAge;
this.run = function () {
console.log("run run");
}
}
//注意点:ES6定义类的格式,会将方法默认放到原型对象中
say(){
console.log(this.name, this.age);
}
}
let per = new Person("张三",18);
for(let key in per){
console.log(key); // name age run
console.log(per[key]); //代码含义取出per对象中名称叫做当前遍历到的名称的属性或方法的值
console.log(per.key); //不能这样写 代码含义是取出per对象中名称为key的属性/或方法的值
}
52.0 对象的解构赋值
对象的解构赋值和数组的解构赋值,除了符号不一样,其它的都一模一样,数组的解构使用[] ,对象的解构赋值使用 {}
示例:
let obj = {
name:"zhang",
age:18,
}
let {name,age} = obj;
console.log(name, age); // zhang 18
let {name,age,height } = {name:"zhang",age:18};
console.log(name, age, height); //zhang 18 undefined
let {name,age,height = 1.70 } = {name:"zhang",age:18};
console.log(name, age, height); //zhang 18 1.70
let {age} = {name:"zhang",age:18};
console.log(age); //18
注意点:
- 在对象的解构赋值中,左边的变量名称必须和对象的属性名称一致,才可以解构出数据
let {a,b} = {name:"张三",age:18};
console.log(a, b); // undefined undefined
解构赋值应用场景
函数传参
let array = [1,2,3];
function sum([a,b,c]) {
return a+b+c;
}
let res = sum(array);
console.log(res); // 6
let obj = {
name:"zhang",
age:18,
};
function say({name,age}) {
console.log(name, age);
}
say(obj); //zhang 18
53.0 JavaScript的深拷贝和浅拷贝
深拷贝 | 修改新变量的值不会修改原有变量的值 默认情况下,基本数据类型都是深拷贝 |
浅拷贝 | 修改新变量的值会修改原有变量的值 默认情况下,引用类型都是浅拷贝 |
class Person{
constructor(myName,myAge){
this.name = myName;
this.age = myAge;
}
say(){
console.log(this.name, this.age);
}
}
// 浅拷贝
let per = new Person("zhang",18);
let per1 = per;
per1.name = "li";
console.log(per.name, per1.name); // li li
//深拷贝
let per2 = new Person();
per2.name = per.name; // li
per2.name = "xiao"; // xiao
console.log(per.name, per1.name, per2.name); //li li xiao
//将per的所有属性拷贝到per2中
for(let key in per){
per2[key] = per[key];
console.log(per2[key]);
}
assign(p1,p2)方法,可以将p2中的所有属性拷贝到p1中
//assign(p1,p2)方法,可以将p2中的所有属性拷贝到p1中 let obj = new Object(); obj.name = "zhang"; obj.age = 18; let obj1 = new Object(); Object.assign(obj1,obj); console.log(obj1); //{name: "zhang", age: 18}
深拷贝
class Person{ name = "zhang"; cat = { age:18, }; score = [1,2,3]; } let per1 = new Person(); let per2 = new Object(); function depCopy(target,source) { //通过遍历拿到source中的所有属性 for(let key in source){ //取出当前遍历到的属性对应的取值 let sourceValue = source[key]; //console.log(sourceValue); //判断当前取值是否为引用数据类型 if(sourceValue instanceof Object){ //console.log(sourceValue.constructor); //console.log(new sourceValue.constructor); let subTarget = new sourceValue.constructor; target[key] = subTarget; depCopy(subTarget,sourceValue); }else { target[key] = sourceValue; } } } depCopy(per2,per1); console.log(per2);
54.0 数组高级API
传统遍历数组的方法
let array = [1,2,3,5,6,7,8]; //传统遍历数组的方法 for (let i=0;i<array.length;i++){ console.log(array[i]); } //在企业开发中不推荐使用for in循环来遍历数组,for in循环一般用来遍历对象的 for(let key in array){ console.log(key); } function Person() { this.name = "zhang"; this.age = 18; this.score = 100; } let per = new Person(); console.log(per); //对象中的属性是无序 /* Person {name: "zhang", age: 18, score: 100} age: 18 name: "zhang" score: 100 __proto__: Object*/
利用ES6中推出的for of 循环来遍历数组
let array = [1,2,3]; for(let value of array){ console.log(value); }
利用Array数组对象的forEarch方法来遍历数组
forEarch方法会自动调用传入的函数,每次调用都会将当前遍历到的元素,当前遍历到的索引,当前被遍历的数组传递给这个函数
let array = [1,2,3]; array.forEach(function (currentValue,currentIndex,currentArray) { console.log(currentValue, currentIndex, currentArray); /* 1 0 (3) [1, 2, 3] 2 1 (3) [1, 2, 3] 3 2 (3) [1, 2, 3]*/ })
重写forEach方法
let array = [1,2,3]; // 重写forEach方法 Array.prototype.myForEach = function (fn) { for(let i=0;i<this.length;i++){ fn(this[i],i,this); } } array.myForEach(function (currentValue, currentIndex, currentArray) { console.log(currentValue, currentIndex, currentArray); })
数组的findIndex方法
findIndex方法:定制版的indexOf,找到返回索引,找不到返回-1
let array = [1,3,7,9]; let index = array.findIndex(function (currentValue, currentIndex, currentArray) { if(currentValue === 11) return true; }); console.log(index); // -1
数组的find方法
find返回找到的元素,找到则返回该元素,找不到返回undefined
let array = [1,2,3,7,8,9]; let value = array.find(function (currentValue, currentIndex, currentArray) { if(currentValue === 7) return true; }); console.log(value);
数组过滤(数组的filter方法)
filter方法:将满足条件的元素添加到一个新的数组中
let array = [1,2,3,7,8,9,10]; // 将数组中是2的倍数是元素添加到newArray数组中 let newArray = array.filter(function (currentValue, currentIndex, currentArray) { if(currentValue % 2 === 0) return true; }); console.log(newArray); // [2,8,10]
数组映射(map方法)
map方法:将满足条件的元素映射到一个新的数组中
let array = [1,2,3,7,8,9,10]; // 将数组中是2的倍数是元素映射到newArray数组中 let newArray = array.map(function (currentValue, currentIndex, currentArray) { if(currentValue % 2 === 0) return currentValue; }); console.log(newArray); //[undefined, 2, undefined, undefined, 8, undefined, 10]
删除数组元素
- splice()
- delete array[index] 通过delete来删除数组中的元素,数组的length属性不会发生变化
数组排序
- array.sort()
如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前; 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。 compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。 注:如果元素是字符串类型,那么比较的是字符串的Unicode编码,如果数组中元素是数组类型,如果需要升序排序,直接 return a-b;如果需要降序排序,直接return b - a;
let array = ["c","a","b"];
array.sort(function (a,b) {
if(a>b){
return 1;
}else if(a<b){
return -1;
}else {
return 0;
}
// return a-b; 数值类型
});
console.log(array);
按字符串长度排序
let array = ["22","1","123","12345","33","789123456"];
array.sort(function (str1,str2) {
// return str1.length - str2.length; // 升序
return str2.length - str1.length; //降序
});
console.log(array);
按对象的某一个属性排序
let array = [
{name:"zs",age:18},
{name:"ls",age:20},
{name:"ww",age:15},
];
array.sort(function (a,b) {
return a.age - b.age; //按年龄升序排序
});
console.log(array);
55.0 字符串常用方法
- 获取字符串长度 str.length
- 获取某个字符 str[索引] / charAt(索引)
- 字符串查找 index lastIndex includes
index[value] | 返回value在字符串中的index |
astIndex[value] | 从字符串后面往回找,返回value在字符串中的index |
includes[value] | 找到则返回true,找不到则返回false |
- 字符串拼接 concat sr1.concat(str2) / str1 + str2
- 截取子字符串
str.slice(stratindex,endindex) | 不包括endindex 返回截取到的字符串 |
str.substring(stratindex,endindex) | |
str.substr(startindex,count) | count 截取的个数 返回截取到的字符串 |
字符串切割
let array = [1,2,3]; let str = array.join("-"); console.log(str); //1-2-3 let str1 = "1-2-3"; let array1 = str1.split("-"); console.log(array1); // ["1", "2", "3"]
判断字符串是否以指定字符串开头 ES6
let str = "www.baidu.com"; let res = str.startsWith("www"); console.log(res); // true
判断字符串是否以指定字符串结尾 ES6
let str = "www.baidu.com"; let res = str.endsWith("com"); console.log(res); // true
字符串模板 ES6
- let str = "" ; 双引号
- let str = '' ; 单引号
格式化输出字符串(字符串模板)
let str = `` ; 反引号(Esc键下边,数字键1左边)
let name = "张三";
let age = 18;
str = `我的名字叫${name},我的年龄是${age}`;
console.log(str);
56.0 基本类型和基本包装类型
基本数据类型:字符串类型,数值类型,布尔类型,空类型,未定义类型
常量:通过字面量创建的基本数据类型的数据都是常量
常量的特点:常量是不能被修改的,每次修改或拼接都生成一个新的.
基本类型特点:没有属性和方法
对象类型特点:有属性有方法
基本包装类型:String() Number() Boolean() Array() Funtion() Object() Data() RegExp()
JavaScript中提供了三种自带的对象
本地对象 | 与宿主无关,无论在浏览器还是在服务器中都有对象, 它是ECMAScript标准中定义的类(构造函数) 在使用过程中需要手动new创建 如 String() Number() Boolean() Array() Funtion() Object() Data() RegExp()
|
内置对象 | 与宿主无关,在浏览器和服务器中都有对象 ECMAScript已经自动创建好对象 在使用过程中无需手动new创建 如:Global Math JSON |
宿主对象 | 对于镶嵌到网页中的JavaScript,其宿主对象就是浏览器,所以宿主对象就是浏览器提供的对象 包含: Window 和 Document 所有的DOM和BOM对象都属于宿主对象 |
宿主:宿主是JavaScript的运行环境,JavaScript可以在浏览器中运行,也可以在服务器上运行(node.js)
Math.floor() | 向下取整 |
Math.ceil() | 向上取整 |
Math.round() | 四舍五入 |
Math.abs() | 绝对值 |
Math.random() | 生成随机数 |