当前位置: 首页 > news >正文

JavaScript笔记

文章目录

  • JavaScript
      • 变量
        • 变量-命名
        • 变量规则
        • 变量提升
      • 表达式
      • 数据类型
        • Number类型
          • 类型转换,转成Number
        • Stirng
          • 类型转换,转成String
        • Boolean
          • 类型转换,转成Boolean
        • 类型判断typeof isNaN isFinite
      • operator 操作符
        • 算术运算符
        • 一元运算符
        • 逻辑运算符(布尔运算符)
            • 补0案例
        • 关系运算符(比较运算符)
        • 赋值运算符
        • 运算符的优先级
    • 数组
      • 数组的概念
      • 数组的定义
      • 创建方式
      • 基础数组
        • Array.concat()合并数组
        • Array.indexOf()
        • Array.isArray()
        • Array.join()连接
        • Array.pop()删除
        • Array.push()添加
        • Array.shift()删除
        • Array.unshift()添加
        • Array.slice()切割
      • 进阶数组
        • Array.filter()过滤
        • Array.forEach()循环遍历
        • Array.map()循环遍历
        • Array.reduce()叠加
        • Array.sort()排序
        • Array.flat()降维
        • Array.includes()
        • Array.lastIndexOf()
        • Array.reverse()反向
        • Array.some()和every()
        • Array.splice()替换
    • 字符串
      • 基础方法
        • String.slice()切割
        • String.charAt()
        • String.indexOf()
        • String.split()转成数组
        • String.trim()删空字符串
      • 进阶方法
        • String.charCodeAt()
        • String.replace()
        • toLocaleUpperCase()、toLocaleLowerCase()
    • 函数
      • 函数定义
      • 函数的参数
      • 函数的定义
      • 函数调用
      • 函数返回值
      • arguments
          • 实例
      • 函数分类
        • 纯函数
        • 非纯函数(函数副作用)
        • 匿名函数
        • 柯理化
      • 作用域
        • 全局变量和局部变量
        • 块级作用域(){}
        • 词法作用域
        • 作用域链
      • 判断全局作用域还是局部作用域
      • 预解析
    • 对象 Object
      • 创建对象方式(自定义)
      • 构造函数
      • this详解
      • 对象的使用
        • 遍历对象的属性
        • 删除对象的属性
      • 方法
        • Object.is()
        • Object.freeze()
        • Object.assign()
        • Object.keys()
      • JSON格式对象
        • JSON 语法:
        • JSON 示例:
        • JSON方法API:
          • JSON.parse() 反序列化
          • JSON.stringify() 序列化
      • 总结
    • Date对象方法
    • Math对象方法
    • 执行上下文
        • 1. 什么是执行上下文
        • 2. 执行上下文的类型
      • 执行上下文的生命周期
        • 执行阶段
        • 垃圾回收机制
    • 箭头函数指向:
  • 高级部分
    • Function方法 与 函数式编程
      • call
      • apply
      • 柯理化函数(currying)
      • bind
      • 实例
    • 面向对象编程
    • 原型 prototype
        • 原型的属性和方法
        • 原型链
        • 原型判断
        • 原型继承
        • 原型继承 + 构造函数继承
        • 跨代继承
        • 组合寄生继承
    • 对象Object
        • super 关键字
        • 可枚举
        • Object.entries()
        • Object.fromEntries()
        • Object.keys()
    • Class
    • Promise
    • Symbol

JavaScript

变量

	/*** 声明* 赋值* 调用*/var num;num = 1 + 1console.log(num); //2// 如果没有赋值的变量,有默认的undefined值var str;console.log(str); //undefinedb = 1;console.log(b);//1console.log(a);//报错 a is not defined,没有声明
变量-命名
		/**标识符(变量名)* 规则* 1、javascript区分大小写* 2、由数字、字母、-、$组成,只有两种字符,其余的都不行,中文等其他语言属于字母,可以使用* 3、不能以数字和字符开头* 4、不能是关键字(if,else)*//**规范* 1、驼峰命名法: 第一个单词小写开头,后面的都以大写开头来区分* 2、有意义* 3、n / adj+n*/
变量规则
/*** 变量规则* 1、无声明,报错* 2、无声明,直接赋值,调用,有隐式声明,但是不采取* 3、重复声明,第二次声明的忽略* 4、批量声明,用逗号,隔开,进行显式声明* 5、特殊声明,与批量声明区别,用等号=隔开*/// 1、无声明,报错//  console.log(num);// 2、无声明,直接赋值,调用,有隐式声明,但是不采取str = 2;console.log(str);//2//3、重复声明var x;x = 10console.log(x);//10var x;//第二次声明的忽略x = 30;//第二次赋值有效console.log(x);//30//4、批量声明,用逗号,隔开,进行显式声明var a , b , c , d = 10;/*** var a;* var b;* var c;* var d = 10;*///5、特殊声明,与批量声明区别,用等号=隔开var e = f = g = 10;/** * var g = 10; //隐式声明* var f = g; //隐式声明* var e = f;//显示声明*/console.log(a,e);//undefined 10
变量提升
 /*** 先声明,后赋值、调用* 解释器会先把声明提出来*/console.log(x);var x = 10;console.log(x);x = 20;console.log(x);var w = 30;var y = x + w;console.log(y);/*** 1、首先解释器提出声明* var x;* var w;* var y;* 2、后赋值、调用* console.log(x);//undefined* x = 10;* console.log(x);//10* x = 20;* console.log(x);//20* w = 30;* y = x + w;* console.log(y);//50*/

表达式

var num = 1+1;

上述代码中 1 + 1 就是一个表达式(expression) 指一个为了得到返回值的计算式。

语句可以理解为一条命令,并不一定需要的到一个具体的期望值。表达式的目的是为了得到一个值,方便后面利用值去做什么事情,在上述例子中 表达式 1+1得到的值 赋值 给了 变量 num;

数据类型

数值(number):整数和小数(比如13.14

字符串(string):文本(比如'Hello World')。

布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)

undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值

null:表示空值,即此处的值为空。

对象(object):各种值组成的集合。

symbol (symbol ) : 唯一标识符 //es6学习前不做讨论

Number类型
		//十进制//进行算数计算时,八进制和十六进制表示的数值最终都将被转换成十进制数值。var num = 9;console.log(num);//十六进制,数字序列范围:0~9以及A~Fvar num = 0xA;console.log(num);//八进制var num = 07;   // 对应十进制的7console.log(num);// 如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析var num = 19; // 对应十进制的19console.log(num);//最小值:Number.MIN_VALUE,这个值为: 5e-324console.log(Number.MIN_VALUE);//最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308console.log(Number.MAX_VALUE);//无穷大:Infinity//无穷小:-Infinity/**NAN:not a number* NaN 与任何值都不相等,包括他本身* 只能使用isNaN(is not a number)进行比较*/var y = 10 - 'f';// y = NaN;console.log(typeof y === 'NaN'); //无法判断console.log(y === NaN); //无法判断console.log(isNaN(y)); //只能通过isNaN方法判断   
类型转换,转成Number
/**Number()* 可以把正常的转换为数值,如果遇到非数值的返回NaN* 如果数值0开头,会忽略,直到非0开始计数*/console.log(Number(13.133));//13.133console.log(Number('13.133.133'));//NaNconsole.log(Number('13.13u'));//NaNconsole.log(Number('1k3.13u'));//NaNconsole.log(Number('0100'));//100console.log(Number('k13'));//NaN/**parseInt()* 只保留整数部分* 从左到右进行识别* 可以把正常的转换为数值,直到非数值的停止* 如果开头不是数值,直接返回NaN* 如果数值0开头,会忽略,直到非0开始计数*/console.log('parseInt');console.log(parseInt(13.133));//13console.log(parseInt('13.133'));//13console.log(parseInt('13.13u'));//13console.log(parseInt('1k3.13u'));//1console.log(parseInt('0100')); //100console.log(parseInt('k13')); //NaN/**parseFloat()* 可以转换为浮点型* 从左到右进行识别* 可以把正常的转换为数值,直到非数值的停止* 如果开头不是数值,直接返回NaN* 如果数值0开头,会忽略,直到非0开始计数*/console.log('parseFloat');console.log(parseFloat(13.133));//13.133console.log(parseFloat('13.133.133'));//13.133console.log(parseFloat('13.13u'));//13.13console.log(parseFloat('1k3.13u'));//1console.log(parseFloat('0100')); //100console.log(parseFloat('k13')); //NaN
Stirng
 console.log('今天是2023年11月1日');//一、换行//1、编码时换行,用+进行连接,+一般放在下面一行,便于观看console.log('今天'+'是'+'2023年11月1日');//2、显示换行,在需要换行后加\nconsole.log('今天\n是\n2023年11月1日');//二、转义字符\,在转义的符号前面添加\console.log('\'刘老师\'');//三、字符串长度str.lengthvar str = '12345';console.log(str.length);//5//字符串长度只读,不能进行更改,因为在存储的时候,字符串一坨整体进行存储的,并不是单个字符分开存储的str.length = 2;console.log(str.length);//5//查找字符串的第x个字符,str[x],x是从0开始数console.log(str[0]);//1//字符串只读str[0] = '9';console.log(str[0]);//1str = '92345';console.log(str[0]);//9//只要有一边是字符串,都会转换成字符串console.log(12 + '张三');//12张三// console.log(ab + '李四');//ab is not definedconsole.log(11 + 11);//22console.log('hello' + ' world');//hello worldconsole.log('100' + '100');//100100console.log('11' + 32);//1132console.log('male:' + true);//maletrueconsole.log(isNaN(NaN));//trueconsole.log(isNaN('123'));//false
类型转换,转成String
//1、利用javascript是一个弱类型的语言进行转换var x = 10;x = '你猜我是什么类型';console.log(x);//'你猜我是什么类型'  //2、利用toString()转换成字符串类型var num = 10;num = num.toString();console.log(typeof(num));//string/*** 3、使用String()强制转换* undefined null 无法使用toString 可以使用String()*/num = String(null); //强制转换console.log(num);console.log(typeof(num));//string//4、任何值与字符串进行 + 运算 结果都是字符串console.log(null + '');
Boolean
类型转换,转成Boolean
//1、Boolean()//除了 '' 0 false undefined null 之外 其他的值转换为布尔值 都是 trueconsole.log(Boolean(1));//trueconsole.log(Boolean('哈哈哈'));//trueconsole.log(Boolean('133.13'));//trueconsole.log(Boolean(null));//falseconsole.log(Boolean(undefined));//falseconsole.log(Boolean(NaN));//false//2、两次取反!!console.log(!!null);//false
类型判断typeof isNaN isFinite
console.log(typeof 1);//numberconsole.log(typeof '1');//stringconsole.log(typeof false);//boolenconsole.log(typeof undefined);//undefinedconsole.log(typeof null);//objectconsole.log(typeof NaN);//numberconsole.log(typeof 'abc'.length);//numberconsole.log(typeof (1 < 2) === 'boolean');//bolleanconsole.log(1, '1', false, NaN, null, undefined);console.log(typeof x);//undefined//除了`Infinity`、`-Infinity`、`NaN`和`undefined`这几个值会返回`false`,`isFinite`对于其他的数值都会返回`true`。console.log(isFinite(Infinity)); // falseconsole.log(isFinite(-Infinity)); // falseconsole.log(isFinite(NaN)); // falseconsole.log(isFinite(undefined)); // falseconsole.log(isFinite(null)); // trueconsole.log(isFinite(-1)); // true

operator 操作符

运算符 operator

5 + 6

表达式 组成 操作数和操作符,会有一个结果

算术运算符

++ – 只能给变量使用

  • 加法运算符x + y
  • 减法运算符x - y
  • 乘法运算符x * y
  • 除法运算符x / y
  • 指数运算符x ** y
  • 余数运算符x % y
  • 自增运算符++x 或者 x++
  • 自减运算符--x 或者 x--
  • 数值运算符+x
  • 负数值运算符-x

x/+0默认为正无穷,x/-0默认为负无穷

一元运算符

一元运算符:只有一个操作数的运算符

1 + 2 两个操作数的运算符 二元运算符

++ 自身加1

– 自身减1

  • 前置++

  • 用了就加1 实时改变

    var num1 = 5;
    ++ num1; //num1 = num1+1	//num1 = 6var num2 = 6;
    console.log(num1 + ++ num2);//13
    //num1 + (num2+1)	//6 + 7
    
  • 后置++

  • 先赋值再加1 (在调用时加1)

    var num1 = 5;
    num1 ++;    //num1 = 5
    var num2 = 6 
    console.log(num1 + num2 ++);//12
    //num1+1 + num 2	//6	+ 6
    
  • 猜猜看

    var a = 1; var b = ++a + ++a; console.log(b);  //5  
    var a = 1; var b = a++ + ++a; console.log(b);  //4
    var a = 1; var b = a++ + a++; console.log(b);  //3  
    var a = 1; var b = ++a + a++; console.log(b);  //4
    

    总结
    前置++:先加1,后参与运算
    后置++:先参与运算,后加1
    上面两个理解后,下面两个自通
    前置-- :先减1,后参与运算
    后置-- :先参与运算,后减1

逻辑运算符(布尔运算符)
&& 与 两个操作数同时为true,结果为true,否则都是false
|| 或 两个操作数有一个为true,结果为true,否则为false
!  非  取反
短路与 &&
如果左边为真 返回右边
如果左边为假 返回左边本身
		var x = 1;var y = 3;var z = x < y && 1;console.log(z);//1z = x > y && 1;console.log(z);//falsez = 0 && 1;console.log(z);//0
短路或 ||
如果左边为假 返回右边
如果左边为真 返回左边本身
		 var a = 1;var b = 3;var c = a < b || 2;console.log(c);//truec = a > b || 2;console.log(c);//2c = 0 || 2;console.log(c);//2

案例:

 		var x = false;y =  false    || truevar y = x == true || !x && x == false;//    true    ||console.log(y);//trueconsole.log(padLeft(1));
补0案例
function padLeft(num) {// if(String(num)[1]){//     //2位数字//     return num;// }else{//     return '0' + String(num);// }return (String(num)[1] && num) || ('0' + num)}
关系运算符(比较运算符)
<  >  >=  <= == != === !==
/***  1. 如果两个操作值都是数值,则直接比较大小。2. 如果两个操作值都是字符串,则字符串进行其Unicode编码进行比较。3. 如果一个操作值是数值,则另一个值转换为数值进行比较。4. 如果一个操作值是对象,则调用对象的valueOf()和toString()方法,然后再进行上述比较。5. 如果一个操作值是布尔值,则将布尔值转换为数值再进行比较。(注:NaN和任何值都不相等,包括自己,同时它与任何类型比较都会返回false。)*/
=====的区别:==只进行值得比较,===类型和值同时相等,则相等var result = '55' == 55;  	// true
var result = '55' === 55; 	// false 值相等,类型不相等
var result = 55 === 55; 	// true
赋值运算符

= += -= *= /= %=

例如:
var num = 0;
num += 5;	//相当于  num = num + 5;
运算符的优先级
优先级从高到底1. ()  优先级最高2. 一元运算符  ++   --   !3. 算数运算符  先*  /  %   后 +   -4. 关系运算符  >   >=   <   <=5. 相等运算符   ==   !=    ===    !==6. 逻辑运算符 先&&   后||7. 赋值运算符
// 练习1:
4 >= 6 || '山海' != '琨' && !(12 * 2 == 144) && true	//true
// 练习2:
var num = 10;
5 == num / 2 && (2 + 2 * num).toString() === '22'	//true

数组

数组的概念

所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。

数组的定义

数组是一个有序的列表,可以在数组中存放任意的数据,并且数组的长度可以动态的调整。

创建方式

通过实例化创建

var arr = new Array(3); //只写一个参数,创建一个长度为3的数组 , 数组中每一项都为 空置empty [empty,empty,empty]
arr = new Array(1,2,3,4); //多个参数  会生成对应参数个数与内容的数组 [1,2,3,4]

通过数组字面量创建数组

// 创建一个空数组
var arr1 = []; 
// 创建一个包含3个数值的数组,多个数组项以逗号隔开
var arr2 = [1, 3, 4]; 
// 创建一个包含2个字符串的数组
var arr3 = ['a', 'c']; 

学习方法看三部分

参数、返回值、是否会改变原来的变量

基础数组

Array.concat()合并数组

**作用:**将两个及两个以上个数组进行合并

​ 1、参数:要合并的数组 可以传一个以上的参数

​ 2、返回值:合并后的结果 返回的是一个新数组

​ 3、是否会改变原来的变量:不会

//Array.concat()方法,合并数组var arr = ['我的','名字','是','YH'];var arr1 = [1 , 2 , 3 , 4 , 5];var arr2 = [11 , 22 , 33];console.log(arr.concat(arr1));//['我的', '名字', '是', 'YH', 1, 2, 3, 4, 5]console.log(arr);//['我的', '名字', '是', 'YH']console.log(arr.concat(arr1,arr2));//['我的', '名字', '是', 'YH', 1, 2, 3, 4, 5, 11, 22, 33]
Array.indexOf()

**作用:**查找数组中对应元素所在下标,并可以指定查找开始的位置

1、参数:

​ 两个参数

​ 第一个参数代表,要找的元素

​ 第二个参数代表,查找的起始下标

​ 如果是负数,从末端开始计数,但是查找顺序还是从左到右

​ 2、返回值:返回下标值,不存在会返回-1

​ 3、是否会改变原来的变量:不会

//Array.indexOf()方法,查找数组对应内容的下标var arr = ['我的','名字','是','YH'];var plants = ['西红柿', '黄瓜', '芹菜', '豆角', '土豆','黄瓜'];console.log(arr.indexOf('名字'));//1console.log(arr.indexOf(' '));//-1console.log(plants.indexOf('黄瓜'));//1console.log(plants.indexOf('黄瓜',-6));//1console.log(plants.indexOf('黄瓜',2));//5console.log(plants.indexOf('黄瓜',-3));//5
Array.isArray()

**作用:**判断是否为对象

1、参数:判断的对象

​ 2、返回值:Boolean值

​ 3、是否会改变原来的变量:不会

//Array.isArray()方法,判断是否是数组console.log(Array.isArray('123'));//falseconsole.log(Array.isArray(123));//falseconsole.log(Array.isArray([]));//true
Array.join()连接

**作用:**设置特定字符将数组元素连接成一个字符串

​ 1、参数:需要添加的分割符号

​ 2、返回值:添加后的字符串

​ 3、是否会改变原来的变量:不会

//Array.join()方法,数组元素之间添加分割符号进行连接var arr = ['我的','名字','是','YH'];var arr1 = [1 , 2 , 3 , 4 , 5];console.log(typeof(arr.join('')));//stringconsole.log(arr.join(''));//我的名字是YHconsole.log(arr1.join('|'));//1|2|3|4|5console.log(arr1);//[1 , 2 , 3 , 4 , 5]
Array.pop()删除

**作用:**从数组末端删除1个元素

​ 1、参数:无

​ 2、返回值:被删除的数组元素

​ 3、是否会改变原来的变量:会

//Array.pop()方法,从数组的末端进行删除,只要执行了pop()就会进行删除var arr = ['我的','名字','是','YH'];arr.pop();console.log(arr);//['我的', '名字', '是']console.log(arr.pop());//是 console.log(arr);//['我的', '名字']
Array.push()添加

**作用:**从数组末端添加1个元素

​ 1、参数:需要添加的内容

​ 2、返回值:数组的长度

​ 3、是否会改变原来的变量:会

//Array.push()方法,从数组的末端进行添加var arr = ['我的','名字','是','YH'];var arr1 = [1 , 2 , 3 , 4 , 5];arr.push(arr1[0]);console.log(arr);//['我的', '名字', '是', 'YH', 1]arr.push('!');console.log(arr);//['我的', '名字', '是', 'YH', 1, '!']console.log(arr.push(arr1));//7,返回值是 数组的长度//Array.concat()方法,返回值是 合并后的数组var arr = ['我的','名字','是','YH'];var arr1 = [1 , 2 , 3 , 4 , 5];var arr2 = [11 , 22 , 33];console.log(arr.concat(arr1));//['我的', '名字', '是', 'YH', 1, 2, 3, 4, 5]console.log(arr);//['我的', '名字', '是', 'YH']console.log(arr.concat(arr1,arr2));//['我的', '名字', '是', 'YH', 1, 2, 3, 4, 5, 11, 22, 33]
Array.shift()删除

**作用:**从数组前端删除1个元素

​ 1、参数:无

​ 2、返回值:被删除的数组元素

​ 3、是否会改变原来的变量:会

//Array.shift()方法,从数组的前端进行删除,只要执行了shift()就会进行删除var arr = ['我的','名字','是','YH'];arr.shift();console.log(arr);//['名字', '是', 'YH']console.log(arr.shift());//名字 console.log(arr);//['是', 'YH']
Array.unshift()添加

**作用:**从数组前端添加1个元素

​ 1、参数:需要添加的内容

​ 2、返回值:数组的长度

​ 3、是否会改变原来的变量:会

	//Array.unshift()方法,从数组的前端进行添加var arr = ['我的','名字','是','YH'];var arr1 = [1 , 2 , 3 , 4 , 5];arr.unshift(arr1[0]);console.log(arr);//[1, '我的', '名字', '是', 'YH']arr.unshift(':');console.log(arr);//[':', 1, '我的', '名字', '是', 'YH']arr.unshift(arr1);console.log(arr);//[Array(5), ':', 1, '我的', '名字', '是', 'YH']// console.log(arr.unshift(arr1));//7,返回值是 数组的长度
Array.slice()切割

**作用:**切割数组begin(起始下标),不包括end(结束下标)

1、参数:

​ 不管是正数还是负数,方向都是从左到右进行切割

​ 正数:

​ 切割从0开始计数

​ 一个参数的情况下,保留头并且一直到最后部分

​ 两个参数,切割部分:“保留头,不要尾”

​ 负数:

​ 从末端开始切割,1开始计数

​ 一个参数的情况下,保留头并且一直到最后部分

​ 两个参数,切割部分:“保留头,不要尾”

​ 2、返回值:

​ 切割部分: “保留头,不要尾”的部分,并且是一个新数组(浅拷贝)

​ 3、是否会改变原来的变量:

​ 不会

//Array.slice()方法,切割数组,“保留头,不要尾”var arr = [1 , 2 , 3 , 4 , 5 , 6];console.log(arr.slice(0));//[1, 2, 3, 4, 5, 6]console.log(arr);//[1, 2, 3, 4, 5, 6]console.log(arr.slice(2));//[3, 4, 5, 6]console.log(arr);//[1, 2, 3, 4, 5, 6]console.log(arr.slice(2,4));//[3, 4]console.log(arr.slice());//[1, 2, 3, 4, 5, 6] 浅拷贝console.log(arr.slice(-2));//[5, 6]console.log(arr.slice(-5,-2));//[2, 3, 4]

进阶数组

数组的高级方法,会进行遍历,让每一个数组都进行对应的操作

Array.filter()过滤

​ 1、参数:

​ current 元素

​ index 元素下标

​ array 数组

​ 2、返回值:返回过滤掉之后的新数组 有return返回,就要有接受的容器

​ 3、是否会改变原来的数组:不会

//Array.filter() 过滤var arr = [1 , 2 , 3 , 4 , 5];var newArr = arr.filter(function(current,index,arr) {return current > 3;});console.log(newArr);//[4, 5]console.log(arr);// [1, 2, 3, 4, 5]
Array.forEach()循环遍历

**作用:**对想要编辑的参数进行修改,相对map选择性更灵活

​ 1、参数:callback(current,index,array),[option指定this对象]

​ 2、返回值:,永远为undefined

​ 3、是否会改变原来的变量:不会

// Array.forEach() 遍历数组var arr = [1,2,3,4];/*forEach()里面放的是函数,有遍历数组的作用里面三个参数,第一个是值,第二个是对应的下标,第三个是数组*/arr.forEach(function(current,index,array){console.log(current,index,array);});

结果:image-20250714013319691

  var obj ={name:"lisi",age:18}arr.forEach(function(){//this指向obj,对obj进行遍历console.log(this.name);//lisi},obj);
Array.map()循环遍历

**作用:**对数组所欲参数进行修改,相对foreach,map只能对数组所有元素同时进行修改

​ 1、参数:

​ current 元素

​ index 元素下标

​ array 数组

​ 2、返回值:返回一个新数组 有return返回,就要有接受的容器

​ 3、是否会改变原来的数组:不会

//Array.map() 让每一个数组元素进行对应的操作并返回var arr = [1 , 2 , 3 , 4 , 5];var arr1 = [3 , 4 , 5];var newArr = arr.map(function(current,index,arr) {return current*2;});console.log(arr);//[1, 2, 3, 4, 5] 不会改变原来的数组console.log(newArr);//[2, 4, 6, 8, 10]var kvArray = [{key: 1, value: 10}, {key: 2, value: 20}, {key: 3, value: 30}];var newK = kvArray.map(function(current,index,arr) {var newArray = {};newArray[current['key']] = current['value'];return newArray;});console.log(newK);//[{1: 10}, {2: 20}, {3: 30}]
Array.reduce()叠加

​ 1、参数:

​ accumulator 累计器 可以设置初始值

​ current 元素

​ index 元素下标

​ array 数组

​ 2、返回值:返回过滤掉之后的新数组 有return返回,就要有接受的容器

​ 3、是否会改变原来的数组:不会

//Array.reduce() 合并 叠加var arr = [1, 2, 3, 4, 5];var newArr = arr.reduce(function (acc, current, index, arr) {console.log(acc);return acc + current;}, 10);console.log(newArr); //25console.log(arr); //[1, 2, 3, 4, 5]var str = "qwenrhtgfncgzhgnrertyuiytx";//字符串转换成数组var newStr = str.split("");console.log(newStr); //['q', 'w', 'e', 'n', 'r', 'h', 't', 'g', 'f', 'n', 'c', 'g', 'z', 'h', 'g', 'n', 'r', 'e', 'r', 't', 'y', 'u', 'i', 'y', 't', 'x']var count = newStr.reduce(function (acc, current, index, arr) {if (acc[current]) {acc[current]++;} else {acc[current] = 1;}return acc;}, {});console.log(count);
Array.sort()排序

​ 1、参数:function(a,b)

​ 2、返回值:排序后结果

​ 3、是否会改变原来的变量:会

// Array.sort() 给数组排序var arr = [100,5,3,4,9];const months = ['March', 'Jan', 'Feb', 'Dec'];//直接使用sort方法,什么都不加,会按照开头进行排序console.log(arr.sort());//[100, 3, 4, 5, 9]console.log(months.sort());//['Dec', 'Feb', 'Jan', 'March']//使用函数返回值,进行大小排序//从小变大arr.sort(function(a,b) {return a-b;});console.log(arr);//[3, 4, 5, 9, 100]//从大变小arr.sort(function(a,b) {return b-a;});console.log(arr);//[100, 9, 5, 4, 3]//返回值为0,不会改变排序arr.sort(function(a,b) {return 0;});console.log(arr);//[100, 9, 5, 4, 3]//返回值为-1,倒序arr.sort(function(a,b) {return -1;});console.log(arr);//[3, 4, 5, 9, 100]
Array.flat()降维

​ 1、参数:

​ 需要进行降维的次数

​ 2、返回值:返回降维后的数组

​ 3、是否会改变原来的数组:不会

//Array.flat() 展开嵌套的数组,对数组进行降维var arr = [1 , 2 , [3 , [1 , 9] , 8] , 5 , 6];//三维数组console.log(arr.flat());//[1, 2, 3, Array(2), 8, 5, 6]三维==>二维console.log(arr.flat(1));//[1, 2, 3, Array(2), 8, 5, 6]三维==>二维console.log(arr.flat(2));//[1, 2, 3, 1, 9, 8, 5, 6]三维==>一维console.log(arr);//[1, 2, Array(3), 5, 6]
Array.includes()

​ 1、参数:

​ 需要进行判断的元素内容

​ 2、返回值:返回Boolean值

​ 3、是否会改变原来的数组:不会

//Array.includes() 判断数组里面是否有这个元素var arr = [1 , 2 , 3 , 4 , 5 , 6];console.log(arr.includes(5));//trueconsole.log(arr.includes(100));//false
//Array.filter() 过滤var arr = [1 , 2 , 3 , 4 , 5];var newArr = arr.filter(function(current,index,arr) {return current > 3;});console.log(newArr);//[4, 5]console.log(arr);// [1, 2, 3, 4, 5]
Array.lastIndexOf()

​ 1、参数:

​ 要找的数组元素

​ 2、返回值:返回从末端开始找到的对应的下标 有return返回,就要有接受的容器

​ 3、是否会改变原来的数组:不会

//Array.lastIndexOf() 从末端开始找下标var arr = [1 , 2 , 3 , 4 , 1, 3];      console.log(arr.lastIndexOf(1));//4//查找到重复的元素function duplicates() {var newArr = [];for (var i = 0,len = arr.length;i < len;i++) {if (arr.lastIndexOf(arr[i]) !== arr.indexOf(arr[i])&&newArr.indexOf(arr[i]) === -1) {newArr.push(arr[i]);}}return newArr;}console.log(duplicates(arr));
Array.reverse()反向

​ 1、参数:无

​ 2、返回值:返回反向后的数组

​ 3、是否会改变原来的数组:会

//Array.reverse() 将数组进行反向var arr = [1 , 2 , 3 , 4];console.log(arr.reverse());//[4, 3, 2, 1]console.log(arr);//[4, 3, 2, 1]
Array.some()和every()
/*判断一个数组是不是纯数字数组some 数组中至少有一项符合return的测试 如果有 返回true 如果没有 返回false ||every 每一项都通过return的条件 返回true 有一项不通过就返回false  &&*/var arr = [1 , 2 , "3" , 4 , 5 , 6];var result1 = arr.some(function (current,index,arr) {return typeof current === 'number';});console.log(result1);//truevar result2 = arr.every(function (current,index,arr) {return typeof current === 'number';});console.log(result2);//false
Array.splice()替换

​ 1、参数:

​ 需要删除的下标,从0开始

​ 删除或者替换的个数

​ 需要进行替换的字符串。可以有很多个字符串,用逗号,进行分割

​ 2、返回值:返回删除的部分,删除是从下标开始

​ 如果只设置了一个参数,那么就会从开始的下标进行删除,直到最后

​ 如果设置两个参数,会根据下标和删除的个数进行删除

​ 3、是否会改变原来的数组:会

//Array.splice() 在对应的地方进行删除或者替换var arr = [1 , 2 , 3 , 4 , 5 , 6];//设置一个参数console.log(arr.splice(1));//[2, 3, 4, 5, 6]console.log(arr);//[1]//设置两个参数arr = [1 , 2 , 3 , 4 , 5 , 6];console.log(arr.splice(1,2));//[2, 3]console.log(arr);//[1, 4, 5, 6]//设置三个参数arr = [1 , 2 , 3 , 4 , 5 , 6];console.log(arr.splice(1,2,'100','56'));//[2, 3]console.log(arr);//[1, '100', '56', 4, 5, 6]arr = ['a','b','c','d','e','f'];var eTargetIndex = 1,colliIndex = 3,colliEle = arr[1];arr.splice(eTargetIndex,1);console.log(arr);//['a', 'c', 'd', 'e', 'f']arr.splice(colliIndex,0,colliEle);console.log(arr);//['a', 'c', 'd', 'b', 'e', 'f']

字符串

基础方法

String.slice()切割

同数组slice()

var str = 'The quick brown fox jumps over the lazy dog.';console.log(str.slice(31));
//  "the lazy dog."console.log(str.slice(4, 19));
//  "quick brown fox"console.log(str.slice(-4));
//  "dog."console.log(str.slice(-9, -5));
//  "lazy"
String.charAt()

**作用:**查找对应下标的字符

​ 1、参数:需要查找的下标,从0开始计数
​ 2、返回值:返回对应
​ 3、是否会改变原来的变量:不会

        //String.charAt()方法,查找对应下标的字符var str = '我的,名字是YH';console.log(str.charAt(0));//我console.log(str.charAt(2));//,console.log(str.charAt(15));//超出长度,会返回一个空字符串
String.indexOf()

**作用:**查找对应字符的下标

​ 1、参数:需要查找的内容

​ 2、返回值:返回对应内容所在的下标 如果不存在,会返回-1

​ 3、是否会改变原来的变量:不会

        //String.indexOf()方法,查找对应字符的下标var str = '我的,名字是YH';console.log(str.indexOf('我'));//0console.log(str.indexOf(','));//2console.log(str.indexOf('15'));//-1 不存在,会返回-1var plants = '西红柿,黄瓜,芹菜,豆角,土豆,黄瓜'; //length 18console.log(plants.indexOf('黄瓜')); //4console.log(plants.indexOf('黄瓜',5)); //16
String.split()转成数组

**作用:**把字符串转成数组

1、参数:

​ 通过某个字符串中的特殊符号,进行切割成散装的数组元素

​ 2、返回值:返回转换后的数组

​ 3、是否会改变原来的变量:不会

         //String.split()方法,把字符串转成数组var str = '我的,名字是YH';console.log(str.split(','));//['我的', '名字是YH'] 通过,分割,返回两个元素的数组console.log(str.split(''));//['我', '的', ',', '名', '字', '是', 'Y', 'H'] 空字符串会吧所有字符串都拆开,放到数组里面console.log(str.split('15'));//['我的,名字是YH'] 不存在,会返回整体console.log(str.split());//['我的,名字是YH'] 什么都不写也会返回整体var str ='你好,我,是海,牙老,师';var arr = str.split(',',3);console.log(arr);//['你好', '我', '是海']从第3个,开始就结束了
String.trim()删空字符串

**作用:**把空字符串删掉

​ 1、参数:无

​ 2、返回值:返回把空字符串删掉后的结果

​ 3、是否会改变原来的变量:不会

        //String.trim()方法,把空字符串删掉var greeting = '   Hello world!   ';console.log(greeting);//   Hello world!   console.log( greeting.trim());//Hello world!console.log(greeting);//   Hello world!   原来的变量不会改变

进阶方法

String.charCodeAt()

**作用:**查找对应下标的字符,并转换成对应UTF-16 编码

​ 1、参数:需要查找的下标,从0开始计数

​ 2、返回值:返回对应UTF-16 编码

​ 3、是否会改变原来的变量:不会

       //String.charCodeAt()方法,查找对应下标的字符,并转换成对应UTF-16 编码var str = '我的,名字是YH';console.log(str.charCodeAt(0));//25105console.log(str.charCodeAt(15));//超出长度,会返回NaN
String.replace()

**作用:**把空字符串删掉

​ 1、参数:

​ 需要进行替换的内容

​ 进行替换的内容

​ 2、返回值:返回替换后字符串

​ 3、是否会改变原来的变量:不会

        //String.replace()方法,替换,从左到右进行查找,替换第一个匹配到的内容进行替换var str = '我的,名字是YH,我';console.log(str.replace('我','你'));//你的,名字是YH,我console.log(str);//我的,名字是YH,我
toLocaleUpperCase()、toLocaleLowerCase()

**作用:**把空字符串删掉

​ 1、参数:

​ 无

​ 2、返回值:返回转换后字符串

​ 3、是否会改变原来的变量:不会

        //toLocaleUpperCase()和toLocaleLowerCase()方法大小写转换var str = 'qeaFSHjeuyk';console.log(str.toLocaleUpperCase());//QEAFSHJEUYKconsole.log(str.toLocaleLowerCase());//qeafshjeuykconsole.log(str);//qeaFSHjeuyk

函数

函数定义

JavaScript 函数是被设计为执行特定任务的代码块。

JavaScript 函数会在某代码调用它时被执行。

/*函数 封装一段代码 方便重复调用参数 形参 实参通过传参可以让函数内的代码接收不同的数据源进行计算得出不同的结果返回 return函数执行结束会返回值 默认为 undefined 我们可以通过return关键字 设置返回值函数执行的时候 内部代码执行完成return 就不会往后执行 后面的代码就放弃了*/

函数的参数

函数的参数分为 形参(parameter) 和 实参(argument)

当函数需求根据不同的值做出不同反馈时, 就需要通过使用参数。

形参为声明函数时预设的形势参数,我们可以自定义命名。

实参为调用函数时对应 形参所传递的实际参数,为所需要的原始值。

在这里插入图片描述

函数的定义

函数的定义 有 函数表达式函数声明 两种, 函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行。

JavaScript 函数通过 function 关键词进行定义,其后是函数名和括号 ()。

函数名可包含字母、数字、下划线和美元符号(规则与变量名相同)。

  • 函数声明
function 函数名(){// 函数体
}
  • 函数表达式
var 变量名 = function() {// 函数体
}

函数名:

函数一般都用来干一件事情,需用使用动词+名词 的驼峰结构命名,例如: setValue clearInterval 等。

函数调用

函数有声明就有调用,函数内代码只有在调用时才会执行。函数可以多次调用。

函数名(); //主动调用

函数返回值

当 JavaScript 到达 return 语句,函数将停止执行。

如果函数被某条语句调用,JavaScript 将在调用语句之后“返回”执行代码。

返回值语法:

//声明一个带返回值的函数
function 函数名(形参1, 形参2, 形参...){//函数体return 返回值;
}//可以通过变量来接收这个返回值
var 变量 = 函数名(实参1, 实参2, 实参3);

函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。

返回值详解:
如果函数没有显示的使用 return语句 ,那么函数有默认的返回值:undefined
如果函数使用 return语句,那么跟再return后面的值,就成了函数的返回值
如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined
函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后面的所有其他代码都不会再执行。

arguments

JavaScript 函数有一个名为 arguments 对象的内置对象。

arguments 对象包含函数调用时使用的参数数组

arguments为 (类数组)

实例
//查找数字列表中的最高值:
jsx = findMax(1, 123, 500, 115, 44, 88);//500
function findMax() {   var i;    var max = -Infinity;for (i = 0; i < arguments.length; i++) { if (arguments[i] > max) {  max = arguments[i];       }   } return max;
}

函数分类

纯函数

它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数

/*纯函数有参数 有对应参数的返回值该函数不会产生任何可观察的副作用拿到参数 对参数加工 返回加工后的结果 其他一律不作*/function pure(a, b) {return a + b;}function noPure(a, b) {return 3;}
非纯函数(函数副作用)

所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

var str = '海牙';
function changeStr(){str = 'kyogre';
}
console.log(str); //海牙
change();
console.log(str); //kyogre
匿名函数
 //匿名函数var x = function () {console.log('我是谁?');}x();//IIFE 匿名函数自调用  (匿名函数)(); (匿名函数());(function () {console.log('我是IIFE自调用函数');})();(function () {console.log('我是IIFE自调用函数');}());
柯理化
//柯理化function pure(a, b) {return a + b;}var result = pure(1, 2); //3function currying(a) {return function (b) {return a + b;}}var result = currying(9)(3); //12console.log(result);

作用域

/*javascript 有作用域概念script 是全局域函数 局部域函数内的变量 是 局部变量局部内可以访问全局变量局部外不可以访问局部内的私有变量*/
全局变量和局部变量
  • 全局变量

    在任何地方都可以访问到的变量就是全局变量,对应全局作用域

  • 局部变量

    只在固定的代码片段内可访问到的变量,最常见的例如函数内部。对应局部作用域(函数作用域)

不使用var声明的变量是全局变量,不推荐使用。
变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
块级作用域(){}

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
在es5之前没有块级作用域的的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域

词法作用域

变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。

在 js 中词法作用域规则:

  • 函数允许访问函数外的数据.
  • 整个代码结构中只有函数可以限定作用域.
  • 作用域规则首先使用提升规则分析
  • 如果当前作用规则中有名字了, 就不考虑外面的名字
var num = 123;
function foo() {console.log( num );
}
foo();
if ( false ) {var num = 123;
}
console.log(num); // undefiend
作用域链

只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。

将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。

// 案例1:
function f1() {function f2() {}
}var num = 456;
function f3() {function f4() {    }
}

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5Czwn%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20250714145428393.png&pos_id=img-KZMmZx1P-1752832747005
)

判断全局作用域还是局部作用域

 /*1. 在当前域寻找 x 的声明 => 没有 (确定x不是局部变量)2. 向上一级域寻找 x 的声明 一直一层一层找到 全局作用域 => 也没有声明3. 在全局进行隐式声明*/

预解析

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程

/*1. 在javascript中 有全局作用域(script) 有局部作用域 (函数{})2. 作用域是单向可访问 内部作用域可以访问外部作用域的变量 外部作用域不可以访问内部作用域的私有变量3. 私有变量 指的是 在当前局部作用域下*声明*的变量 , 如果没有声明符就不是当前作用域的私有变量4. 在调用没有声明的变量的时候 会向上一级作用域寻找 声明 一直找到 全局作用域为止.5. 变量的访问 优先访问自己作用域内的局部变量 自己作用域找不到 向上寻找调用6. 如果一个变量 在局部作用域中直接使用 但是没有声明, 并且向上一直寻找到 全局作用域 也没有 var 声明 ,js引擎会在全局作用域进行隐式声明*/
/*javascript引擎会对代码进行预解析1. 寻找所有的声明 并提升2. 按照顺序 执行所有的 执行语句步骤:1、一层一层作用域解析先解析全局作用域 然后解析局部作用域(先解析全局再解析局部作用域)2、声明有两种 1 变量声明  2 函数声明,提升到 当前作用域最顶端(变量提升)3、写执行语句先提升var,再提升function- 变量提升定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。- 函数提升JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面代码执行分两个阶段1. 寻找变量声明 并且提升2. 按照顺序执行所有的执行语句;*/

JavaScript的执行过程

var a = 25;
function abc (){alert(a);//undefinedvar a = 10;
}
abc();
// 如果变量和函数同名的话,函数优先
console.log(a);//25
function a() {console.log('aaaaa');
}
var a = 1;
console.log(a);//1

预解析:

全局:

//变量提升
var a
function abc ()
function a()//写执行语句
a = 25;
abc();
// 如果变量和函数同名的话,函数优先
console.log(a);
a = 1;
console.log(a);

局部:

function abc (){var a;//变量提升alert(a);a = 10;
}function a() {console.log('aaaaa');
}

对象 Object

创建对象方式(自定义)

创建对象有三种基础方式: 对象字面量 原生对象实例化 自定义构造函数

  • 字面量对象
var myCat = {name: '橘子',color: 'orange',age: 1,favorite: '小鱼干',speak: function(){ console.log('喵~~喵~喵~~~');}
}
  • 原生对象实例化 new Object()
var myCat = new Object();
myCat.name = '橘子';
myCat.color = 'orange';
myCat.age = 1;
myCat.favorite = '小鱼干';
myCat.speak = function(){console.log('喵~~喵~喵~~~');
}
  • 工厂函数创建对象
function createCat(name,age,color){var cat = new Object();cat.name = name;cat.color = color;cat.age = age;cat.favorite = '小鱼干';cat.speak = function(){console.log('喵~~喵~喵~~~');}return cat;
}var myCat = createCat('橘子',1,'orange');
  • 自定义构造函数
function Cat(name,age,color,favorite){this.name = name;this.age = age;this.color = color;this.favorite = favorite;this.speak = function(){console.log('喵~~喵~喵~~~');}
}
var myCat = new Cat('橘子',1,'orange','小鱼干');

构造函数

面向对象编程’的第一步,就是要生成对象。而js中面向对象编程是基于构造函数(constructor)和原型链(prototype)的。

前面说过,“对象”是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后“对象”根据这个模板生成。

js语言中使用构造函数(constructor)作为对象的模板。所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。

function Person(name,age,sex){ //Person就是构造函数this.name = name;this.age = age;this.sex = sex;this.speak = function(){console.log('我叫' + this.name + ',今年:' + this.age + '岁,性别:' + this.sex);}
}
  a:构造函数的函数名的第一个字母通常大写。b:函数体内使用this关键字,代表所要生成的对象实例。c:生成对象的时候,必须使用new命令来调用构造函数。

this详解

JavaScript中的this指向问题,有时候会让人难以捉摸,随着学习的深入,我们可以逐渐了解
现在我们需要掌握函数内部的this几个特点1. 函数在定义的时候this是不确定的,只有在调用的时候才可以确定2. 一般函数直接执行,内部this指向全局window3. 函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象(被谁调用了该函数就指向谁)4. 构造函数中的this其实是一个隐式对象,类似一个初始化的模型,所有方法和属性都挂载到了这个隐式对象身上,后续通过new关键字来调用,从而实现实例化(构造函数中this指向实例对象)

一般函数直接执行,内部this指向全局window

function f1() {console.log(this);}window.f1(); //window调用的f1

函数被谁调用了就指向谁

var obj = {name: '哈哈哈',showName: function () {console.log(this.name);}}obj.showName();//obj对象调用了showName方法(函数) showName函数里面的this指向obj  this.name === obj.name

构造函数中this指向实例对象

function Student(name, age, sex) {//虚拟对象 => thisthis.name = name;this.age = age;this.sex = sex;this.speak = function () { //console.log('我要学习,学习使我快乐,学习让我成长!' + '我叫' + this.name);}// return this;}var x = 18;var stu3 = new Student('张三', 18, 1); //this指向实例化的 stu3

对象的使用

遍历对象的属性

通过for…in语法可以遍历一个对象

var obj = {};obj.name = 'object';
obj['name'] = 'object';var key = 'name';console.log(obj[key]);for (var i = 0; i < 10; i++) {obj[i] = i * 2;
}for(var key in obj) {console.log(key + "==" + obj[key]);
}
删除对象的属性
function fun() { this.name = 'mm';
}
var obj = new fun(); 
console.log(obj.name); // mm 
delete obj.name;
console.log(obj.name); // undefined

方法

Object.is()
 // Object.is() 判断是否为同一个值console.log(Object.is(NaN , NaN));//trueconsole.log(NaN === NaN);//falsefunction a() {}function b() {}//虽然a和b都是空的函数,但是他们的地址不一样,是分开存储的,所以不一样console.log(Object.is(a , b));//false//通过赋值的方式,把内容直接给bb = a;console.log(Object.is(a , b));//true
Object.freeze()
// Object.freeze() 冻结对象var obj ={name:"lisi",age:18}obj.age = 20;Object.freeze(obj);obj.age = 30;//冻结对象后不会对对象有影响console.log(Object.freeze(obj));//返回对象console.log(obj.age);//20
Object.assign()
      // Object.assign() 连接对象var obj1 = {a: 1,b: 2,c: 3}var obj2 = {b: 6,f: 7,e: 8}obj = Object.assign(obj1 , obj2);/*连接对象的时候,有相同的属性或者方法的时候会进行覆盖返回值:连接后的对象*/console.log(obj);//{a: 1, b: 6, c: 3, f: 7, e: 8} /*连接第一个对象,也会进行更改*/console.log(obj1);//{a: 1, b: 6, c: 3, f: 7, e: 8} /*连接第二个对象,不会进行更改*/console.log(obj2);//{b: 6, f: 7, e: 8} 
Object.keys()
// Object.keys() 返回一个数组,按顺序存储着对象的属性名var obj = {a: 1,b: 2,c: 3,f: 7,e: 8}console.log(Object.keys(obj));//['a', 'b', 'c', 'f', 'e']//如果是数组进行使用,返回的是对应数组下标var arr = ["a" , "b" , "c"];console.log(Object.keys(arr));//['0', '1', '2']

JSON格式对象

JSON即Javascript对象表示方法 (Javascript Object Notation) ,也就是通过字面量来表示一个对象:

JSON 语法:

数据使用键名/值对表示,键名是字符串,值没有限定;
例如 “language”:”Java”
每个数据之间由逗号分隔;
使用大括号保存对象,对象可以包含若干个数据;
使用方括号保存数组,数组值使用“,”分割;

JSON数据使用’”键名”:”值”’的形式,其中键名要求是字符串,而值 可以是以下任意类型:

  1. 数值(整数,浮点数)
  2. 字符串(在双引号中)
  3. 逻辑值(true/false)
  4. 数组(在方括号中)
  5. 对象(在花括号中)
JSON 示例:
var nodeDate = {"NodeName" : "P","NodeType" : "Node.ELEMENT_NODE","NodeId" : "","NodeClassName" : "des","NodeStyle": "text-align:center;color:blue;font-size:22px;text-indent:2em;","NodeContent":"哈哈哈哈","NodeChildElement" : []
}
JSON方法API:
JSON.parse() 反序列化

解析JSON字符串,将JSON字符串转换为对象类型

var json = '{"result":true, "count":42}';
var obj = JSON.parse(json);console.log(obj);//{result: true, count: 42}console.log(obj.count);//42
console.log(obj.result);// trueconsole.log(typeof obj);//'object'

异常

若传入的字符串不符合 JSON 规范,则会抛出 SyntaxError 异常
JSON.stringify() 序列化

方法将一个 JavaScript 对象或值转换为 JSON 字符串

console.log(JSON.stringify({ x: 5, y: 6 }));
//  "{"x":5,"y":6}"console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)]));
//"[3,"false",false]"console.log(JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] }));
//  "{"x":[10,null,null,null]}"console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
//  ""2006-01-02T15:04:05.000Z""

异常

当发现循环引用时,抛出类型错误TypeError(“循环对象值”)异常。
当试图将BigInt (BigInt 为javascript中Number能表示的最大数 2^53 - 1 )值字符串化时,会抛出类型错误 TypeError(“BigInt值不能在JSON中序列化”)。

总结

<!-- 包装对象 instanceofjavascript中 分基础类型和对象类型null undefined string number boolean array objectfunction基础内置对象String Number Boolean Array Function Object Null RegExp Date Math JSON Error Arguments 字面量 直接的书写"值" 在存储的时候 不考虑他的构造对象 使用的时候 会通过包装对象进行包装 使用后 销毁包装对象实例化和字面量赋值区别1. 字面量单纯的值 存储更迅捷 占用空间更少 栈空间存储 值 2. 实例化对象 出生的时候就拥有对应构造函数内置属性 方法 完整的对象 对象包装调用 字面量形式会临时生成一个包装对象来帮助完成属性调用和方法调用 然后包装对象自我销毁实例化 可以直接用 不需要包装对象-->

Date对象方法

//使用Date先声明一个Date对象var date = new Date();var date1 = new Date("2020-10-05");//直接打印对象,会打印默认模板console.log(date);//Thu Nov 21 2024 16:28:08 GMT+0800 (中国标准时间)console.log(date1);/*用毫秒表示当前的时间毫秒数:1970年1月1日(世界标准时间)起的毫秒数*/// 1、valueOf用于获取对象的原始值console.log(date.valueOf());//1732177837267//2、Date.now()console.log(Date.now());//1732178011059//获取对应的时间console.log(date.getFullYear());//年console.log(date.getMonth()+1);//月,月份要+1,因为从0开始计数console.log(date.getDay());//星期console.log(date.getDate());//日console.log(date.getHours());//时console.log(date.getMinutes());//分console.log(date.getSeconds());//秒

Math对象方法

/*1、属性*/Math.E  //属性表示自然对数的底数(或称为基数),e,约等于 2.718。Math.LN10 //属性表示 10 的自然对数,约为 2.302:Math.LN2 // 属性表示 2 的自然对数,约为 0.693:Math.LOG10E //属性表示以 10 为底数,e 的对数,约为 0.434:Math.LOG2E //属性表示以 2 为底数,e 的对数,约为 1.442:Math.PI //表示一个圆的周长与直径的比例,约为 3.14159:Math.SQRT1_2 // 属性表示 1/2 的平方根,约为 0.707:Math.SQRT2 //属性表示 2 的平方根,约为 1.414:/*2、方法*/console.log(Math.abs(-1));//1 取绝对值console.log(Math.abs("-1"));//1 取绝对值console.log(Math.abs(null));//0 取绝对值console.log(Math.abs("null"));//NaN 取绝对值console.log(Math.sin("0.5"));console.log(Math.cos("0.5"));console.log(Math.tan("0.5"));console.log(Math.max(1,2,3,4,5));//5取最大值console.log(Math.min(1,2,3,4,5));//1取最小值console.log(Math.pow(2,3));//8 幂次方console.log(Math.sqrt(16));//4 平方根console.log(Math.random());//生成(0,1]的伪随机数//生成-100到100的随机数console.log(Math.random() *200 - 100);//取整//1、~~console.log(~~(1.5));//1console.log(~~(1.7));//1//2、Math.round()四舍五入console.log(Math.round(1.5));//2console.log(Math.round(-1.5));//-1console.log(Math.round(-1.51));//-2//3、Math.floor() 向下取整:返回小于或等于一个给定数字的最大整数console.log(Math.floor(1.5));//1console.log(Math.floor(-1.5));//-2//4、Math.ceil()函数返回大于或等于一个给定数字的最小整数 console.log(Math.ceil(1.5));//2console.log(Math.ceil(-1.5));//-1

执行上下文

1. 什么是执行上下文

简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行

2. 执行上下文的类型

执行上下文总共有三种类型:

  • 全局执行上下文: 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。

    /*由上至下 一句 一句 执行代码1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。*/
    
  • 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤,具体过程将在本文后面讨论。

  • Eval 函数执行上下文: 运行在 eval 函数中的代码也获得了自己的执行上下文,但由于eval是魔鬼 我们一般不通过eval进行开发操作。

执行上下文的生命周期

执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段

执行阶段

javascript是单线程的

垃圾回收机制
/*垃圾回收机制 垃圾GC回收函数没有执行的时候有对应的函数存储空间存放函数内容体(不解析)函数开始执行的时候 会解析内容 根据内容 声明变量赋予空间函数执行完成之后 私有局部变量的地址空间会被回收(私有变量在没有被期望需要的时候)闭包*/

箭头函数指向:

箭头函数没有自己的 this,而是继承定义时所在作用域的 this

简而言之就是,当前作用域(function、{})的父级的this指向

高级部分

Function方法 与 函数式编程

call

call语法实质上就是狸猫换太子(this指向改变)

函数.call(参数1,参数2)

函数.call(参数1)

参数1必填(null指向函数本身),参数2可有可无

表示函数执行函数.(参数2),函数内部{}数据的this指向参数1,函数的形参为参数2

let pig = {name:'XIAOHUA',age:1,}let otherPig = {name:'XIAOHONG',age:2,showName(){console.log(`${this.name}是我的名字`);console.log(this);}}function showName(){console.log(`我的名字:${this.name}`);console.log(this);}showName.call(pig);//表示showName.(),this指向pig//我的名字:XIAOHUA//{name: 'XIAOHUA', age: 1}otherPig.showName.call(pig);//XIAOHUA是我的名字//{name: 'XIAOHUA', age: 1}
 function add() {return [].reduce.call(arguments,function (acc,current) {return acc + current;});}console.log(add(1,2,3,4,5));//15===function add() {return [].reduce(function (acc,current) {return acc + current;//this指向arguments([1,2,3,4,5])});}console.log(add(1,2,3,4,5));//15

apply

call: 方法.call(替换对象,参数1,参数2,…参数n)

apply: 方法.call(替换对象,[参数1,参数2,…参数n])

arguments的形式是[参数1,参数2,…参数n],当不定参的时候,使用apply

function numMax() {return Math.max.apply(null,arguments);}console.log(numMax(1,2,3,4,555));//555

柯理化函数(currying)

柯里化:将n个参数的函数转化成n个单一参数函数

闭包:主要通过函数嵌套来实现

currying函数:传参(fn,参数1,参数2…参数n)

fn执行函数(操作函数) 累加、累乘…

 function currying(fn) {const args = Array.prototype.slice.call(arguments, 1);const inlay = function () {if (arguments.length === 0) {return fn.apply(this, args);}if(arguments.length > 0 ){Array.prototype.push.apply(args, arguments);return inlay;}     }return inlay;}function add() {const vals = Array.prototype.slice.call(arguments);return vals.reduce((pre, val) => {return pre + val;});}let newAdd = currying(add, 1, 2, 3);newAdd(4, 5);newAdd(6, 7)(6)(2, 3);console.log(newAdd()); //39

bind

/*bind绑定方法.bind(对象,参数1,参数2....参数n);使用bind,会返回新函数,与方法函数一模一样但是对象指向bind绑定的对象对象:绑定对象参数:固定参数绑定:bind只能在赋值和声明中的时候添加,并且后期执行时使用call和apply改变this都是无效的call和apply是在执行的时候添加*/
let cat = {name:'MIMI',age:1,showAge:function() {console.log(`${this.age}是我的年龄`);}}let catHua = {name:'XIAOHUA',age:3,showName:function() {console.log(`${this.name}是我的名字`);}}//bind只能在声明和赋值的时候添加let catAge = function showAge() {console.log(`我的年龄是${this.age}`);}.bind(catHua);// cat.showAge.call(catHua); //3是我的年龄catAge();//我的年龄是3//即使通过call改变对象为cat,但是函数已经绑定了catHua,无法改变this指向catAge.call(cat);//我的年龄是3let catName = catHua.showName.bind(cat);catName();//MIMI是我的名字catName.call(catHua);//MIMI是我的名字
 function add() {return [].reduce.call(arguments,function(arr,curr) {return arr + curr;});}//bind除了第一个参数表示指向的对象,其他的都是固定参数let count = add.bind(null,2,3);console.log(count(1,8));//14  (2+3+1+8)

实例

/*fn1参数1 cb 回调函数参数2 arguments 不定参返回值: 执行cb 回调函数的结果 = resultargs [fn1传进来的不定参除了第一个参数(回调函数)]*/function fn1(cb) {console.log(arguments);let args = [].slice.call(arguments, 1);//[不定参除了第一个参数]return cb.apply(null, args);}let result = fn1(function () {return [].reduce.call(arguments, function (acc, curr) {return acc + curr;});}, 2, 3, 4, 5, 6); //20console.log(result);

面向对象编程

/*面向对象:1.写构造函数 function Ball(){属性;方法}2.创建对象     let ball = new Ball();通过构造函数创建出来的对象,可以直接用 Instanceof 判断对象是否为创建出来的对象ball Instanceof Ball*/

原型 prototype

/*原型 prototype原型:用来承载DNA中的行为的载体(与生俱来的都在原型里面)原型是一个对象有constructor,构造函数本身[Prototype]承载DNA*/
function Ball(ele, s = 1) {this.ele = ele;this.x = s;this.y = s;}function Unit(ele, s = 1) {this.ele = ele;this.x = s;this.y = s;this.reg = 30;}let ball = new Ball();let unit = new Unit();console.log(Ball.prototype);//返回一个对象{}
//1、覆盖的方式,写入DNA,会覆盖constructorUnit.prototype = {map: function () {//原型方法中 通过this访问实例对象console.log(this.x);},move: function () {console.log('move Unit')}}console.log(Unit.prototype);//返回一个对象{}//2、非覆盖的方式,写入DNA,分开写入(推荐),不会覆盖constructorBall.prototype.map = function () {//原型方法中 通过this访问实例对象console.log(this.x);}Ball.prototype.move = function () {console.log('move ball')}console.log(Ball.prototype);//返回一个对象{}
/*原型 prototype原型是一个对象原型是函数function的属性constructor就是构造函数是prototype的属性pig.__proto__ = Pig.prototype;pig.__proto__  //实例查看原型的方式Pig.prototype  //构造函数查看原型的方式function () {prototype:{constructor:fuction Pig(){}  //构造函数}}javaScript没有函数的区分,为了进行面向对象把函数名大写第一个字母,当做构造函数,否则为普通函数实例化对象通过 new 构造函数()来实例化对象Pig() 为构造函数pig   为实例*/
//构造函数function Pig(name = 'XIAOHUA',age = 1){this.name = name;this.age = age;this.show = function () {console.log(`我是${this.name},今年${this.age}岁了`);}}let pig = new Pig('HUAHUA');//实例化对象console.log(pig instanceof Pig);//true//向原型里面添加属性Pig.prototype.eat = function() {console.log(`我是${this.name},我想吃饭了`);};//即使实例pig的构造函数Pig没有eat()方法,但是原型里面有,可以直接使用pig.eat();//我是HUAHUA,我想吃饭了pig.show();//我是HUAHUA,今年1岁了  构造函数Pig有的console.log(Pig.prototype);//构造函数查看原型的方式console.log(pig.__proto__);//实例查看原型的方式console.log(Pig.prototype === pig.__proto__);//true//constructor是prototype的属性console.log(Pig.prototype.constructor);console.log(pig.__proto__.constructor);
原型的属性和方法
/*原型prototype查找属性或方法实例去找对应的属性或者方法时优先级:自身构造函数 > 原型内的属性意思就是如果自身构造函数找不到对应属性或方法,再去原型里面查找赋值构造函数进行赋值,添加属性或方法是公共的实例进行赋值,添加属性或方法是实例私有的引用类型([])如果属性是引用类型(堆栈保存,如数组[],改变数组内的元素值,能引用该数组的都会随之改变)prototype原型上的属性 1. 方法 函数 公用性最高2. 非引用类型的值 固定参数(眼睛数量等常量)3. 公共集合 引用类型(数组[])*/
let num = [1,2,3,4];function Pig(name = 'HUAHUA',age =1,weight) {this.name = name;this.age = age;this.weight = weight;this.num = num;this.show = function () {console.log(`我是${this.name},今年${this.age}岁了`);}}let pig = new Pig('小布',2,100);let pig2 = new Pig('小美',1,200);Pig.prototype.eyes = 2;Pig.prototype.weight = 150;//优先级:自身构造函数 > 原型内的属性console.log(pig.eyes,pig2.eyes);//2 2console.log(pig.weight,pig2.weight);//100 200//改变的是私有,即在构造函数内添加一个私有属性eyes,并没有改变原型prototype内的eyes属性pig.eyes = 3;console.log(pig.eyes,pig.__proto__.eyes);//3 2console.log(pig.eyes,pig2.eyes);//3 2//属性是引用类型([]堆栈保存地址)pig.num[0] = 9;console.log(pig.num);//[9, 2, 3, 4] console.log(pig2.num);//[9, 2, 3, 4]console.log(Pig.prototype.num); //undefined
原型链
/*原型是一个对象实例化.__proto__ => Objectlet 实例化对象 = new 构造函数();实例化对象.__proto__ === 构造函数.prototypeFunctionArrayObjectStringBooleanNumber*/let arr = new Array();console.log(arr.__proto__ === Array.prototype);//trueconsole.log(arr.__proto__.__proto__ === Object.prototype);//true//--------1、对象.prototype.__proto__ === Object.prototype-------console.log(Array.prototype.__proto__ === Object.prototype);//trueconsole.log(String.prototype.__proto__ === Object.prototype);//trueconsole.log(Function.prototype.__proto__ === Object.prototype);//trueconsole.log(Number.prototype.__proto__ === Object.prototype);//trueconsole.log(Boolean.prototype.__proto__ === Object.prototype);//true//---------2、每一个实例化对象都是由构造函数通过new出来的------------//1、函数对象也是由构造函数通过new出来的,把Function看成实例化对象,Function看成构造函数//2、对象也是函数 把Object看成实例化对象,Function看成构造函数console.log(Function.__proto__ === Function.prototype);//trueconsole.log(Object.__proto__ === Function.prototype);//true//-------3、为了形成闭环 原型链中,对象的原型的原型是null-----------console.log(Object.prototype.__proto__ === Object.prototype);//falseconsole.log(Object.prototype.__proto__);//null
原型判断
/*let 实例化对象 = new 构造函数();实例化对象.__proto__ === 构造函数.prototype*/
/*1、isPrototypeOf()作用判断实例化对象的原型(__proto__)是否是构造函数的原型(prototype)使用构造函数.prototype.isPrototypeOf(实例化对象)*/function Pig(name = 'XIAOHUA',age = 1) {this.name = name;this.age = age;}let pig = new Pig();console.log(pig.__proto__ === Pig.prototype);//trueconsole.log(Pig.prototype.isPrototypeOf(pig));//true
/*2、Object.getPrototypeOf()使用Object.getPrototypeOf(实例化对象)作用返回实例化对象的原型(__proto__)*/console.log(Object.getPrototypeOf(pig) === Pig.prototype);//trueconsole.log(Object.getPrototypeOf(pig));//ƒ () { [native code] }
/*hasOwnProperty('属性')实例化对象.hasOwnProperty('属性')作用判断属性是否有该属性或者是自身构造函数内的,而非原型里面的是自身构造函数内的返回true不存在或者在原型内返回false*/Pig.prototype.sex = '男';console.log(pig);//age: 1 name: "XIAOHUA"  并没有原型添加的sex属性console.log(pig.hasOwnProperty('name'));//trueconsole.log(pig.hasOwnProperty('sex'));//falseconsole.log(pig.hasOwnProperty('show'));//false
/*in作用判断属性是否有该属性,不区分是否在原型*/console.log('name' in pig);//trueconsole.log('sex' in pig);//true/*in 与 !!obj[key]的区别当属性值为隐式转换成false的会影响!!obj[key]的结果in不会受到影响*/let obj = {a: 2,b:undefined,c:0,d:'',e:false,f:null,g:NaN}console.log(!!obj['a']);//trueconsole.log('a' in obj);//trueconsole.log(!!obj['b']);//falseconsole.log('b' in obj);//trueconsole.log(!!obj['c']);//falseconsole.log(!!obj['d']);//falseconsole.log(!!obj['e']);//falseconsole.log(!!obj['f']);//falseconsole.log(!!obj['g']);//false
原型继承
function Parent1(name) {this.name = name;}Parent1.prototype.showName = function () {console.log(this.name)}Parent1.prototype.showAge = function () {console.log(this.age)}function Parent2(age) {this.age = age;}Parent2.prototype.showSomething = function () {console.log('something')}function Child(name, age, address) {Parent1.call(this, name);Parent2.call(this, age);this.address = address;}
		//1.原型继承Child.prototype = Object.create(Parent1.prototype);// Object.assign(Child.prototype,Parent2.prototype);//直接Object.create会覆盖,使用Object.assign(A,B),把B拼接到A里面
mixProto(Child, Parent1, Parent2);/** @Description:用于多重继承,子级继承第一个父级和第二个父级* @param {Strng}targetClass: 子级构造函数名* @param {Strng}parentClass: 第一个父级构造函数名* @param {Strng}otherParent: 第二个父级构造函数名*/function mixProto(targetClass, parentClass, otherParent) {targetClass.prototype = Object.create(parentClass.prototype);Object.assign(targetClass.prototype, otherParent.prototype);}let child = new Child('xiaohua',1);//进行了多重继承,可以调用多个父级child.showSomething();//somethingchild.showAge();//1child.showName();//xiaohua
原型继承 + 构造函数继承
 /*原型继承 +  构造函数继承 = 组合继承 (js经典继承)Pig、Cat都去继承Animal的一些公共属性和方法1、把父级Animal赋值给Pig原型,就可以继承AnimalPig.prototype = new Animal();new Animal()返回的是一个Animal对象包括Animal构造函数写入的属性和方法还有写入Animal原型的属性和方法2、父级Animal赋值给Pig原型的时候,constructor属性会被覆盖,需重新覆盖Pig.prototype.constructor = Pig;3、改变this指向在对应构造函数内添加:Animal.call(this,name,age,sex);                     */
function Animal(name='XIAOHUA',age=1,sex='公'){this.name = name;this.age = age;this.sex = sex;}Animal.prototype.show = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,今年${this.age}岁了,性别${this.sex}`);}Animal.prototype.eat = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,现在要吃饭了`);}function Pig(name='XIAOHUA',age=1,sex='公',weight=100){Animal.call(this,name,age,sex);this.weight = weight;}function Cat(name='HUAHUA',age=2,sex='母',color='orange'){Animal.call(this,name,age,sex);this.color = color;}// console.log(new Animal());//Animal对象Pig.prototype = new Animal();Pig.prototype.constructor = Pig;Cat.prototype = new Animal();Cat.prototype.constructor = Cat;Pig.prototype.eat = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,现在要吃饭了,体重${this.weight}斤了`);}Cat.prototype.show = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,今年${this.age}岁了,性别${this.sex}${this.color}`);}let pig = new Pig();let cat = new Cat();pig.show();//我是XIAOHUA,属于Pig类目,今年1岁了,性别公pig.eat();//我是XIAOHUA,属于Pig类目,现在要吃饭了,体重100斤了cat.show();//我是HUAHUA,属于Cat类目,今年2岁了,性别母,orange色cat.eat();//我是HUAHUA,属于Cat类目,现在要吃饭了
跨代继承
/*跨代继承 既可以调用父类的方法 也可以调用祖类的方法*/function Animal(name = 'ani') {this.name = name;}Animal.prototype.sayHi = function () {console.log(`我是${this.name} 我是Animal的方法`)}function Person(name = '人', lan = 'ZH-cn') {Animal.call(this, name);this.lan = lan;}//父级继承了祖代的原型Person.prototype = Object.create(Animal.prototype);Person.prototype.constructor = Person;Person.prototype.sayHi = function () {console.log(`我是${this.name} 我是Person的方法`)}function Student(name, lan, grade = 3) {Person.call(this, '学生', '汉语')this.grade = grade}//子级继承父级原型Student.prototype = Object.create(Person.prototype);Student.prototype.constructor = Student;//子级继承祖级原型(加到子级的属性里面)Student.prototype.parent = Object.create(Animal.prototype)let stu = new Student();//继承的父级sayHistu.sayHi();//我是学生 我是Person的方法//继承的祖级sayHi,在属性parent内进行调用//使用call解决this指向问题stu.parent.sayHi.call(stu);//我是学生 我是Animal的方法
组合寄生继承
 /*Object.create()组合寄生继承 原型继承 +  构造函数继承 = 组合寄生继承 1、原型继承子级.prototype = Object.create(父级.prototype);Pig.prototype = Object.create(Animal.prototype);2、constructor属性会被覆盖,需重新覆盖子级.prototype.constructor = 子级;3、构造函数继承在对应构造函数内添加:父级.call(this);Animal.call(this);new Animal();//父级Anomal的属性和方法都有Object.create(Animal.prototype);//只有父级的方法        */function Animal(name,arr){this.name = name;this.arr = [1,2,3,4];}Animal.prototype.show = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,今年${this.age}岁了,性别${this.sex}`);}Animal.prototype.eat = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,现在要吃饭了`);}function Pig(weight){Animal.call(this);this.weight = weight;}// Pig.prototype = new Animal();Pig.prototype = Object.create(Animal.prototype);Pig.prototype.constructor = Pig;Pig.prototype.eat = function () {console.log(`我是${this.name},属于${this.constructor.name}类目,现在要吃饭了,体重${this.weight}斤了`);}let pig1 = new Pig();pig1.arr.push(9);console.log(pig1.arr);//[1, 2, 3, 4, 9]let pig2 = new Pig();console.log(pig2.arr);//[1, 2, 3, 4]

对象Object

super 关键字

我们知道,this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象。

const proto = {foo: 'hello'
};const obj = {foo: 'world',find() {return super.foo;}
};Object.setPrototypeOf(obj, proto);
obj.find() // "hello"

上面代码中,对象obj.find()方法之中,通过super.foo引用了原型对象protofoo属性。

注意,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。

可枚举

可枚举属性:通过循环遍历的方式找到的属性

Object.entries()

将对象的键值对以数组的形式存放在数组里面

/*Object.entries(obj)返回一个二维数组[['key1',value1],['key2',value2]...]该二维数组也是键值对列表的形式*/	let obj = {a:1,b:2,c:3,d:4}console.log(JSON.stringify(obj));//{"a":1,"b":2,"c":3,"d":4}console.log(Object.entries(obj));//[['a', 1]['b', 2]['c', 3]['d', 4]]let arr = (Object.entries(obj)).map(([key,value]) => [key,value*3]);console.log(arr);//[['a', 3]['b', 6]['c', 9]['d', 12]]
Object.fromEntries()
 /*Object.fromEntries(obj)把键值对列表转换为一个对象*/console.log(Object.fromEntries(arr));//{a: 3, b: 6, c: 9, d: 12}
Object.keys()

将对象的key以字符串的形式存放在数组里面

const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

Class

/*class       关键字extends     继承static      静态属性/方法constructor 构造函数super();    this指向继承父级*/
/*classconstrutor构造函数方法自身属性      */class Pig {constructor(name,age) {//构造函数this.name = name;this.age = age;}//-------属性、方法函数--------static xxx = 10;static showMe() {console.log(this.name); //指向类本身 不是指向实例化对象}showName() {console.log(this.name);}showAge() {console.log(this.age);}}class Spig extends Pig{constructor(name,age,sex){super(name,age);this.sex = sex}showAge() {console.log(this.age + '岁');}}let pig = new Spig('haha',1,0);let pig1 = new Pig('huahua',2);pig.showAge();//1岁pig1.showAge();//2console.log(pig.name);//haha//静态方法和函数只能该类使用Pig.showMe();//Pigconsole.log(Pig.xxx);//10pig1.showMe();//报错,静态获取不到console.log(pig1.xxx);//undefined 静态获取不到
//-------------组合寄生继承---------------------------function Pig(name,age) {this.name = name;this.age = age;}Pig.prototype.showName = function() {console.log(this.name);}Pig.prototype.showAge = function() {console.log(this.age);}function Spig(name,age,sex) {Pig.call(this,name,age);this.sex = sex;}Spig.prototype = Object.create(Pig.prototype);Spig.prototype.constructor = Spig;Spig.prototype.showAge = function() {console.log(this.age + '岁');}let pig = new Spig('haha',1,0);console.log(pig.name);//hahapig.showAge();//1岁pig.showName();//haha

Promise

/*Promise是一个对象,使用时要new实例化处理回调函数多的情况Promise(function(reslove,reject){})参数:一个函数functionfunction参数有两个回调函数作为参数reslove:成功时调用的回调函数reject:失败时调用的函数对两个回调函数的设置使用then()方法then(fn1,fn2),两个参数时fn1:reslove函数的实参,成功时函数内容fn2:reject函数的实参,失败时函数内容使用then()、catch()方法then(fn1)1个参数时,和catch(fn2)方法一起使用fn1表示成功时函数内容fn2表示失败时函数内容*/
let x = 8;function p(x) {return new Promise(function (reslove, reject) {if (x < 10) {//成功时的回调函数reslove(x);}//失败时调用的函数reject(x);});}let pro = p(x);pro.then((x) => {x++;console.log(`'x<10',x=${x}`); //'x<10',x=10return p(x);}).then((x) => {x++;console.log(`666, x=${x}`);return p(x);}).then((x) => {x++;console.log(`666, x=${x}`);return p(x);}).catch((x) => console.log(`'x>=10',x=${x}`)); //'x>=10',x=10
let x = 8;function pro(x) {return new Promise(function (reslove, reject) {if (x >= 10) {//失败时调用的函数reject(x);return false;}//成功时的回调函数reslove(x);});}let promise1 = pro(x);promise1.then((x) => {x++;console.log(`'x<10',x=${x}`);return pro(x);},(x) => console.log(`'x>=10',x=${x}`)).then((x) => {x++;console.log(`'x<10',x=${x}`);return pro(x);},(x) => console.log(`'x>=10',x=${x}`)).then((x) => {x++;console.log(`'x<10',x=${x}`);return pro(x);},(x) => console.log(`'x>=10',x=${x}`));

Symbol

/*symble数据类型作用:形成独一无二的值*/
       //写法Symbol('属性名');let a = Symbol('index');/*虽然创建了两个Symbol('index'),但是两者是不相等的都是独一无二的,自己也不等于自己*/console.log(Symbol('index') === Symbol('index'));//false       let pig = {name:'hahha'}let cat = {name:'xiaohua'}function assign(o1, o2) {for (let key in o2) {if (o1[key]) {o1[Symbol(key)] = o1[key]}o1[key] = o2[key];}return o1;}console.log(assign(pig,cat));//{name: 'xiaohua', Symbol(name): 'hahha'}
/*Symbol('属性名')1、使用了Symbol的属性名不能进行枚举(for in 不能遍历出来)2、Symbol('属性名')有toString方法进行转化为字符串3、!!Symbol('属性名')的布尔值永远是true,因为包装成了Symbol类型,永远为true4、Symbol('属性名')不能用于任何计算5、description属性可以访问Symbol的属性名6、Symbol.for('name'),强制性全局注册一个Symbol值为 name7、Symbol.keyFor(Symbol.for('name')),返回属性名name*/
let s = Symbol('num');let obj ={}obj.s = 10;obj[s] = 20;obj['num'] = 30;console.log(obj);//{s: 10, num: 30, Symbol(num): 20}//1、使用了Symbol的属性名不能进行枚举for(var key in obj) {console.log(key);//s num}//2、Symbol('属性名')有toString方法进行转化为字符串console.log(typeof s);//symbol       console.log(typeof s.toString());//stringconsole.log(typeof String(s));//string//3、!!Symbol('属性名')的布尔值永远是trueconsole.log(!!s);//true//5、description属性可以访问Symbol的属性名console.log(s.description);//num//6、Symbol.for('属性名')let o = {// [Symbol('name')]:'HUAHUA'[Symbol.for('name')]:'HUAHUA'}//直接o.Symbol('name')是访问不到的,因为每一个Symbol('name')都是独一无二的,使用Symbol.for('name')可以console.log(o[Symbol.for('name')]);//HUAHUA//7、Symbol.keyfor('属性名'),返回属性名let x = Symbol.for('name');console.log(Symbol.keyFor(x));//nameconsole.log(Symbol.keyFor(Symbol.for('name')));//nameconsole.log(Symbol.for('name') === Symbol.for('name'));//true//4、Symbol('属性名')不能用于任何计算console.log('123' + s);//报错 Uncaught TypeError: Cannot convert a Symbol value to a string
http://www.xdnf.cn/news/1144297.html

相关文章:

  • 【JS笔记】Java Script学习笔记
  • C#将【程序集引用-依赖关系】展示到NetronLight图表中
  • Java 核心工具类 API 详解(一):从 Math 到 Runtime 的实用指南
  • 设计模式五:桥模式(Bridge Pattern)
  • wedo牛-----第47节(免费分享图纸)
  • MBIST - Memory BIST会对memory进行清零吗?
  • 基于单片机的便携太阳能光伏系统研究
  • C语言—如何生成随机数+原理详细分析
  • 20250718-FDU-HDUOJ钉耙编程一
  • 初探:C语言FILE结构之文件描述符与缓冲区的实现原理
  • 更适合后端宝宝的前端三件套之HTML
  • CentOS7 内网服务器yum修改
  • 有好内容,如何做好知识变现?
  • 【Zephyr开发实践系列】08_NVS文件系统调试记录
  • GEV/POT/Markov/点过程/贝叶斯极值全解析;基于R语言的极值统计学
  • 【案例教程】基于现代R语言【Tidyverse、Tidymodel】的机器学习方法与案例分析实践技术应用
  • [AI8051U入门第五步]modbus_RTU主机
  • stack and queue 之牛刀小试
  • Excel批量生成SQL语句 Excel批量生成SQL脚本 Excel拼接sql
  • 大型市政污水处理厂“智变”记:天拓四方IOT平台让磁悬浮鼓风机“活”起来
  • React 实现人员列表多选、全选与取消全选功能
  • MC0457符咒封印
  • Ansible + Shell 服务器巡检脚本
  • mysql not in 查询引发的bug问题记录
  • pycharm结构查看器
  • 2.3 前端-ts的接口以及自定义类型
  • 哪个厂家生产的戒烟药好:从机制到体验的差异化博弈
  • MySQL 插入时间 更新时间
  • 推荐 1 款 4.5k stars 的AI 大模型驱动的开源知识库搭建系统
  • 跨域问题及解决方案