JavaScript笔记

基础语法

DOM:文档模型

BOM:浏览器模型

ES:JavaScript标准

href:参考,联系。同步执行

src:源,载入。单独执行

严格区分大小写

环境搭建,下载node.js

  • 命令提示符中全局安装镜像服务器
npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 使用npm或cnpm安装各种模块

安装输入模块 cnpm install readlinec

  • 报错无法加载cnpm

则以管理员身份运行命令提示符,进入PowerShell

(路径C:\WINDOWS\system32>PowerShell)后,

执行 Set-ExecutionPolicy RemoteSigned 即可

  • js测试

引入 require

let readline = require("readline-sync");
let a1 = readline.question("");
let b2 = readline.question("");
console.log(a1*b2)

数据类型

基本数据类型
String

转义字符\n \t \b

  • 反引号字符串模板``类似p标签与pre,且可以插入代码:${}

  • 区别string数字和number数字的方法

    • 利用+的特性
    • 利用typeof(typeof输出的类型单词是一个字符串)
  • 类型转换

    • 调用数据的.toString 方法(实列方法) 该方法不会影响到原变量,它会将转换的结果返回

    Undefined和Null无此方法

    • 调用.String()函数,Undefined和Null转换为"Undefined" 和"Null"
    • a=a+“”
Number

NaN(非法数字),参与运算则运算结果为NaN

Infinity:正无穷,infinity不能参与计算

  • 数学函数

    • toFixed(n) 四舍五入保留n位小数
    • 求x的n次方 Math.pow(x,n)
    • 随机数生成 Math.random()
  • 类型转换

    • 用Number(),true和object为1,false和空字符串为0(静态方法)

    • 用 Number .parseInt()或~.parseFloat(),将String类型转换为Number,非String则会先转换为String

      这种转换称为隐形转换,即系统自转换

Boolean

所有具有“真实”值的即为 True

用Boolean(),0和NaN以外的Number,空字符串以外的String,Null以外的object,undefined以外的值都转换为true

Undefined

声明了变量但未赋值的,undefined是null的衍生

Null

空对象,typeof返回object

输出数据
 console.log(typeof a);
	console.log("输出一条日志");//最常用
    console.info("输出一条信息");
    console.warn("输出一条警告");
    console.error("输出一条错误");

变量声明

变量声明 let
   // 声明
    let a = 5;
    alert(a);
    // 更改
    a = 6;
    console.log(a);
常量声明 const
// 常量声明
    const a = 5;
    alert(a);
    // 更改会报错
    a = 6;
    console.log(a);
//数组常量内的值修改不会报错,但是其地址不能修改
var

同变量名可以重复声明,且声明的是全局变量,其声明部分var=a会被放到全局的顶部,但赋值仍在声明处

{var a=1;} 等价于var a; { var a=1}

 // 变量声明
    var a = 5;
    alert(a);
    // 覆盖前面的值
    var a = 6;
    console.log(a);
遗漏声明

全局变量,但不会从局部放到全局,因为其没有声明部分,所以在全局的顶部访问不到

// console.log(a); 此处访问不到 
    {
      a = 9;
    }
    console.log(a);
    // 此处可以访问

运算符

条件运算符 a?b:c ,a真执行b,a假执行c

%取余数

递增递减符号

++放前面立即增1,++放后面,下一次使用此变量时增1。

let a = 0;
    b = a++;
    c = a++;
    d = ++a;
    console.log(b);//0
    console.log(c);//1
    console.log(d);//2

逻辑运算符
  • && 且

两个值中只要有一个值为false,就返回false,只有两个值都为true时,才会返回true

JS中的“与”属于短路的与,如果第一个值为false,则不会检查第二个值(可用于简写if判断语句)

非布尔值时:如果两个都为true,则返回第二个值,如果两个值中有false,则返回靠前的false的值

  • || 或

两个值中只要有一个true,就返回true,只有两个值都为false,才会返回false

JS中的“或”属于短路的或,如果第一个值为true,则不会检查第二个值

非布尔值时:如果两个都为false ,则返回第二个值,如果两个值中有true,则返回靠前的true的值

  • ! 非

非布尔值时:先会将其转换为布尔值,然后再取反,所以我们可以利用该特点,来将一个其它的数据类型转换为布尔值,可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样

  • 三目运算 a>b?c:d (true选c,false选d)

通过逻辑运算a=!a可以实现状态切换(常用Boolean值)

比较运算符
  • 相等运算==

    当使用==来比较两个值时,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型,然后在比较

  • 不相等运算 !=

    不相等用来判断两个值是否不相等,如果不相等返回true,否则返回false,不相等也会对变量进行自动的类型转换,如果转换后相等它也会返回false

  • 全等运算===

    用来判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回false

  • 不全等运算!==

    用来判断两个值是否不全等,它和不等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回true

  • <,>

    如果只有一个是数字,另一个则隐形转换为数字。两个字符串则依次比较他们字符的ASCLL码大小

快捷生成

<body>
  <!--  .box>li.item$*3 -->
  <div class="box">
    <li class="item1"></li>
    <li class="item2"></li>
    <li class="item3"></li>
  </div>
  <!-- ul.box>li{item$}*3 -->
  <ul class="box">
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
  </ul>
  <!-- div>(span+p)*2 -->
  <div>
    <span></span>
    <p></p>
    <span></span>
    <p></p>
  </div>
    <!-- table>(thead>tr>th{arr[$]}*4+tbody>(tr>td*4)*2) -->
    <table>
      <thead>
        <tr>
          <th>arr[1]</th>
          <th>arr[2]</th>
          <th>arr[3]</th>
          <th>arr[4]</th>
      <tbody>
        <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
        </tr>
        <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
        </tr>
      </tbody>
      </tr>
      </thead>
    </table>
  <script>

  </script>
</body>


流程控制

分支语句

条件表达式会转换为Boolean值,true执行,false不执行,类似a<b<c这种条件要拆成&&运算

if…else
var age = 18;
if (age < 18) {
    console.log("小于18");
} else if (age == 18) {
    console.log("18岁了");
} else {
    console.log("大于18")
}


switch…case

case后面是和switch()所匹配的某一种值,如果case要用一个表达式来表示ture或false,则switch(true/false)

var month = 10;
switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        console.log("31天");
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        console.log("31天");
        break;
    case 2:
        console.log("28天");
        break;
    default:
        console.log("输入错误");
}


循环语句

while
var i = 1;
while (i <= 10) {
    console.log(i);
    i++;
}

大小循环的开关控制

let readline = require('readline-sync');
flagA = true;
while (flagA) {
  console.log('这是大循环');
  flagB = true;
  while (flagB) {
    console.log('这是小循环');
    console.log('请输入有Y/N');
    let user_choise = readline.question('');
    if (user_choise == 'Y') {
      continue;
    } else if (user_choise == 'N') {
      flagB = false;
      flagA = false;
    } else {
      console.log('输入有误');
    }
  }
}

while do
var i = 1;
do {
    console.log(i);
    i++;
} while (i <= 10);

for
for(初始化表达式 ; 条件表达式 ; 更新表达式){
    语句...
}


跳转控制

  • break:结束最近的一次循环,可以在循环和switch语句中使用。
  • continue:结束循环中的这一次,执行下一次循环,只能在循环中使用。
  • 可以在循环内部通过改变循环的控制变量值达到跳转的作用

跳转到指定位置

outer: for (var i = 0; i < 10; i++) {
    for (var j = 0; j < 10; j++) {
        if (j == 5) {
            break outer;
           // continue 
        }
        console.log(j);
    }
}


对象基础

在 JavaScript 中,几乎“所有事物”都是对象。

  • 布尔是对象(如果用 new 关键词定义)
  • 数字是对象(如果用 new 关键词定义)
  • 字符串是对象(如果用 new 关键词定义)
  • 日期永远都是对象
  • 算术永远都是对象
  • 正则表达式永远都是对象
  • 数组永远都是对象
  • 函数永远都是对象
  • 对象永远都是对象

所有 JavaScript 值,除了原始值( 原始值指的是没有属性或方法的值 ),都是对象。

创建对象

对象的属性可以看成一个一个的键值对

//var person = new Object();
//person.name = "孙悟空";
//person.age = 18;

var person = {
    name: "孙悟空",
    age: 18
};
//ES6中简化写法
let	sex='man';
let obj={
    sex,
}


访问对象属性
  • 常用点访问 obj.key 这是==匹配的key
  • 中括号 obj[“key”] 这是===匹配的key

当想要访问的key是用的某个变量时,类似数组遍历时使用arr[i]来访问一个不定的键

判断对象是否存在某属性

  let obj = {
    name: 'xxx'
  }
  console.log(obj.hasOwnProperty('name'));
  console.log('name' in obj);
  console.log(obj.name === undefined);

Symbol函数

ES6之前,对象的属性名默认是字符串。对一个未知的对象添加属性时,可能会因为重名而覆盖,

用法:声明一个变量=Symbol(注释);赋值;

 let obj = {
    name: '独孤',
    age: 18,
  };
//Symbol的用法
let name = Symbol('名');
  obj[name] = '小冬瓜';

console.log(obj.name + obj[name]);//独孤小冬瓜
  console.log(obj);//{ name: '独孤', age: 18, [Symbol(名)]: '小冬瓜' }

对象的引用

对象是易变的:它们通过引用来寻址,而非值。

var x = person;  // 这不会创建 person 的副本。

对象 x 并非 person 的副本。它就是 person。x 和 person 是同一个对象。

遍历对象

for…in 遍历对象的键,再在循环中log输出对应键的属性值即可

类似数组的for of keys,values,entries

let obj = {
  name: 'Xdd',
  age: '20',
  watchName: function (name = '你的名字') {
    console.log(name);
  },
};
for (let i in obj) {
  console.log(i + `` + obj[i]);
}
console.log(obj.watchName('Xbb'));
//遍历键(相当于转换为数组然后遍历)
 for (i of Object.keys(obj)) {
  console.log(i);
}

对象解构
let a = {name:"张三",age:18};
let {name:name0,age} = a;
console.log(name0);//张三
console.log(age);//18

JSON

一种数据存储格式

转字符串

let person = {
"name" : "laoliang",
"age" : 18,
"gender" : "male",
}
let str = JSON.stringify(person);
console.log(str);

转JSON

let person = '{"name":"laoliang","age":18,"gender":"male"}';
  let obj = JSON.parse(person);
  console.log(obj);

Date
//返回时间
{
let now = Date();
console.log(now);
console.log(typeof now);
}
//创建Date对象
{
  let now = new Date();
  console.log(now.toTimeString());
  console.log(now.toDateString());
  console.log(now.getMonth());
}

创建数组

一般直接创建,不推荐用数组函数Array()

  • 可以对数组的任意位置进行赋值,中间空置的位置会用undefined代替

  • 二维数组理解为一个两列的表,arr[]后面[]内的数字依次为行,列

  • JS中不支持传统编程语言中的多维数组,所以要用[]中套[]来模拟多维数组

  • 在 JavaScript 中,数组只能使用数字索引

  • 假如您使用命名索引,JavaScript 会把数组重定义为标准对象。之后,所有数组的方法和属性将产生非正确结果。

  • 在 JavaScript 中,数组使用数字索引。

    在 JavaScript 中,对象使用命名索引。

    数组是特殊类型的对象,具有数字索引。

数组的遍历
  • 最安全用for
let arr = [
 ["Bill",20],
 ["Lucy",23],
 ["David",25],
 ["Lily",18]
];
for(let i=0;i<arr.length;i++){
 for(let j=0;j<arr[i].length;j++){
 console.log(arr[i][j]);
 }
}
//delete arr[2];删除数组中的第三个元素,但是不删除位置
// Bill
// 20
// Lucy
// 23
// David
// 25
// Lily
// 18

  • 根据键值遍历对象中的属性,可以使用for … in语句循环,对象中有几个属性,循环体就会执行几次
let arr = [1, 2, 3, 4, 5];
for (let i in arr) {
 console.log('键值' + i + '的值为' + arr[i])
}

for …of 根据值来迭代遍历

  • .keys()遍历键
let arr = [3,5,8,1];
for(let i of arr.keys()){
 console.log(i);
}

  • .values()遍历值
  • .entries()遍历键和值
let arr = [3,5,8,1];
for(let i of arr.entries()){
 console.log(i);
}

解构数组
let arr = [1,2,3];
let [a,..c] = arr;//a=1,c=[2,3]
[a,b]=[b,a]//简单的值互换方法

相当于把数组里的1,2,3分解给了a,b,c。可以使用逗号来跳过不想解构的元素

扩展运算符…

取出可迭代对象的每一项,用来快速展开数组,扩展和结构混用,扩展放最后

let a = ["Bill","Mary","Lucy"];
let b = "ABC";
let c = [...a,...b];
console.log(c);
//[ 'Bill', 'Mary', 'Lucy', A, B, C ]

数组属性和方法
  • Array.isArray() 检测是否为数组

  • 数组和字符串转换 .join()和.split(分隔符)
    let arr = [];
    a = 'hello';
    arr = a.split('');
    console.log(arr);
    
    
  • 快速清空数组(设置数组的长度)

let arr = [1,2,3,4,5];
arr.length = 0;

  • 找最大值,最小值 Math.max.apply(null,arr); Math.min~

  • push和pop方法(栈),
    • push推入元素是从右往左,在栈尾操作,pop只能弹出一个元素, pop() 方法返回“被弹出”的值 。 unshift()是从左往右推入 ,shift弹出一个。在栈底操作
let arr = [];
let i = arr.push("red","blue");
console.log(arr);//[ 'red', 'blue' ]
console.log(i);//2
let j = arr.pop();
console.log(arr);//[ 'red' ]
console.log(j);//blue

  • 删除,插入,替换 splice(起始位,删除多少位,插入内容…)
let readline = require('readline-sync');
console.log('请输入一串字符:');
let num2 = readline.question('');

let arr = num2.split('');
console.log(arr);

let i = arr.splice(1, 2);
console.log(i);
console.log(arr);
// 数组中的操作-删除字符串
arr = [1, 'asd', 2, '3', '38'];
let len = arr.length;
for (i = 0; i < len; i++) {
  if (typeof arr[i] == 'string') {
    arr.splice(i, 1);
    i--; //当执行了删除操作后,数组后面部分发生前移,如果i继续增加,则会露检.从后往前删可避免此问题
  }
}
console.log(arr);

  • 截取slice(起始,结束) concat()合并之后
  • 查找

search(字符) 返回下标,-1

includes(字符,起始位) 返回Boolean

indexOf(字符,起始位) 找到返回下标,没找到返回-1

找最大值

let array = [2, 3, 55, 3, 2, 42];
let max = -Infinity;
for (let i = 0; i < array.length; i++) {
  if (array[i] > max) {
    max = array[i];
  }
}

数组排序
排序方法

reverse()倒序,

let arr = [1,2,3,4,5];
console.log(arr.reverse());//[ 5, 4, 3, 2, 1 ]
console.log(arr);//[ 5, 4, 3, 2, 1 ]


sort() 方法默认以字母顺序对数组进行排序

sort()方法也可以对数组内的对象排序

let arr = [1,2,3,4,5];
//sort()方法的数字排序修正 
arr.sort(function(a, b){return a - b}); 
//对象排序
let arr0 = [{ num: 1 }, { num: 3 }, { num: 2 }];
console.log(
  arr0.sort(function (a, b) {
    return a.num - b.num;
  })
);

选择排序

每一个依次和其他的进行比较,冒泡排序是相邻两个依次比较

{	//生成随机数
	let x = Math.floor(Math.random() * 100);
  //选择排序
  let arr = [];
  arr.length = 8;
  for (i = 0; i < arr.length; i++) {
    x = Math.floor(Math.random() * 100);
    arr[i] = x;
  }
  console.log(arr);
  console.log('选择排序结果');
  for (let j = 0; j < arr.length - 1; j++) {
    //指针=轮数
    for (let k = j + 1; k < arr.length; k++) {
      //次数
      if (arr[j] > arr[k]) {
        [arr[j], arr[k]] = [arr[k], arr[j]];
      }
    }
  }
  console.log(arr);
}


创建集合

基本方法
let s1 = new Set();
let s2 = new Set([1,2,3]);//添加数组会分解
console.log(s1);//Set {}
console.log(s2);//Set { 1, 2, 3 }
//add()方法添加元素(添加数组则为一个数组元素)
s1.add([1,2,3]);
console.log(s1);//Set { [ 1, 2, 3 ] }
//.size查看长度
console.log(s1.size);//1
//搜索
console.log(s2.has(1));//true
//删除某个元素
s2.delete("2");
//清空
s2.clear()

集合的遍历

  • for…of枚举
  • for…of .keys()
  • for…of .values()
  • for…of .entries()
除重

集合与数组之间的相互转换

let s1 = new Set([1,2,3,2]);
console.log(s1);//自动删除重复元素 Set { 1, 2, 3 }
let arr = [...s1];//扩展运算符
console.log(arr);//[ 1, 2, 3 ]

正则表达式

RegExp对象

var 变量名 = new RegExp("正则表达式","匹配模式");


匹配模式:

  • i:忽略大小写
  • g:全局匹配模式
  • ig:忽略大小写且全局匹配模式
var 变量名 = /正则表达式/匹配模式;

匹配模式:

  • i:忽略大小写
  • g:全局匹配模式
  • m:执行多行匹配

注意:可以为一个正则表达式设置多个匹配模式,且顺序无所谓

包含

常见组合:

​ [ ]表示其中之一

  • [a-z]:任意小写字母
  • [A-Z]:任意大写字母
  • [A-z]:任意字母
  • [0-9]:任意数字
// 这个正则表达式可以来检查一个字符串中是否含有字母
var reg = /[A-z]/;
var str = "Abc";
var result = reg.test(str);
console.log(result);


排除

常见组合:

  • [^a-z]:除了任意小写字母
  • [^A-Z]:除了任意大写字母
  • [^A-z]:除了任意字母
  • [^0-9]:除了任意数字
// 这个正则表达式可以来检查一个字符串中是否除了数字还有其它字母
var reg = /[^0-9]/;
var str = "0123456789";
var result = reg.test(str);
console.log(result);


符号
  • ^ :表示开头,注意它在[^字符序列]表达的意思不一样

  • $ :表示结尾

  • {n} :正好出现n次

  • {m,} :出现m次及以上

  • {m,n} :出现m-n次

  • + :至少一个,相当于{1,}

  • * :0个或多个,相当于{0,}

  • ? :0个或1个,相当于{0,1}

  • | :或

缩写

  • \w :任意字母、数字、,相当于[A-z0-9]
  • \W :除了字母、数字、,相当于[^A-z0-9]
  • \d :任意的数字,相当于[0-9]
  • \D :除了任意的数字,相当于[^0-9]
  • \s :空格
  • \S :除了空格
  • \b :单词边界
  • \B :除了单词边界
  • ?= :环视,比如匹配以.js结尾的字符串 /\w+(?=.js)/
var phone_reg = /^1[3|4|5|8][0-9]{9}$/;//常见手机号
//邮箱号
var emailStr = "abc.def@163.com";
var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
console.log(emailReg.test(emailStr));

//除去字符串中单词前后的空格
var str = "  hello child  "
var reg = /^\s*|\s*$/g;
console.log(str);
str = str.replace(reg, "");
console.log(str);

捕获

获取日期的年月日

reg=/(\d{4})-(\d{2})-(\d{2})/

括号用来分组表示范围,比如使用 /ab{2}/ 和 /(ab){2}/ 分别表示 a,b两次 和 (ab)两次

方法

split()

match():该方法可以根据正则表达式,从一个字符串中将符合条件的内容提取出来,可以设置全局匹配模式,这样就会匹配到所有的内容,match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果

var str = "1a2a3a4a5e6f7A8B9C";
var result = str.match(/[a-z]/ig);
console.log(result);
//[
  'a', 'a', 'a',
  'a', 'e', 'f',
  'A', 'B', 'C'
]

replace()方法演示:该方法可以将字符串中指定内容替换为新的内容,默认只会替换第一个,但是可以设置全局匹配替换全部。替换后return返回值,不更改原字符串

  • 第一个参数:被替换的内容,可以接受一个正则表达式作为参数
  • 第二个参数:新的内容
var str = "1a2a3a4a5e6f7A8B9C";
var result = str.replace(/[a-z]/gi, "*");
console.log(result);
//字母替换为*

函数

函数声明

function 函数名(){} 或者 var 变量=function(){} (相当于把一个匿名函数赋值给变量进行调用)

函数可以被定义为对象方法

var myObject = {
    firstName:"Bill",
    lastName: "Gates",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}
myObject.fullName();         // 将返回 "Bill Gates"

函数的调用

函数的调用必须带括号

let test = function(){
 console.log("Hello");
}
let i = test;//将test赋值给i
i();//Hello

return

函数的返回值代表函数要重内部返回给外部的值,不写return会返回undefined.

函数会以return作结束标志,后面的代码不会继续执行

return只能返回一个值(可以是一个数组)

var x = 1; 
function fn(n){
 n = n+1; 
}; 
y = fn(x);
console.log(y);//undefined(因为返回值是undefined,而不n)

提升

函数里面声明变量无论是let 还是var 都是函数作用域。外部无法访问

  • 函数提升
test();//Hello!
function test(){
 console.log("Hello!");
}//提升
let  test0=function(){
 console.log("Hello!");
}//不会提升

  • 函数中的遗漏声明是全局作用域,但是不会提升
var a = (b = 10);//这种写法只会声明前者,后者为遗漏声明
(function () {
  var a = (b = 20);//此处声明的a是函数局部变量的a,而不是覆盖
  ++a;
  console.log(a);//21
})();//立即执行函数
console.log(b);//20
console.log(a);//10

函数的参数

形参

形参名重复时,传入实参取重复值的最后一个,实参不足时,未赋值的为undefined

function test(x){
 for(let i=0;i<arguments.length;i++){
 console.log(arguments[i]);
 }
}
test(1,2,3);
// 1
// 2
// 3

函数内置对象arguments

调用函数时,可以传入多个实参,系统会在执行函数体之前,使用一个伪数组arguments来存放传入的所有实参

x = findMax(1, 123, 500, 115, 44, 88);

function findMax() {
    var i;
    var max = -Infinity;
    //通过伪数组arguments来遍历参数
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}

参数解构

fun(…arr) 会将arr数组解构,然后相当于传入arr.length个参数,也可以fun.applay(null,arr) 参考函数This

不定参数
function test(a,...b){
 console.log(a);
 console.log(b);
}
test(1,2,3);//1 [2,3]

不定参数要放在形参最后

默认参数

默认参数用 形参=赋予,数组的默认参数写法如下

let fn = function([a = 1,b = 2] = []){
 console.log(a,b);
}
fn(); // 1 2
fn([3,4]); // 3 4

箭头函数

let 变量=(形参)=>{}

只有一个形参可以不用括号,只有一句函数体可以不用大括号

箭头函数不会把自己的this值绑定到函数上

函数对象This

  • this

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this

  • 以函数的形式调用时,this永远都是window
  • 以方法的形式调用时,this就是调用方法的那个对象
  • 使用call和apply调用时,this是传入的那个指定对象

函数调用时,使用.call()调用函数,在调用的时候传入一个对象,这个对象就是this所指向的对象,也就是说,可以自己指定this的指向,然后从第二个参数开始,实参将会依次传递 function.call(obj,参数)

使用.apply()调用函数 ~ function.apply(obj,参数的数组)

  • 箭头函数的this

当箭头函数是一个嵌套函数时,指向上级函数的this

无上级则指向window

嵌套函数

在函数中声明的函数就是嵌套函数,嵌套函数只能在当前函数中可以访问,在当前函数外无法访问

立即执行函数

(function () {
    alert("我是一个匿名函数");
})();

回调函数

一个函数fun1作为参数传入到fun2函数,在fun2函数中调用fun1,fun1就叫做回调函数

数组迭代中使用

every() 每一项运行某函数,全true则返回true

let arr = [1,2,3,4,5,6,7,8,9,10];
let i = arr.every(function(item){
 if(item % 2 == 0){
 return true;
 }else{
 return false;
 }
});
console.log(i);//false

some() 每一项运行某函数,有true则返回true

filter() 过滤器,将true的项返回

let arr = [1,2,3,4,5,6,7,8,9,10];
let i = arr.filter(function(item){
 if(item % 2 == 0){
 return true;
 }else{
 return false;
 }
});
console.log(i);//[ 2, 4, 6, 8, 10 ]

map() 对数组的每一项运行某函数,返回每一项的结果

forEach() 对数组的每一项运行某函数,不返回结果

构造函数

构造函数:构造函数是用来模拟类的,习惯上首字母大写,构造函数和普通函数的还有一个区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。

那构造函数是怎么执行创建对象的过程呢?我再来解释一下:

  • 调用构造函数,它会立刻创建一个新的对象

  • 将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象

  • 逐行执行函数中的代码

  • 将新建的对象作为返回值返回

    // 使用构造函数来创建对象
    function Person(name, age) {
        // 设置对象的属性
        this.name = name;
        this.age = age;
        // 设置对象的方法
        this.sayName = function () {
            console.log(this.name);
        };
    }
    
    var person1 = new Person("孙悟空", 18);
    var person2 = new Person("猪八戒", 19);
    var person3 = new Person("沙和尚", 20);
    
    console.log(person1);
    console.log(person2);
    console.log(person3);
    
    
    

DOM

查找HTML元素

方法描述
document.getElementById(id)通过元素 id 来查找元素
document.getElementsByTagName(name)通过标签名来查找元素。
document.getElementsByClassName(name)通过类名来查找元素。
document.querySelector(CSS选择器)通过CSS选择器选择一个元素。
document.querySelectorAll(CSS选择器)通过CSS选择器选择多个元素。

getElements会实时更新,querySelecor不会

获得多个返回值一般是以伪数组的形式,想要控制其中一个需要用[ ]

<body>
<button id="btn">我是按钮</button>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var btn = document.getElementById("btn");
    console.log(btn);
</script>
</body>


获取→修改HTML值

节点.innerText

获取文本内容(不会获取到display:none的内容),可以用textContent

<script>
    var a = document.getElementById("a");

    console.log(getInnerText(a));

    /*获取任意标签的内容*/
    function getInnerText(element) {
        // 判断浏览器是否支持textContent,如果支持,则使用textContent获取内容,否则使用innerText获取内容。
        if(typeof element.textContent == "undefined") {
            return element.innerText;
        } else {
            return element.textContent;
        }
    }
</script>


节点.innerHTML

获取代码(string),当内容只有文本时,获取到的和innerText一样

可以通过给其赋值新的代码来达到修改

通过关系获取节点
// (一)父子关系
// 1-1.知道父元素节点,获取子节点;包括空白节点,文本节点,元素节点
let ul=document.getElementsByTagName("ul")[0];
console.log(ul.childNodes);

// 1-2.知道父元素节点,获取子元素节点;只有子元素节点
console.log(ul.children);
console.log(ul.children[1].children);

// 2.知道子元素节点,获取父元素节点;返回值是具体元素节点
console.log(ul.parentNode.parentNode);

// (二)兄弟关系
// 1.获取前一个兄弟元素节点
console.log(ul.previousElementSibling);
// 2.获取后一个兄弟元素节点
console.log(ul.nextElementSibling);

克隆

let ol=document.querySelector("ol");
// 1.浅克隆:参数为false;只是克隆节点本身,不包含子节点
let newOL=ol.cloneNode(false);
// 插入到页面
document.body.insertBefore(newOL,ol);

// 2.深克隆:参数为true;克隆节点和子节点
// let newOL2=ol.cloneNode(true);
// 插入到页面
// document.body.insertBefore(newOL2,ol);

增删节点

如需向 HTML DOM 添加新元素,您必须首先创建这个元素(元素节点),然后将其追加到已有元素

方法描述
document.createElement(element)创建 HTML 元素节点。
document.createAttribute(attribute)创建 HTML 属性节点。
document.createTextNode(text)创建 HTML 文本节点
元素节点.removeChild(element)删除 HTML 元素(不建议用节点.remove())
元素节点.appendChild(element)添加 HTML 元素
元素节点.replaceChild(element)替换 HTML 元素
元素节点.insertBefore(element,子节点)在指定的子节点前面插入新的子节点
document.write(text)写入HTML输出流
节点插入
// 四.增加节点
// 1.创建元素节点
let newP=document.createElement("p");
// 2.创建文本节点
let newText=document.createTextNode("具体文本");
// 3.把文本节点作为子节点放入到元素节点中
newP.appendChild(newText);
// 4.把组合好的元素节点作为页面中某个元素的子节点,插入到页面中
document.body.appendChild(newP);

// 4-1:把组合好的元素节点插入到页面中某个元素的前面
// 父元素节点.insertBefore(新元素,旧元素)
// 这里的父元素节点是指旧元素节点的父元素
let sc=document.getElementsByTagName("script")[0];
document.body.insertBefore(newP,sc);

文档碎片插入

每次添加都会刷新页面,所以建议使用文档碎片一次性添加

let arr=["唐僧","悟空","八戒","沙僧"];
let list=document.getElementsByClassName("list")[0];
let of=document.createDocumentFragment();// 创建文档碎片
for(let i=0;i<arr.length;i++){
    // 1.创建元素节点
    let li=document.createElement("li");
    // 2.创建文本节点
    let word=document.createTextNode(arr[i]);
    // 3.把文本节点插入到元素节点
    li.appendChild(word);
    // 4.把元素节点插入到文档碎片中
    of.appendChild(li);
}
// 5.把文档碎片插入到页面中
list.appendChild(of);

节点删除

如需删除某个 HTML 元素,您需要知晓该元素的父

var child = document.getElementById("p1");
child.parentNode.removeChild(child);

getElements实时更新导致找不到删除节点,用 let li = document.querySelectorAll(‘li’);

 <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <button>删除</button>
  <script>
    let ul = document.getElementsByTagName('ul')[0];
    let li = document.getElementsByTagName('li');
    let button = document.getElementsByTagName('button')[0];
    console.log(button);
    for (let i = 0; i < li.length; i++) {
      li[i].onclick = function () {
        ul.removeChild(li[i])
      }

    }
    button.onclick = function () {
      ul.removeChild(li[0])
    }
  </script>

属性的类和操作

删除属性

节点.removeAttribute()

  • 节点.属性

      <input type="text"> <button class="reset">提交</button>
      <button class="remove">删除</button>
      <script>
        let button = document.querySelector('.reset');
        let remo = document.querySelector('.remove');
        let txt = document.querySelector('input');
        button.onclick = function () {
          txt.style.border = '1px solid red'
        }
        remo.onclick = function () {
          txt.style.removeProperty('border')
        }
      </script>
    
    

获取属性

属性的修改
  • 节点.getAttribute(‘属性’)
  • 节点.setAttribute(‘属性’,‘值’)
  • element.style.property = new style
元素类的相关操作

获取节点类名.classList数组

<body>
 <p id="test1" class="abc qwe">Lorem ipsum dolor sit amet.</p>
 <script>
 let test1 = document.getElementById("test1");
 console.log(test1.classList); // DOMTokenList(2) ["abc", "qwe", value: "abc qwe"](数组)
 console.log(test1.classList[0]); // abc
 console.log(test1.classList[1]); // qwe
 </script>
</body>

获取到类名数组后可以用add()方法在该数组中添加新类,remove()删除

toggle()方法切换类(无则添加,有则删除)

通过对类名的增删可以实现样式切换

获取节点类名.classList字符串

<body>
 <p id="test1" class="abc qwe">Lorem ipsum dolor sit amet.</p>
 <script>
 let test1 = document.getElementById("test1");
 console.log(test1.className);//abc qwe(返回字符串)
 </script>
</body>

注意:如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color,需要将这种样式名修改为驼峰命名法,去掉-,然后将-后的字母大写,我们通过style属性设置的样式都是行内样式,同样的获取也是行内样式,而行内样式有较高的优先级,所以通过JS修改的样式往往会立即显示,但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加!important
————————————————
版权声明:本文为CSDN博主「轻松的小希」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38490457/article/details/109257751

拓展

通过style属性设置和读取的都是内联样式,无法读取样式表中的样式或者说正在应用的样式,如果想要读取当前正在应用的样式属性我们可以使用元素.currentStyle.样式名来获取元素的当前显示的样式,它可以用来读取当前元素正在显示的样式,如果当前元素没有设置该样式,则获取它的默认值,但是currentStyle只有IE浏览器支持,其它的浏览器都不支持,在其它浏览器中可以使用**getComputedStyle()**这个方法来获取元素当前的样式,这个方法是window的方法,可以直接使用,但是需要两个参数:

第一个参数:要获取样式的元素
第二个参数:可以传递一个伪元素,一般都传null
该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过 对象.样式名 来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值,比如:没有设置width,它不会获取到auto,而是一个长度,但是该方法不支持IE8及以下的浏览器。通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性,因此,我们可以写一个适配各个浏览器的读取元素样式的方法。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        /*样式表的样式*/
        #box {
            width: 200px;
            height: 200px;
            background-color: green;
        }
    </style>
</head>
<body>
<div style="width: 100px;height: 100px;" id="box"></div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    /*通用的获取元素样式的方法*/
    function getStyle(obj, name) {
        if (window.getComputedStyle) {
            //正常浏览器的方式,具有getComputedStyle()方法
            return getComputedStyle(obj, null)[name];
        } else {
            //IE8的方式,没有getComputedStyle()方法
            return obj.currentStyle[name];
        }
    }

    var box = document.getElementById("box");

    console.log(getStyle(box, "width"));
    console.log(getStyle(box, "height"));
    console.log(getStyle(box, "background-color"));
</script>
</body>
</html>



BOM

1.相同条件下,setTimeout() 只执行一次,setInterval() 则循环执行;
2.setTimeout() 延迟执行一次: setTimeout(fn, 1000); //延迟1秒,执行一次fn();
3.setInterval() 隔段时间循环执行; setInterval(fn, 1000); //每隔1秒,循环执行fn()

调用的fn为外部函数则加引号

1、作用域:这里我引用《你不知道的javascript》中的一个比喻,可以把作用域链想象成一座高楼,第一层代表当前执行作用域,楼的顶层代表全局作用域。我们在查找变量时会先在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上找,以此类推。到达顶层后(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。
2、闭包:我的理解是在传递函数类型的变量时,该函数会保留定义它的所在函数的作用域。读起来可能比较绕,或者可以简单的这么理解,A函数中定义了B函数并且它返回了B函数,那么不管B函数在哪里被调用或如何被调用,它都会保留A函数的作用域。
3、事件循环:这个概念深入起来很复杂,下面新开一个段落只说一些跟本文相关的内容。

说起事件循环,不得不提起任务队列。事件循环只有一个,但任务队列可能有多个,任务队列可分为宏任务(macro-task)微任务(micro-task)XHR回调、事件回调(鼠标键盘事件)、setImmediate、setTimeout、setInterval、indexedDB数据库操作等I/O以及UI rendering都属于宏任务(也有文章说UI render不属于宏任务,目前还没有定论),**process.nextTick、Promise.then、Object.observer(已经被废弃)、MutationObserver(html5新特性)**属于微任务。注意进入到任务队列的是具体的执行任务的函数。比如上述例子setTimeout()中的timer函数。另外不同类型的任务会分别进入到他们所属类型的任务队列,比如所有setTimeout()的回调都会进入到setTimeout任务队列,所有then()回调都会进入到then队列。当前的整体代码我们可以认为是宏任务。事件循环从当前整体代码开始第一次事件循环,然后再执行队列中所有的微任务,当微任务执行完毕之后,事件循环再找到其中一个宏任务队列并执行其中的所有任务,然后再找到一个微任务队列并执行里面的所有任务,就这样一直循环下去。这就是我所理解的事件循环。

- textContent 会获取style= “display:none” 中的文本,而innerText不会
- textContent 会获取style标签里面的文本,而innerText

代码如下(示例):
childNodes:获取子节点——返回所有节点的数组,只返回文本和元素节点,对于属性节点直接无视
children:子元素——只返回元素节点


事件

事件捕获(由外到内)

addEventListener() 第三个参数决定事件是冒泡/捕获

box.addEventListener('click', function () {
 box.innerHTML += 'div\n'
 }, true)

默认为事件冒泡(由内到外)

e.preventDefault(); 阻止默认行为(表单)

e.stopPropagation() 阻止冒泡,不阻止默认行为(例如a超链接跳转)‘

return false 阻止冒泡,也阻止行为

多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素的事件触发了,外面的元素的该事件自动的触发了

鼠标事件

event.boutton 鼠标按键值

属性描述
onclick单击鼠标时
ondblclick双击鼠标时
onmousedown按下鼠标按钮时
onmouseup松开鼠标按钮时
onmousemove鼠标指针移动时
onmouseover鼠标指针移至元素之上时运行脚本,冒泡
onmouseout鼠标指针移出元素时运行脚本,冒泡
onmouseenter鼠标指针移至元素之上时运行脚本,可以阻止冒泡
onmouseleave鼠标指针移出元素时运行脚本,可以阻止冒泡
onmousewheel转动鼠标滚轮时
onscroll滚动元素的滚动条时
拖拽
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box1" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<div id="box2" style="width: 100px;height: 100px;background: green;position: absolute;"></div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");

    drag(box1);
    drag(box2);

    /*
     * 提取一个专门用来设置拖拽的函数
     * 参数:开启拖拽的元素
     */
    function drag(obj) {
        //当鼠标在被拖拽元素上按下时,开始拖拽
        obj.onmousedown = function (event) {
            // 解决事件的兼容性问题
            event = event || window.event;

            // 设置obj捕获所有鼠标按下的事件
            /**
             * setCapture():
             * 只有IE支持,但是在火狐中调用时不会报错,
             * 而如果使用chrome调用,它也会报错
             */
            obj.setCapture && obj.setCapture();

            // obj的偏移量 鼠标.clentX - 元素.offsetLeft
            // obj的偏移量 鼠标.clentY - 元素.offsetTop
            var ol = event.clientX - obj.offsetLeft;
            var ot = event.clientY - obj.offsetTop;

            // 为document绑定一个鼠标移动事件
            document.onmousemove = function (event) {
                // 解决事件的兼容性问题
                event = event || window.event;
                // 当鼠标移动时被拖拽元素跟随鼠标移动
                // 获取鼠标的坐标
                var left = event.clientX - ol;
                var top = event.clientY - ot;
                // 修改obj的位置
                obj.style.left = left + "px";
                obj.style.top = top + "px";
            };

            // 为document绑定一个鼠标松开事件
            document.onmouseup = function () {
                // 取消document的onmousemove事件
                document.onmousemove = null;
                // 取消document的onmouseup事件
                document.onmouseup = null;
                // 当鼠标松开时,取消对事件的捕获
                obj.releaseCapture && obj.releaseCapture();
            };

            /*
             * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
             * 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
             * 如果不希望发生这个行为,则可以通过return false来取消默认行为,
             * 但是这招对IE8不起作用
             */
            return false;
        };
    }
</script>
</body>
</html>


键盘事件

event.key 按键的值

event.keyCode 按键的ASCALL码值

属性描述
onkeydown当按下按键时运行脚本。
onkeyup当松开按键时运行脚本。
onkeypress当按下并松开按键时运行脚本。
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box" style="width: 100px;height: 100px;background: red;position: absolute;"></div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var box = document.getElementById("box");

    //为document绑定一个按键按下的事件
    document.onkeydown = function (event) {
        event = event || window.event;

        // 定义移动速度
        var speed = 10;

        // 选择移动方向
        switch (event.keyCode) {
            case 37:
                box.style.left = box.offsetLeft - speed + "px";
                break;
            case 39:
                box.style.left = box.offsetLeft + speed + "px";
                break;
            case 38:
                box.style.top = box.offsetTop - speed + "px";
                break;
            case 40:
                box.style.top = box.offsetTop + speed + "px";
                break;
        }
    };
</script>
</body>
</html>


窗口事件

属性描述
onblur当窗口失去焦点时运行脚本。
onfocus当窗口获得焦点时运行脚本。
onload当文档加载之后运行脚本。
onresize当调整窗口大小时运行脚本。
onstorage当 Web Storage 区域更新时(存储空间中的数据发生变化时)运行脚本。

事件对象event

包含当前事件的所有信息,当事件发生时只能在事件内部调用,事件结束销毁

event.type 事件类型

event.target 事件源

坐标获取

event.clientX 点相对于浏览器窗口的X坐标

event.offsetX 点相对于事件源的X坐标

自身位置 节点.offsetTop 自身高度 节点.offsetHeight

window.innerHeight浏览器高

应用:商品放大镜

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>放大镜儿</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    .box {
      width: 1260px;
      height: 500px;
      border: 2px solid;
      background-color: #fafafa;
      margin: 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .big {
      padding: 4px;
      border: 2px solid skyblue;
    }

    .goods {
      display: flex;
      justify-content: space-between;
      position: relative;
      color: rgba(red, green, blue, 0);
    }



    .look {
      width: 215px;
      height: 215px;
      display: flex;
      overflow: hidden;
      position: relative;
    }

    .look img {
      width: 215px;
      height: 215px;
      position: absolute;
      left: 0;
      top: 0;
    }

    .big0 {
      width: 400px;
      height: 400px;
      padding: 2px;
      overflow: hidden;
      position: relative;
      border: 1px dashed #cacaca;
    }

    .big0>img {
      position: absolute;
      top: 0;
      left: 0;

    }

    .rect {
      width: 40px;
      height: 40px;
      background: url(./images/bg.png);
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="big">
      <ul class="look">
        <img src="./images/imgA_2.jpg" alt="">
        <img src="./images/imgB_2.jpg" alt="">
        <img src="./images/imgC_2.jpg" alt="">
        <div class="rect"></div>
      </ul>
      <ul class="goods">
        <li><img src="./images/imgA_1.jpg" alt=""></li>
        <li><img src="./images/imgB_1.jpg" alt=""></li>
        <li><img src="./images/imgC_1.jpg" alt=""></li>
      </ul>
    </div>

    <div class="big0">
      <img src="./images/imgA_3.jpg" alt="">
      <img src="./images/imgB_3.jpg" alt="">
      <img src="./images/imgC_3.jpg" alt="">
    </div>
  </div>
  <script>
    let ppt = (800 / 215).toFixed(2)
    let big = document.querySelector('.big')
    let look = document.querySelector('.look')
    let look_img = document.querySelectorAll('.look>img')
    let rect = document.querySelector('.rect')
    let goods = document.querySelector('.goods')
    let goods_li = document.querySelectorAll('.goods>li')
    let big0 = document.querySelector('.big0')
    let big0_img = document.querySelectorAll('.big0>img')
    //初始化
    let index = 0;
    for (let i = 0; i < goods_li.length; i++) {
      goods_li[i].setAttribute('count', i)
    }
    big0.style.visibility = 'hidden'
    rect.style.visibility = 'hidden';
    look_img[index].style.zIndex = 1
    big0_img[index].style.opacity = 1
    //选择小图
    goods.addEventListener('mouseover', function () {
      index = event.target.parentNode.getAttribute('count')
      if (event.target.localName == 'img') {
        for (let i = 0; i < look_img.length; i++) {
          look_img[i].style.zIndex = 0
          big0_img[i].style.opacity = 0
        }
        look_img[index].style.zIndex = 1
        big0_img[index].style.opacity = 1
      }
    })
    //选择中图
    look.addEventListener('mouseenter', function () {
      big0.style.visibility = 'visible'
      rect.style.visibility = 'visible';
      let move_left = look.offsetLeft;
      let move_top = look.offsetTop;
      // console.log(look.clientLeft); //边框线
      // console.log(look.offsetParent); //用于定位的父级元素
      // console.log(move_left);// 到定位级父元素的X坐标
      //console.log(event.clientX); //到浏览器的X坐标
      //console.log(event.offsetX);// 到事件源的X坐标
      look.addEventListener('mousemove', function () {
        //移动小方块
        rect.style.left = event.clientX - move_left - rect.offsetWidth / 2 + 'px'
        rect.style.top = event.clientY - move_top - rect.offsetHeight / 2 + 'px'
        //移动大图
        big0_img[index].style.left = (event.clientX - move_left - rect.offsetWidth / 2) * (-ppt) + 'px'
        big0_img[index].style.top = (event.clientY - move_top - rect.offsetHeight / 2) * (-ppt) + 'px'
      })
    })
    look.addEventListener('mouseleave', function () {
      big0.style.visibility = 'hidden';
      rect.style.visibility = 'hidden';
    })


  </script>
</body>

</html>

表单编程

表单元素

text -文本框

password -密码框

radio -单选框

checkbox -多选框

file -文件上传控件

hidden -隐藏表单

submit -提交按钮

image -带图片的提交按钮

reset -重置按钮

button -普通按钮

color颜色

原理

表单通过设置键值对来传递信息,键为表单元素的name,值value

节点.elements,可以获取子节点,不同于 节点.children

<body>
  <form action="" name="fm">
    <input type="text" name="">
    <input type="color" name="">
    <div>
      <input type="text" placeholder="用户名">
      <input type="password" name="psw">
    </div>
  </form>
  <script>

    const { fm } = document;//解构获取form
    const [ipt0, ipt1, ipt2] = fm.elements//解构获取后代,节点.children是子代
    const ipt3 = fm.psw //name名获取节点
    console.log(ipt0, ipt1, ipt2, ipt3);
    ipt0.onblur = function (e) {
      //三种取值方式
      console.log(ipt0.value);
      console.log(this.value);
      console.log(e.target.value);
    }

  </script>
</body>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值