箭头函数
定义
函数的简写
作用
提高书写效率
语法
<script>
// 以前写函数的方式 num1 形参
function func1(num1) {
// return 返回一个结果
return num1 + 100
}
// console.log(func1(1)); //func1(1) 1 代表实参
// 箭头函数 函数的简写,可以通过书写效率 =>箭头函数固定搭配
const func2 = (num1) => num1 + 100 //和上面是相等功能
// console.log(func2(1)); //调用函数一定要写() 代表执行
</script>
-
没有形参,没有返回值 有2行业务
// 没有形参一定要写()。 const func3 = () => { console.log('执行业务1'); console.log('执行业务2'); } -
没有形参,没有返回值,业务只有一行代码,大括号可以省略
const func4 = () => console.log('执行业务3'); -
只有一个形参,没有返回值,业务只有一行代码
// 有形参可以省略括号 // const func5 = num1 => console.log(num1 + 100); num1 可以省略() const func5 = (num1) => console.log(num1 + 100); -
两个或者多个参数(括号不能省略) ,没有返回值,业务只有一行代码
const func6 = (a, b) => console.log(a + b); -
没有形参,有返回值,业务两行代码
const func7 = () => { let a = 100 return a + 100 } -
没有形参,有返回值,业务一行代码
const func8 = () => {
// return 100 + 200
// }
// console.log(func8());
const func8 = () => 100 + 200 //和上述写法 return 100 + 200 功能相等
// console.log(func8())
注意点:
-
箭头函数 ()=>{} 这样是固定搭配,箭头函数是匿名函数,一般做参数传参。
-
没有形参和多个形参的时候不能省略括号(),只有一个形参的时候才能省略括号
-
**(重点)**函数体只有一句,可以省略{ },同时返回函数体的结果,就不能写return;相反如果不省略括号,就要写return。
const func8 = () => { // return 100 + 200 // } // console.log(func8()); const func8 = () => 100 + 200 //和上述写法 return 100 + 200 功能相等 // console.log(func8()) -
return 可以中止函数,后面的代码不再执行,同时return表示的是返回一个结果,所以如果想要获得这个返回值就不能换行写
-
**(重点)**箭头函数返回对象,想要省略return,要加上()
const func9=(num)=>({a:123});// => 右边加了小括号 表示想要返回 小括号里面的数据相当于 const func9=(num)=> return {a:123};
箭头函数和this指向
大部分情况下,箭头函数和this一起使用,this指向的是window
const func = () => {
console.log(this,'这个是箭头函数的this'); //window
};
func();
const obj = {
name: '悟空',
say: () => {
console.log(this,'这个是箭头函数方法调用模式');
},
};
obj.say(); // window
const obj1 = {
name: '悟空1',
obj2: {
name: '悟空2',
say: () => {
console.log(this,'这个是箭头函数 对象为属性的方法调用模式');
},
},
};
obj1.obj2.say(); //window
大部分情况下,普通函数和this一起使用,this指向这个函数调用者
const button = document.querySelector('button');
button.addEventListener('click', function () {
console.log(this,'这个是普通函数的this'); // this = button
});
数组常见的方法
forEach()高阶函数
定义
按顺序为数组中的每个元素调用一次函数
语法
array. forEach(function(value,index,arr),thisvalue)
注意点
forEach类似for循环,但for循环可以通过 break来打断、 forEach不能通过break打断
对于没有值的数组元素,不执行forEach()方法
map()方法
定义
通过指定函数出来数组的每个元素,并返回处理后的数组。换句话说,就是根据原来的数组,按顺序循环返回新的数据,组装成新的数组
语法
array.map(function(value,index,arr),thisvalue)
想要根据数组数据渲染到页面,并且数据独占一行
思路如下:
- 先将原数据用map()方法组装成新的div形式数组
- 再用数据join(" ")方法,将数组转换成字符串
- 最后再渲染到页面即可
捐赠管理案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
/>
<title>01-捐赠管理.html</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h3 {
margin: 50px;
text-align: center;
}
table {
width: 800px;
margin: 0 auto;
border-collapse: collapse;
text-align: center;
}
thead {
background-color: #337ab7;
color: #fff;
}
td,
th {
padding: 10px 50px;
/* 设置文字不换行 */
white-space: nowrap;
}
</style>
</head>
<body>
<h3>捐赠管理</h3>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>捐赠人</th>
<th>收捐单位</th>
<th>金额</th>
<th>收捐日期</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
// 获取tbody
const tbody = document.querySelector('tbody');
// 定义数据
const arr = [
// id:数据编号 person:捐赠人姓名 unit:捐赠单位名称 money:捐赠金额 date:捐赠日期
{
id: 1,
person: '刘德化',
unit: '壹基金',
money: 1000,
date: '2021-10-5',
},
{
id: 2,
person: '周杰伦',
unit: '自然之友',
money: 1000,
date: '2021-01-15',
},
{
id: 3,
person: '李连杰',
unit: '嫣然基金',
money: 1000,
date: '2021-06-7',
},
];
// 根据数组来渲染页面
function render() {
const newArr = arr.map(
(value) => `
<tr>
<td>${value.id}</td>
<td>${value.person}</td>
<td>${value.unit}</td>
<td>${value.money}</td>
<td>${value.date}</td>
<td>
<a href="#" class="del">删</a>
<a href="#" class="update">改</a>
</td>
</tr>
`
);
const html = newArr.join('');
tbody.innerHTML = html;
}
// 根据数组数组渲染页面
render();
</script>
</body>
</html>
every()方法
定义
检查数组中每个元素是否通过测试
语法
array.every(function(value,index,arr),thisvalue)
注意点
- every的返回值是个布尔值,如果数组中的所有元素都通过测试,则返回true,否则返回false
- 如果是空数组,调用every 直接返回true
全选和全不选
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>08-全选和不全选-every</title>
<style>
* {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 500px;
margin: 100px auto;
text-align: center;
}
th {
background-color: #09c;
font: bold 16px '微软雅黑';
color: #fff;
height: 24px;
}
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
.allCheck {
width: 80px;
}
</style>
</head>
<body>
<table>
<tr>
<th class="allCheck">
<input type="checkbox" name="" id="checkAll" />
<span class="all">全选</span>
</th>
<th>商品</th>
<th>商家</th>
<th>价格</th>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck" />
</td>
<td>小米手机</td>
<td>小米</td>
<td>¥1999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck" />
</td>
<td>小米净水器</td>
<td>小米</td>
<td>¥4999</td>
</tr>
<tr>
<td>
<input type="checkbox" name="check" class="ck" />
</td>
<td>小米电视</td>
<td>小米</td>
<td>¥5999</td>
</tr>
</table>
</body>
<script>
let checkAll = document.querySelector('#checkAll');
let checkboxList = document.querySelectorAll('.ck'); // checkboxList 现在是一个伪数组
checkboxList=[...checkboxList];// OK
// 商品全选点击 功能
checkAll.addEventListener('click', function () {
// for (let index = 0; index < checkboxList.length; index++) {
// checkboxList[index].checked = checkAll.checked;
// }
checkboxList.forEach(function (value,index) {
checkboxList[index].checked = checkAll.checked;
}) // 和上述for循环用法相同
});
// 给每一个商品绑定点击事件
checkboxList.forEach(function (value,index) {
checkboxList[index].addEventListener('click',function () {
// 判断是否达到了全选 条件
// 判断每一个小小的复选框的选中状态 如果都是true,那么就全选
let checked = checkboxList.every(value=>value.checked)
// 设置全选按钮即可
checkAll.checked = checked
})
})
</script>
</html>
some()方法
定义
检查数组中每个元素是否通过测试
语法
array.some(function(value,index,arr),thisvalue)
const arr = [1, 3, 4, 6, 2];
// 这个数组里面有没有元素大于6的
const result = arr.some((value) => value > 6);
console.log(result); // 输出true
注意点
- some 返回值是布尔值。只要数组中有一个元素符合条件,就返回 true,否则返回 false。
filter()方法
定义
过滤数组, 过滤出满足条件的数据 =>新的数组
语法
array.filter(function(value,index,arr),thisvalue)
const arr = [1, 2, 3, 4, 5, 6, 7];
// 返回 奇数
const newArr = arr.filter((value) => value % 2 !== 0);
console.log(newArr); //输出 [1, 3, 5, 7]
面向对象
概念:一种编程行业通用的写项目级的代码的思维,世间万物皆是对象-看待事物的思维
看待事物的思维主要可以分成两个部分:
1.属性(一些描述性的数据,一般是固定数值,比如名字,年龄,性别)
2.方法也叫行为(一般是动词,本质是函数,比如说话,唱歌,吃饭,修改颜色,设置字体大小)
创建对象的几种方式
字面量方式创建对象
定义:声明字面式对象
好处:简单粗暴,比较好用
弊端:不方便维护和修改 ,不适合创建多个同类型的, 后期要修改会比较麻烦
语法:const obj = { }
const obj1 = {name:'悟空1',tel:123451 }
const obj2 = {name:'悟空2',tel:123452 }
const obj3 = {name:'悟空3',tel:123453 }
const obj4 = {name:'悟空4',tel:123454 }
const obj5 = {name:'悟空5',tel:123455 }
工厂函数创建对象
工厂函数:批量生产对象
好处:容易维护,一改属性名则全改属性名
弊端:没有实现继承的作用;无法简单分辨对象的特征
function CreatePerson(name, age, height) {
return {
// name: name,
username:name,
age: age,
height: height,
};
}
// 创建对象
const obj1 = CreatePerson('小红',18,155)
console.log(obj1);
const obj2 = CreatePerson('小刚',19,175)
console.log(obj2);
const obj3 = CreatePerson('小丽',21,150)
console.log(obj3);
注意:工厂函数和构造函数会比较相似,但会有不同。
不同之处:
-
工厂函数是通过返回值输出;而构造函数要先通过this赋值
-
创建对象方式不同,工厂函数直接创建对象,而构造函数是通过new的方式来创建对象
自定义构造函数创建对象
定义:能够实例化对象的函数,就是构造函数
好处:可以方便的创建对象
弊端:同一个(say)方法占据两份内存
构造函数是一种特殊的方法,主要是用来创建对象时初始化对象,即为对象成员变量赋初始值,总与new 运算符一起使用在创建对象的语句中
// 1.声明函数
function Person(name, age) {
// 2.通过this 赋值 你希望调用obj里面什么的属性,就this.xxx
// this 和obj1是相关联的
this.name = name;
this.age = age;
}
//3. 通过new的方式来创建对象 ('小红',18)想要创建什么对象,就传什么对象给(name, age)
//这一行代码表示的是创建一个对象,同时实例化一个对象,并且给这个对象的属性进行初始化
const obj1 = new Person('小红',18) //实例化对象
构造函数的工作原理
-
创建一个新对象(开辟空间存储当前对象)
-
把this 设置这个新对象
-
这个新对象添加新的属性和方法
-
把this对象返回
构造函数的特点
- 构造函数的首字母必须是大写的,用于区分与普通函数
- 内部使用的this对象,来指向即将要生成的实例对象
- 使用new 来生成实例对象
<title>构造函数-性能问题</title>
</head>
<body>
<script>
// 构造函数的首字母要大写,行内编码规范,固定的
// 构造函数
// function CreatePerson(name) {
// // 通过this赋值,创建了name的属性
// this.name = name
// this.sayHi = function(){
// console.log('这个是sayHi的方法');
// }
// }
// // 通过new的方式创建对象
// const obj1 = new CreatePerson('小明')
// const obj2 = new CreatePerson('小红')
// obj1.sayHi()
// obj2.sayHi()
//
// console.log(obj1.sayHi === obj2.sayHi); //fasle 表示两个say的方法占据了两份内存。浪费内存,性能不够好
/* 解决浪费内存的方案
提取同一个say方法 */
/* 这样的方式容易维护,也解决了性能,但代码不够优雅,会污染全局变量,以后都不能写sayHi的方法,会很容易覆盖 */
// 提取同一个say 方法
function sayHi() {
console.log("这个是sayHi的方法");
}
function CreatePerson(name) {
// 通过this赋值,创建了name的属性
this.name = name;
this.sayHi = sayHi; //say函数引用类型,构造函数中的sayHi ,其实和外面的sayHi的内存地址一致的,同一个sayHi方法
}
// 通过new的方式创建对象
const obj1 = new CreatePerson("小明");
const obj2 = new CreatePerson("小红");
// obj1.sayHi();
// obj2.sayHi();
// console.log(obj1.sayHi === obj2.sayHi); // true 表示在同一个内存上,优化过的性能比较好
</script>
补充 基本类型和引用类型赋值的不同
// 对于基本类型来说,= 就是复制了一份值
let num = 100;
let num2 = num; // 复制值 num和 num2占两给内存 各自不影响
num2 = 1000;
console.log(num);
// 对于引用类似 = 其实把地址拷贝了一份给新的对象 两个数据 公用一份数据
let person1 = { name: "小明" }; // person1 指向了 一个地址 0x1111 存放悟空
let person2 = person1; // person2也指向了person1的地址 0x1111 person1和person2 通用一个数据
// 修改了person2 person1也会发生改变
person2.name = '小红';
console.log(person1);
// person2 和person1 共同指向了同一个地址
console.log(person1 === person2); // true
let obj1 = {}; // 开辟了一个内存
let obj2 = {}; // 开辟了另外一个内存
console.log(obj1 === obj2); // false 两个不同的内存地址
通过new构造函数来创建对象
原型函数(prototype)
在js中任何一个函数都有一个prototype属性,原型(prototype)就是函数的一个属性,它指向一个对象。
举例子: 构造函数看是人, 原型对象 就是人的DNA
如果我们修改了DNA,那么通过构造函数创建实例都会一起发生修改
如果我们在DNA上新增了一些东西,对应实例一样会被新增
function CreatePerson(name) {
// 通过this赋值
this.name = name;
}
// 原型对象
// console.log(CreatePerson.prototype);
// 在DNA上增加东西
CreatePerson.prototype.say = function () {
console.log("你好");
};
const obj1 = new CreatePerson("小红");
const obj2 = new CreatePerson("小明");
// obj1.say();
// obj2.say();
原型链图
原型链是指对象的原型链,所以原型链上的所有节点都是对象,不能是字符串、数字、布尔值等原始类型。
原型链的终点是null,而不是Object.prototype
原因是Object.prototype确实是个特殊对象,我们先假设用它做终点。那么考虑一下,当你取它的原型时应该怎么办?即
取一个对象的属性时,可能发生三种情况:
- 如果属性存在,那么返回属性的值。
- 如果属性不存在,那么返回undefined。
- 不管属性存在还是不存在,有可能抛异常
假设Object.prototype是终点了,所以看起来不能是情况1。另外,抛出异常也不是好的设计,所以也不是情况3。那么情况2呢,它不存在原型属性,返回undefined怎么样?也不好,因为返回undefined一种解释是原型不存在,但是也相当于原型就是undefined。这样,在原型链上就会存在一个非对象的值。
所以,最佳选择就是null。一方面,你没法访问null的属性,所以起到了终止原型链的作用;另一方面,null在某种意义上也是一种对象,即空对象,因为null一开始就是为表示一个“空”的对象存在的。这样一来,就不会违反“原型链上只能有对象”的约定。
js的数据类型
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)
**注:**Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
检测数据类型的方法
(1)typeof
总结:前6个是基本数据类型, typeof null 返回的结果是错误的,typeof判断不了null的数据类型,可以通过 ===null 来判断 ;引用数据类型object,用typeof判断,除了function 会判断为ok以外,其余都是object,是无法判断出来的。
(2)instanceof
(3)Object.prototype.toString.call()推荐这种检测方法
toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。
值类型和引用类型的区别
1、值类型
1)基本类型数据是值类型
2)保存与复制的是值本身
3)使用typeof检测数据的类型
2、引用类型
1)保存与复制的是指向对象的一个指针
2)使用instanceof检测数据类型
3)使用 new() 方法构造出的对象是引用型
原型链继承
1.属性的继承
利用call技术
call定义: 借调 可以让一个对象 来借用另外一个对象的方法
语法
父元素方法.call(谁要借用,谁借用的方法的形参1,谁借用的方法的形参2)
<title>原型-继承</title>
</head>
<body>
<script>
// 继承的概念:父元素有的,子元素直接拿来用;父元素发生改变,子元素也随之发生改变
// 构造函数 父元素 (name, age, height) 形参
function person(name, age, height) {
// this指的是person
this.name = name; //对象添加新的属性 ,对象名.新的属性名 = 新值
this.age = age;
this.height = height;
}
// 构造函数 子元素
function son(name, age, height,gender) {
// call 表示借用
// 父元素方法.call(谁要借用,谁借用的方法的形参1,谁借用的方法的形参2)
// this = 实例 = s1
person.call(this,name,age,height)
this.gender = gender
}
// 通过new的方式创建实例
// const p1 = new person('大头爸爸',32,160)
const s1 = new son('小头儿子',11,140,'男')
// 分别打印输出p1,s1
// console.log(p1);
console.log(s1);
2.方法的继承
子元素的原型.方法 = 父元素的原型.方法
// 属性写在构造函数 父元素 (name, age, height) 形参
// 构造函数首字母要大写
function Person(name, age, height) {
// this指的是person
this.username = name; //对象添加新的数据 ,对象名.新的属性名 = 新值
this.age = age;
this.height = height;
}
// 方法是写在原型函数中
Person.prototype.sing = function () {
console.log(this.username + "唱一只小蜜蜂");
};
Person.prototype.say = function () {
console.log(this.username + "你好呀");
};
// 构造函数 子元素
function Son(name, age, height, gender) {
Person.call(this, name, age, height);
this.gender = gender;
}
// 通过new的方式创建实例
// const p1 = new Person("大头爸爸", 32, 160);
const s1 = new Son("小头儿子", 11, 140);
// 分别打印输出p1,s1
// console.log(p1);
// console.log(s1);
// 原型函数 继承方法
Son.prototype.sing = Person.prototype.sing
Son.prototype.say = Person.prototype.say
// s1 调用 输出
s1.sing();
s1.say();
bind ,call ,apply的区别
call ,apply,bind 修改this的指向
call,apply 直接返回调用的结果,而bind 不会直接调用函数,而是返回一个新的函数,需要我们主动调用新的函数,
const father = {
name: "灰太狼",
skill() {
console.log(this.name + "会抓羊");
},
};
const son = {
name: "小灰灰",
};
// call 方式来修改this的指向
father.skill.call(son); //this 指向son
// apply 方式来修改this的指向
father.skill.apply(son); //this 指向son
// bind 方式来修改this指向
// bind 不会直接调用skill函数 而是 返回一个新的函数
// 需要我们主动的调用新的函数- 调用skill()
const func = father.skill.bind(son)
func()
call ,apply,bind 传参区别
call传递参数 :obj.skill.call(person,参数1,参数2)
apply传递参数:obj.skill.apply(person,[参数1,参数2])
bind 传递参数 : func(参数1,参数2)
const father = {
name: "灰太狼",
skill(a,b) {
console.log(this.name + " " + a + " " + b);
},
};
const son = {
name: "小灰灰",
};
// call传递参数
father.skill.call(son,1,2)
// apply传递参数
father.skill.apply(son,[1,2])
// bind 传递参数
const func = father.skill.bind(son)
func(1,2)
ES6-class
目前浏览器 支持的js代码版本,主要支持es5 (for if while函数,forEach)版本,新的语法 es6 (提供了更加简单强大的代码更能力) 提高我们的开发效率
Es5的面向对象
- es5 写一个 构造函数 首字母是大写
<script>
//
// 当我们new 一个 对象的时候 Person 代码会被执行
function Person(name) {
// console.log("开始创建对象啦");
this.name = name;
}
// 定义行为 引出 原型
Person.prototype.say = function () {
console.log('say方法被调用啦 ' + this.name);
};
// new 一个对象
const p1 = new Person('悟空1');
const p2 = new Person('悟空2');
// console.log(p1);
console.log(p1.say === p2.say); //输出true
</script>
Es6的面向对象
- es6 面向对象 引出新的语法 类 class
<script>
class Person {
// 方法 constructor 在es6 构造函数
// constructor 会在 new Person的时候触发
constructor(name) {
// console.log("开始创建对象啦");
this.name = name;
}
// 直接写行为
say() {
console.log("say方法被调用啦 " + this.name);
}
}
// 一样new一个对象
const p1 = new Person("悟空1");
const p2 = new Person("悟空2");
console.log(p1.say === p2.say); //输出true
</script>
Es5继承
Es5继承 => 借调( call )
<script>
// 爸爸 person name属性
function Person(name) {
this.name = name;
}
// 爸爸 person say行为
Person.prototype.say = function () {
console.log("say方法我调用啦 " + this.name);
};
// 爸爸 person fly行为
Person.prototype.fly = function () {
console.log("父亲 起飞");
};
// 儿子 student name属性,color属性
function Student(name, color) {
Person.call(this, name); // 继承爸爸name属性
this.color = color;
}
// 儿子继承爸爸 say行为
Student.prototype.say = Person.prototype.say;
// 儿子继承爸爸 fly行为
Student.prototype.fly = Person.prototype.fly;
// new一个对象
const s1 = new Student("学生", "red");
// 儿子 调用 say方法
s1.say();
</script>
Es6继承
Es6继承 ---- extends
注意点:
-
如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super( );
(super 表示可以继承父亲的属性)
-
如果你只写了 extends 但是你没有写constructor 不需要管super
-
父类的构造函数 super :子类有构造方法且使用this前,必须使用super()。不然会报错
Must call super constructor in derived class before accessing 'this' or returning from derived constructor 译文:必须调用超构造函数在派生类访问'this'或从派生构造函数返回之前 -
方法重写 override:子类方法覆盖父类,super.父类方法()
class Person {
// 构造方法
constructor(name) {
// 属性
this.name = name;
}
// 方法
say() {
console.log(this.name);
}
}
// 继承
// extends 直接就实现了继承父亲的方法
class Student extends Person{
constructor(name,height){
// console.log(this); // 语法错误:必须先调用super()才能使用this
super(name); // 父亲的构造函数 =es5 Person.call(this,name);
this.height=height;
}
}
const s1=new Student("八神",180);
s1.say(); // 八神
class Saler extends Person{
constructor(name,age){
super(name);
this.age = age;
}
// 覆盖(重写)
say(){
// 访问父类方法
super.say(); // 马云
console.log(this.age);
}
}
const s2 = new Saler('马云',50);
s2.say(); // 50
Es6属性和方法的写法
属性写法有两种
-
可以写在 大括号内
class Person { color = "yellow"; height = 180; weight = 200; constructor(name) { this.name = name; } say = () => { // 箭头函数中的this , 绝大部分指向 window // 例外 用在 es6的class 充当 方法 this 指向 p1 实例 console.log("say 方法被调用了 " + this.name); }; } const p1 = new Person("悟空"); p1.say(); console.log(p1); </script> -
直接在构造函数内 constructor this.name=name
<script> class Person { constructor(name) { this.name = name; this.color = 'yellow'; this.height = 180; this.weight = 200; } say = () => { // 箭头函数中的this , 绝大部分指向 window // 例外 用在 es6的class 充当 方法 this 指向 p1 实例 console.log("say 方法被调用了 " + this.name); }; } const p1 = new Person("悟空"); p1.say(); console.log(p1); </script>
方法写法有三种
推荐写法一,性能最好,同一个内存
// 写法一:方法简写
say() {
console.log('say 方法被调用了 ' + this.name);
}
// 写法二:普通函数
say = function () {
console.log('say 方法被调用了 ' + this.name);
};
// // 写法三 :箭头函数
say = () => {
// 箭头函数中的this , 绝大部分指向 window
// 例外 用在 es6的class 充当 方法 this 指向 p1 实例
console.log("say 方法被调用了 " + this.name);
};
函数参数默认值
定义函数的同时可以给形参一个默认值
函数参数默认值
-
如果没有给我传递参数,那我就输出默认值
-
如果你给我传递了参数,那我就输出你的参数
function show(msg = '你好',str = '你我都好') {
console.log(msg,str);
}
// 调用函数
show() //输出 你好,你我都好
show('大家好') //输出 大家好,你我都好
show('大家好','世界美好') // 输出大家好,世界美好
对象简写
在定义对象的时候,如果属性名和变量名一致,可以实现简写
属性简写
以前属性的书写方式
const obj = {
username:'小明'
}
es6方式 如果变量的名字和对象的属性的名字 一致的话,对象可以简写 作用创建对象更方便
const username = "小明";
const age = 18;
const say = function () {};
const obj = {
username,
age,
say,
};
console.log(obj);
方法简写
//以前常规写法
const obj1 = {
say:function(){
console.log('say');
}
// es6关于方法简写
show(){
console.log('show');
}
};
obj1.say()
obj1.show()
解构
提供更加方便获取数组中的元素或者对象中属性的写法
数组解构
const [a,b,c] = ['悟空','八戒','唐僧']
console.log(a,b,c); //输出悟空 八戒 唐僧
元素交互顺序
let num1 = 100;
let num2 = 200;
[num2,num1] = [num1,num2];
console.log(num1,num2); //输出200,100
对象解构(重点)
const obj = {
name: "小明",
age: 18,
sex: "男",
};
const { name, age, sex } = obj;
console.log(name,age,sex) //输出小明 18 男
解构+数组默认值
没有参数又没有默认值就输出undefined
const arr = [1];
const [a,b ] = arr; //a = 1 如果b没有参数就输出b=undefined
没有参数,就使用默认值,有参数,就使用参数
// b = 2 默认值
const [a, b = 2] = [1]; //没有参数
console.log(a, b); //输出 a =1 b = 2
const [a1, b1 = 2] = [1,100]; //有参数
console.log(a1,b1);//输出 a1 =1 b1 = 100
解构+对象默认值
和数组默认值用法一样
const obj = {
username: 100,
height: 500,
};
const { username, height = 200 } = obj;
console.log(username, height); //输出100,500
拓展运算符||剩余运算符
剩余思想(获取剩下的数据)
数组中获取
const [a,b,...c]=[1,2,3,4,5,6,7];
const [a,b,...c]=[1,2,3];
const [a, b, ...c] = [1, 2];
console.log(c);// 输出[3,4,5,6,7]
console.log(c); // 输出 [3]
console.log(c); // 输出 []
也可以利用... 将伪数组转成数组
对象中获取
const { a, ...c } = { a: 1, b: 2, c: 3 };
const { a1,b1,c1 ,...d1 } = { a1: 1, b1: 2, c1: 3 };
console.log(c);// 输出 {b:2,c:3}
console.log(d1); // 输出 {}
函数中获取
用在函数的形参中,输出数组的格式
calc(1, 2, 3);
function calc(...args) {
// args= 数组 装载这所有传给calc的参数
console.log(args); //输出 args = [1,2,3]
}
应用场景:计算数据求和
function calc(...args) {
let sum = 0;
args.forEach((value) => (sum += value));
console.log(sum);
}
calc(1, 2); // 输出3
calc(1, 2, 3); // 输出6
calc(1, 2, 3, 4); // 输出10
拓展思想
数组中获取
const arr = ['a', 'b', 'c'];
// 在数组的后面 新增一个 元素 'd'
const newArr=[...arr,'d']; // 输出['a', 'b', 'c','d']
console.log(newArr);
// 在数组的前面 新增一个属性 w
const newArr1 = ['w', ...arr];
console.log(newArr1); // 输出['w','a', 'b', 'c']
对象中获取
const obj = {
username: '悟空',
height: 200,
};
const newObj1 = { ...obj, color: 'yellow' }; // 给newObj 开辟新的内存空间
newObj1.username = '八戒';
newObj1.weight = 100;
console.log(newObj1); //输出{username: '八戒', height: 200, color: 'yellow', weight: 100}
数组去重
方式1:some方法,只要有一个符合条件就返回true
const input = document.querySelector('input');
const ul = document.querySelector('ul');
const arr = ['a', 'b'];
render();
input.addEventListener('keydown', function (event) {
//判断按下的是不是回车
if (event.key === 'Enter') {
// console.log(this.value);
// some 如果数组中有一项 是返回了true 整个some方法就返回了true
// 调用some方法的时候,在它的回调函数中 拿数组中的元素 和 当前要添加的元素 做比较 如果相等 就返回true 表示找到了重复
const isHas = arr.some((value) => value === this.value); // 在我的数组中找到了和你待添加的元素 一样的值 返回true
if (isHas) {
// 有重复了 不要再添加
console.log('有重复了 不要再添加');
} else {
// 没有重复 你可以添加
// 把它添加到数组中
arr.push(this.value);
// 数组发生了改变 重新调用render方法 来实现页面的渲染
render();
}
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join('');
ul.innerHTML = html;
}
方式2:假设定义法,定一个变量表示有没有重复的数据,对数组中的每一个元素和输入框的值循环做比较,如果找到重复就跳出循环
const input = document.querySelector('input');
const ul = document.querySelector('ul');
const arr = ['a', 'b'];
render();
input.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
// 假设它 没有重复
let isHas = false;
for (let index = 0; index < arr.length; index++) {
// 如果找到了,设置 isHas=true 同时 打断循环
if (arr[index] === this.value) {
// 找到重复了
isHas = true;
break;
}
}
// 判断数据有没有重复
if (isHas) {
// 有重复
console.log('有重复');
} else {
// 没有重复 添加
arr.push(this.value);
render();
}
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join('');
ul.innerHTML = html;
}
方式3:filter方法,过滤出和当前输入框不相等的数据组成新数组,然后旧数组等于新数组,最后再添加过滤好的新数组
const input = document.querySelector('input');
const ul = document.querySelector('ul');
let arr = ['a', 'b'];
render();
input.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
// 过滤出不包含 当前输入框的值的数组
const newArr = arr.filter((value) => value !== this.value);
console.log(newArr)
// debugger
// 让我们的旧的数组 等于你过滤后的数组
arr = newArr;
arr.push(this.value);
render();
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join('');
ul.innerHTML = html;
}
方式4:假设定义法,利用数组删除方法,先删除相同的再添加
const input = document.querySelector('input');
const ul = document.querySelector('ul');
let arr = ['a', 'b'];
render();
input.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
let i = -1; // -1 表示没有找到
for (let index = 0; index < arr.length; index++) {
if (arr[index] === this.value) {
i=index;
break;
}
}
// 判断 i 等于-1 表示没有相同,直接添加
// i 不等于-1 表示有相同,先执行删除 再添加
if(i===-1){
arr.push(this.value);
}else{
// 找到相同
arr.splice(i,1);
arr.push(this.value);
}
render();
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join('');
ul.innerHTML = html;
}
方式5:set方法去重
基础知识
set 是一个对象,不是数组
使用set 数组去重,需要先考虑把旧数组转成对象,最后再将对象转成数组
数组转对象方法 :new Set(beforeArr)
去重处理 : set.add( 元素)
对象转数组方法:const arr = [...set]
去重案例
const input = document.querySelector("input");
const ul = document.querySelector("ul");
let arr = ["a", "b"];
render();
input.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
// 去重处理
const set = new Set(arr); //1.数组转对象
set.add(this.value); //2.去重处理
arr = [...set]; //3.对象转数组
render();
input.value = "";
}
});
function render() {
const html = arr.map((value) => `<li>${value}</li>`).join("");
ul.innerHTML = html;
}
函数的四种调用模式
函数调用模式
如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window
function fn(){
console.log(this);// 指向window
}
fn();
方法调用模式
当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象
const obj = {
sayHi:function(){
console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
}
}
obj.sayHi();
构造函数调用模式
如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。
function Person() {
this.name = '悟空';
}
Person.prototype.say = function () {
console.log(this); //this指向被实例化,p1
};
const p1 = new Person();
p1.say();
方法借用模式
也叫上下文模式,分为 apply 与 call
call
call方法可以调用一个函数,并且可以指定这个函数的this指向
call应用:将伪数组转成数组
let newArr = Array.protype.slice.call(伪数组)
apply
就是apply()方法接受的是一个包含多个参数的数组。而call()方法接受的是若干个参数的列表
apply应用:1.简化log方法
bind方法
**bind()**方法创建一个新的函数, 可以绑定新的函数的this指向
const father = {
name: "灰太狼",
skill() {
console.log(this.name + "会抓羊");
},
};
const son = {
name: "小灰灰",
};
// call 方式来修改this的指向
father.skill.call(son); //this 指向son
// apply 方式来修改this的指向
father.skill.apply(son); //this 指向son
// bind 方式来修改this指向
// bind 不会直接调用skill函数 而是 返回一个新的函数
// 需要我们主动的调用新的函数- 调用skill()
const func = father.skill.bind(son)
func()
js数组装字符串(3种方法)和字符串转数组(2种方法)
数组转字符串
JavaScript 允许数组与字符串之间相互转换。其中 Array 方法对象定义了 3 个方法,可以把数组转换为字符串,如表所示。
1:join()方法用于把数组中的所有元素放入一个字符串
元素是通过指定的分隔符进行分隔的
// join(',')
const a= ["00", "01", "02", "03", "04"]
const b= a.join(',')
console.log(b)
console.log( typeof b)
//打印结果 00,01,02,03,04
或者
// join('-')
const a= ["00", "01", "02", "03", "04"]
const b= a.join('-')
console.log(b)
console.log( typeof b)
//打印结果 00-01-02-03-04
或者
// join('!')
const a= ["00", "01", "02", "03", "04"]
const b= a.join('!')
console.log(b)
console.log( typeof b)
//打印结果 00!01!02!03!04
2:toString()方法可把一个逻辑值转换为字符串,并返回结果
const a= ["00", "01", "02", "03", "04"]
const c = a.toString(); //把数组转换为字符串
console.log(c)
console.log(typeof c); //返回字符串string,说明是字符串类型
//打印结果 00,01,02,03,04
toString()方法不可以指定分隔符,但是我们可以通过replace()方法指定替换
const a= ["00", "01", "02", "03", "04"]
const f = a.toString().replace(/,/gi,'-') // 正则表达式/,/gi,'-'
console.log(f)
//打印结果:00-01-02-03-04
3:toLocaleString()
把数组转换成本地约定的字符串
const a= ["00", "01", "02", "03", "04"]
const e = a.toLocaleString();
console.log(e)
console.log(typeof e);
//打印结果:00,01,02,03,04
字符串转数组
1:split() 方法用于把一个字符串分割成字符串数组
const arr = 'aa,bb,cc,dd'
const newStr = arr.split()
console.log(newStr)
// 打印结果: ["aa,bb,cc,dd"]
2:es6里面的扩展运算符
const arr = 'aa,bb,cc,dd'
const newStr = [...arr]
console.log(newStr)
//打印结果 ["a", "a", ",", "b", "b", ",", "c", "c", ",", "d", "d"]