JavaScript面向对象
一.面向对象编程
面向对象(oop)是把事务分解成一个个对象,然后有对象之间分工与合作。
三大特性:继承 封装 动态
优点:易维护,易复用,易扩展,由于面向对象有继承 封装 动态三大特性可以设计出低耦合的系统,使系统更加灵活,便于维护
缺点:性能比面向对象低
二.ES6中的类和对象
1.面向对象的思维特点
1.抽取(抽象 )对象公用的属性和行为组成(封装)成一个类(模板)
2.对类进行实例化,获得类的对象
对象由属性和方法组成:
属性:事物的特征
方法:事物的行为
2.类 class
对象是类的实例化
类泛指一大类,对象特指某一个,通过类实例化一个具体的对象
3.创建类和对象
<!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>
</head>
<body>
<script>
//1.创建类class 创建一个明星类
class star {
// constructor构造函数 可以接收传递过来的参数 同时返回实例对象 在new的时候执行
//必须写constructor
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
//方法
//类里面 方法之间 不用加逗号!!
//类中方法前不用加function
//可以传递参数
sing(song) {
console.log(this.uname + "会唱" + song);
}
}
//2.利用类创建对象 new
var dlrb = new star("迪丽热巴", 18);
console.log(dlrb);
dlrb.sing("wild");
var ycy = new star("杨超越", 15);
console.log(ycy);
</script>
</body>
</html>
三.类的继承
1.子承父业!
<!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>
</head>
<body>
<script>
//类的继承
class Father {
constructor() {
}
money() {
console.log(100);
}
}
//子类
class Son extends Father {
}
//使用
//可以使用父类的方法和属性
var son = new Son();
son.money();
</script>
</body>
</html>
2.super关键字
<!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>super关键字</title>
</head>
<body>
<script>
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
//加法
sum() {
console.log("求和是:" + parseInt(this.x + this.y));
}
say() {
console.log();
return "我是father";
}
}
class Son extends Father {
constructor(x, y) {
//调用父类的构造函数 必须在子类this之前调用
super(x, y);
this.x = x;
this.y = y;
}
say() {
//有返回值的方法才能被super调用
console.log(super.say() + "'s son");
}
//减法
subtract() {
console.log("求差是:" + parseInt(this.x - this.y));
}
}
var son = new Son(1, 3);
son.sum();
son.subtract();
//调用子类的say方法
//继承中的属性方法查找原则:
// 1.继承中 如果实例化子类输出一个方法 先看子类有没有这个方法 如果有就先执行子类的
// 2.如果子类没有 就去查找父类有没有这个方法 如果父类中有就回去执行父类这个方法(就近原则)
son.say();
</script>
</body>
</html>
3.三个注意点
1.在ES6中没有变量的提升 所以必须先定义类,才能通过类实例化对象。
2.类里面的共有属性和方法一定要加this才能调用
3.constructor里面的this指向实例对象,方法里面的this指向这个方法的调用者。
四.面向对象案例
tab栏切换功能
<!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>tab栏切换功能</title>
<style>
/* css样式部分 */
* {
margin: 0;
padding: 0;
}
ul li {
list-style: none;
}
main {
width: 960px;
height: 500px;
border-radius: 10px;
margin: 50px auto;
}
main h4 {
height: 100px;
line-height: 100px;
text-align: center;
}
.tabsbox {
width: 900px;
margin: 0 auto;
height: 400px;
border: 1px solid lightsalmon;
position: relative;
}
nav ul {
overflow: hidden;
}
nav ul li {
float: left;
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
border-right: 1px solid #ccc;
position: relative;
}
nav ul li.liactive {
border-bottom: 2px solid #fff;
z-index: 9;
}
#tab input {
width: 80%;
height: 60%;
}
nav ul li span:last-child {
position: absolute;
user-select: none;
font-size: 12px;
top: -18px;
right: 0;
display: inline-block;
height: 20px;
}
.tabadd {
position: absolute;
/* width: 100px; */
top: 0;
right: 0;
}
.tabadd span {
display: block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border: 1px solid #ccc;
float: right;
margin: 10px;
user-select: none;
}
.tabscon {
width: 100%;
height: 300px;
position: absolute;
padding: 30px;
top: 50px;
left: 0px;
box-sizing: border-box;
border-top: 1px solid #ccc;
}
.tabscon section,
.tabscon section.conactive {
display: none;
width: 100%;
height: 100%;
}
.tabscon section.conactive {
display: block;
}
</style>
</head>
<body>
<main>
<h4>
Js 面向对象 动态添加标签页
</h4>
<div class="tabsbox" id="tab">
<!-- tab 标签 -->
<nav class="fisrstnav">
<ul>
<li class="liactive"><span>测试1</span><span class="delete">x</span></li>
<li><span>测试2</span><span class="delete">x</span></li>
<li><span>测试3</span><span class="delete">x</span></li>
</ul>
<div class="tabadd">
<span>+</span>
</div>
</nav>
<!-- tab 内容 -->
<div class="tabscon">
<section class="conactive">测试1</section>
<section>测试2</section>
<section>测试3</section>
</div>
</div>
</main>
<script src="js/tab.js"></script>
</body>
</html>
tab.js
var that;
class Tab {
constructor(id) {
//获取元素
that = this;
this.main = document.querySelector(id);
this.add = this.main.querySelector('.tabadd');
//li的父元素
this.ul = this.main.querySelector('.fisrstnav ul:first-child');
//section的父元素
this.tabscon = this.main.querySelector('.tabscon');
this.init();
}
//事件绑定 让相关的元素绑定事件
init() {
this.updateNode();
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab;
this.remove[i].onclick = this.removeTab;
this.span[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
}
}
//重新获取
updateNode() {
this.lis = this.main.querySelectorAll('li');
this.sections = this.main.querySelectorAll('section');
this.remove = this.main.querySelectorAll('.delete');
this.span = this.main.querySelectorAll('.fisrstnav li span:first-child')
}
//切换功能
toggleTab() {
that.clearClass();
this.className = 'liactive';
that.sections[this.index].className = 'conactive';
}
//清除 所有
clearClass() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
//添加功能
addTab() {
//先清除 在修改 排他思想
that.clearClass();
//创建li元素和section元素
var li = '<li class="liactive"><span>新建窗口</span><span class="delete">x</span></li>';
var section = '<section class="conactive">新建测试</section>';
that.ul.insertAdjacentHTML('beforeend', li);
that.tabscon.insertAdjacentHTML('beforeend', section);
//添加之后 刷新一下
that.init();
}
//删除功能
removeTab(e) {
//停止冒泡
e.stopPropagation();
var index = this.parentNode.index;
//根据索引号删除对应的li和sectin
that.lis[index].remove();
that.sections[index].remove();
//删除后 刷新一下
that.init();
//当我们删除的不是选中状态的li的时候,原来的选中状态li保持不变
if (document.querySelector('.liactive')) return;
//当删除了选中状态的li的时候 让他前一个li处于选中状态。
index--;
//手动调用点击事件
that.lis[index] && that.lis[index].click();
}
//修改功能
editTab() {
var str = this.innerHTML;
//双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
//添加文本框
this.innerHTML = '<input type="text" />';
var input = this.children[0];
input.value = str;
input.select(); //让文本框文字处于选中状态
//离开文本框就把文本框里面的值给span
input.onblur = function() {
this.parentNode.innerHTML = this.value;
}
//按下回车也可以把文字的值给span
input.onkeyup = function(e) {
if (e.keyCode === 13) {
//手动调用表单失去焦点事件 不需要鼠标离开操作
this.blur();
}
}
}
}
new Tab("#tab");
构造函数和原型
一.构造函数和原型
1.概述
在典型的OOP语言中(JAVA),都存在类的概念,类似对象的模板,对象是类的实例,但是在ES6以前,JS没有引入类的概念。ES6全称为ECMAScript6.0,2015.06发版。在ES6之前,对象不是由类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特征。
2.构造函数
构造函数是一种特殊的函数,主要是用来初始化对象。即为对象成员变量赋初始值,总是与new一起使用。我们可以把对象中一些公共属性和方法抽取出来,然后封装到这个函数里面去。
构造函数使用时注意:
1.构造函数用于创建某个对象首字母要大写。
2.构造函数要和new关键字一起使用,才有意义!
new执行时做的四件事:1.在内存创建一个新的空对象。2.让this指向这个新的对象。3.执行构造函数里面的代码,给这个新对象添加属性和方法。4.返回这个新对象,所以构造函数中不需要return。
实例成员:就是构造函数内部通过this添加的成员。只能通过实例化对象访问。
静态成员:在构造函数本身上添加的成员。只能通过构造函数来访问。
3.存在问题:存在内存浪费问题
3.构造函数原型对象prototype
主要作用:共享方法
构造函数通过原型分配的函数是所有对象共享的,javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的属性和方法,都会被构造函数所拥有。我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例可以共享这些方法。
一般情况下,我们的公共属性定义到构造函数里面!公共方法定义到原型对象中!
<!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>构造函数原型对象prototype</title>
</head>
<body>
<script>
function Star(name, age) {
//实例成员:就是构造函数内部通过this添加的成员
this.name = name;
this.age = age;
}
//原型对象:存放公共的方法
//公共属性 定义到构造函数中去
Star.prototype.sing = function() {
console.log("我会唱歌");
}
var ldh = new Star('刘德华', 15);
var zxy = new Star('张学友', 18);
//静态成员 :在构造函数本身上添加的成员。
Star.sex = '男';
//静态成员:只能通过构造函数来访问。
console.log(Star.sex); //男
console.log(ldh.sex); //undefined
//实例成员:只能通过实例化对象访问
console.log(ldh.name); //刘德华
//地址值比较
console.log(ldh.sing === zxy.sing); //true 说明原型对象prototype生效!
ldh.sing(); //在对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象 prototype
console.log(ldh.__proto__ === Star.prototype); //true!
//方法查找顺序:首先查看ldh对象身上是否有sing方法,如果有就执行这个对象上的sing方法
// 没有的话,因为有__proto__ 的存在,就会去构造函数原型对象prototype 中找
</script>
</body>
</html>
5.构造函数constructor
对象原型_ prpto _ 和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为他指回构造函数本身。
<!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>构造函数constructor</title>
</head>
<body>
<script>
function Star(name, age) {
this.name = name;
this.age = age;
}
//很多情况下,需要手动利用constructor 这个属性返回原来的构造函数
//正常情况下
/* Star.prototype.sing = function() {
console.log("我会唱歌");
}
Star.prototype.movie = function() {
console.log("我会拍电影");
} */
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值时的是以一个对象的形式,
// 则必须加上constructor: 指回原来的构造函数,!
constructor: Star,
sing: function() {
console.log("我会唱歌");
},
movie: function() {
console.log("我会拍电影");
}
}
var ldh = new Star('刘德华', 15);
var zxy = new Star('张学友', 18);
console.log(Star.prototype); //指回Star
console.log(Star.prototype.constructor); //指回构造函数
console.log(ldh.__proto__); //指回Star
console.log(ldh.__proto__.constructor); //指回构造函数
</script>
</body>
</html>
6.构造函数、实例、原型对象三者之间的关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJ7x9rcj-1676954555873)(C:\Users\t-y-x\AppData\Roaming\Typora\typora-user-images\image-20230131211452330.png)]
7.原型链
<!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>
</head>
<body>
<script>
function Star(name, age) {
this.name = name;
this.age = age;
}
Star.prototype.sing = function() {
console.log("我会唱歌");
}
var ldh = new Star('刘德华', 15);
//只要是对象就会有 __proto__ 原型,指向原型对象
//Star原型对象里面__proto__ 原型指向的是Object.prototype
console.log(Star.prototype.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__); //null
</script>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pK5uKT3k-1676954555874)(C:\Users\t-y-x\AppData\Roaming\Typora\typora-user-images\image-20230131212533362.png)]
8.JavaScript的成员查找机制
按照原型链机制查找
1.当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
2.如果没有就去查找他的原型(也就是_ _ proto _ _指向的prototype原型对象)
3.如果还没有就查找原型对象的原型(Object的原型对象)
4.以此类推一直遭到Object为止(null)
9.原型对象this指向
在构造函数中this指向的时里面的对象实例 ,在原型对象函数里面的this 指向的都是实例对象 。
10.扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。
<!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>
</head>
<body>
<script>
//原型对象的应用-扩展内置对象
//之前没有sum
console.log(Array.prototype);
Array.prototype.sum = function() {
for (var i = 0; i < this.length; i++) {
var sum = 0;
sum += this[i];
}
return sum;
}
var arr = [1, 5, 8, 4];
console.log(arr.sum());
//添加之后有了sum方法
console.log(Array.prototype);
</script>
</body>
</html>
二.继承
ES6之前并没有提供继承extends继承。可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
1.call()
调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg, arg1, arg2, …)
参数:thisArg: 当前调用函数this的指向对象。 arg1:传递的参数
<!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>call方法</title>
</head>
<body>
<script>
//call方法
function fn(x, y) {
console.log('我不想和你');
console.log(this); //Window 改变指向后变成了o
console.log(x + y); //3
}
var o = {
name: 'andy'
}
//call(): 可以调用函数
//可以改变这个函数的this指向 改变之后this指向变成了o,
fn.call(o, 1, 2);
</script>
</body>
</html>
2.借用构造函数继承父类型属性和方法
核心原理:通过call()把父类型的this指向子类型的this,这样可以实现子类型继承父类型的属性
<!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>
</head>
<body>
<script>
//借用父构造函数继承属性
//父构造函数
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
//父元素专门的方法
Father.prototype.money = function() {
console.log('10000');
}
//子构造函数
function Son(uname, age) {
//this指向之构造函数的对象实例, 修改指向对象
//实现继承Father的属性!!
Father.call(this, uname, age);
}
//实例化父构造函数
//实现继承父类的方法!!
Son.prototype = new Father();
//利用对象的形式修改原型对象 ,要用constructor指回构造函数
Son.prototype.constructor = Son;
//这是子元素专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试!');
}
var son = new Son('zi', 12);
var fa = new Father('fa', 12);
console.log(son);
console.log(fa);
console.log(Son.prototype.constructor);
console.log(Father.prototype);
</script>
</body>
</html>
3.类的本质
ES6的类他大部分的功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰,更加面向对象编程而已!
ES6是ES5的语法糖!
<!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>
</head>
<body>
<script>
//ES6之前通过构造函数+原型对象编程
// 1.构造函数有原型对象prototype
// 2.构造函数原型对象prototype 里面有constructor 指向构造函数本身
// 3.构造函数可以通过原型对象添加方法
// 4.构造函数创建的实例对象有__proto__原型指向 构造函数的原型对象
//ES6通过类实现面向对象编程
class Star {
}
console.log(typeof Star); //function
//类的本质就是函数 可以简单以为类就是构造函数的另外一种写法
// 1.类有原型对象prototype
console.log(Star.prototype); //存在原型对象
// 2.类原型对象prototype 里面有constructor 指向构造函数本身
console.log(Star.prototype.constructor); //指向类本身
// 3.类可以通过原型对象添加方法
Star.prototype.sing = function() {
console.log('冰雨');
}
var ldh = new Star();
console.log(ldh); //存在sing方法
// 4.类创建的实例对象有__proto__原型指向 构造函数的原型对象
console.log(ldh.__proto__ === Star.prototype); //true
</script>
</body>
</html>
三.ES5中的新增方法
1.数组方法
迭代(遍历)方法:forEach()、map()、 filter()、some()、every()
filter()、forEach() 里面return true不会终止迭代, some()里面遇到return true 就是终止遍历 迭代效率更高,所以查找唯一的元素就用some()!
<!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>
</head>
<body>
<script>
//forEach 迭代遍历数组
var arr = [1, 2, 3];
var sum = 0;
arr.forEach(function(value, index, array) {
console.log('每个数组元素:' + value);
console.log('每个数组元素索引号:' + index);
console.log('数组本身:' + array);
sum += value;
})
console.log("求和是:" + sum);
//filter()方法 :用于进行数组的筛选
var arr1 = [11, 2, 62, 31, 48];
var newArr = arr1.filter(function(value, index, arr) {
//用return返回满足条件的元素 注意要写return!!!
return value >= 20;
})
console.log(newArr);
</script>
</body>
</html>
案例-查询商品
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
table {
width: 400px;
border: 1px solid #000;
border-collapse: collapse;
margin: 0 auto;
}
td,
th {
border: 1px solid #000;
text-align: center;
}
input {
width: 50px;
}
.search {
width: 600px;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="search">
按照价格查询: <input type="text" class="start"> - <input type="text" class="end"> <button class="search-price">搜索</button> 按照商品名称查询: <input type="text" class="product"> <button class="search-pro">查询</button>
</div>
<table>
<thead>
<tr>
<th>id</th>
<th>产品名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 利用新增数组方法操作数据
var data = [{
id: 1,
pname: '小米',
price: 3999
}, {
id: 2,
pname: 'oppo',
price: 999
}, {
id: 3,
pname: '荣耀',
price: 1299
}, {
id: 4,
pname: '华为',
price: 1999
}, ]
// 获取tbody
var tb = document.querySelector('tbody');
var search_price = document.querySelector('.search-price');
var start = document.querySelector('.start');
var end = document.querySelector('.end');
var search_pro = document.querySelector('.search-pro')
var product = document.querySelector('.product');
// 把数据渲染到页面中
datas(data)
function datas(data) {
// 清空tbody里面的内容
tb.innerHTML = '';
data.forEach(function(value) {
// 创建一个行
var tr = document.createElement('tr');
// 创建三个列
tr.innerHTML = '<td>' + value.id + '</td><td>' + value.pname + '</td><td>' + value.price + '</td>';
// 把这个行追加到tbody里面
tb.appendChild(tr);
})
}
//根据价格查询商品
//当我们点击了按钮,就可以根据我们的商品价格去筛选数组里面的对象
search_price.addEventListener('click', function() {
var newDate = data.filter(function(val) {
return val.price >= start.value && val.price <= end.value;
})
//清除表单数据
tb.innerHTML = '';
//把数据放到表单中
datas(newDate);
})
//根据商品名查找商品
//查找数组中唯一的元素用some比较合适 因为他找到这个元素就不再进行循环了 效率高
search_pro.addEventListener('click', function() {
var arr = [];
data.some(function(val) {
if (val.pname === product.value) {
arr.push(val);
//结束some
return true;
}
});
//渲染数据
datas(arr);
})
</script>
</body>
</html>
2.字符串的方法
trim()方法 会从一个字符串的两端删除空白字符!这个方法不会影响字符串本身,返回一个新的字符串。
<!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>
</head>
<body>
<input type="text"> <button>验证</button>
<div></div>
<script>
//trim 方法去除字符串两侧的空格
var str = ' str ';
console.log('加了.trim方法后的str:' + str.trim());
console.log('原来的str:' + str);
var input = document.querySelector('input');
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function() {
var str = input.value.trim();
if (str === '') {
console.log('请输入内容!');
} else {
console.log(str);
console.log(str.length);
div.innerHTML = str;
}
}
</script>
</body>
</html>
3.对象方法
1.Object.keys() 用于获取对象自身的所有属性,返回数组
2.Object.defineProperty(obj, prop, descriptor) 定义对象中新属性或修改原有属性,obj目标对象,prop需要定义或修改的属性名字,descriptor目标属性所拥有的特性,以对象形式传递 有四个参数可以设置,VUE中有用到!!!
<!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>
</head>
<body>
<script>
var obj = {
id: 1,
name: '小米',
price: 1999,
num: 2000
//在对象中直接创建的属性和值 writable enumerable configurable默认值是true
//利用defineProperty创建时writable enumerable configurable 默认值是false
};
//将对象中所有属性存放到数组中!
var arr = Object.keys(obj);
//以前的对象添加和属性修改的方式
// obj.price = 1222;
// obj.num = 100;
//利用defineProperty 修改属性或添加属性
Object.defineProperty(obj, 'num', {
//value:设置属性值 默认undefined
value: 1000,
//writable:值是否可以重写 true或者false
//enumerable:目标属性是否可以被枚举 true或者false
//configurable:目标属性是否可以被删除或者是否可以再次修改特性 true或者false
});
console.log(obj);
Object.defineProperty(obj, 'id', {
//value:设置属性值 默认undefined
//writable:值是否可以重写 true或者false
writable: false, //false不允许被修改
//enumerable:目标属性是否可以被枚举 true或者false
//configurable:目标属性是否可以被删除或者是否可以再次修改特性 true或者false
});
//修改id!但是上面设置不然修改 所以修改不成功
obj.id = 10;
console.log(obj);
Object.defineProperty(obj, 'adress', {
//value:设置属性值 默认undefined
value: '上海!',
//writable:值是否可以重写 true或者false
//enumerable:目标属性是否可以被枚举 true或者false
enumerable: false,//不会被遍历出来!
//configurable:目标属性是否可以被删除或者是否可以再次修改特性 true或者false
configurable: false //为false不允许被删除
});
console.log(Object.keys(obj));
</script>
</body>
</html>
函数进阶
一.函数的定义和调用
1.函数的定义方式
<!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>
</head>
<body>
<script>
//函数定义方式
//自定义函数
function fn() {
};
//函数表达式
var fun = function() {
};
//利用new Function('参数一', '参数2', '函数体');
//Function里面参数必须都是字符串格式的
//这种方法效率较低
//所有函数都是Function的实例,函数并且也属于对象
var f = new Function('a', 'b', 'console.log(a+b)');
//调用
f(1, 2);
</script>
</body>
</html>
2.函数调用方式
<!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>
</head>
<body>
<script>
//1.普通函数
function fn() {
console.log('人生低谷');
}
fn();
//2.对象方法
var o = {
sayHi: function() {
console.log('人生瓶颈');
}
}
o.sayHi();
//3.构造函数
function Star() {
this.sing = function() {
console.log('我会唱歌');
}
}
var star = new Star();
star.sing();
//4.绑定点击事件 点击了btn就会调用函数
//btn.onclick = function(){};
//5.定时器函数 1s触发一次函数
//setInterval(function(){}, 1000);
//6.立即执行函数
(function(){
console.log("立即执行函数");
})
</script>
</body>
</html>
二.this
1.函数内部this的指向
这些this的指向,是当我们调用函数的时候绑定的。调用方式不同决定了this指向不同。一般指向我们的调用者!
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法也指向实例对象 |
方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
2.改变函数内部this指向
常用的方法bind(),call(),apply()三种方法
call方法 调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向,使用这个方法后直接执行!
apply方法也可以改变this指向,使用完直接调用函数!
<!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>apply方法</title>
</head>
<body>
<script>
var o = {
name: 'andy'
}
function fn(arr) {
console.log(this); //andy
console.log(arr); //pink
}
//调用函数 可以改变函数内部的this指向
//参数 必须是数组形式
//主要应用于 数学内置对象求最大值或者最小值!
fn.apply(o, ['pink']); //修改指向
//例子
var arr1 = [18, 51, 35, 74, 67, 86, 48, 56];
var max = Math.max.apply(Math, arr1); //86
console.log(max);
</script>
</body>
</html>
bind方法不会调用函数。可以改变内部指向!
<!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>bind方法</title>
</head>
<body>
<button>按钮</button>
<script>
var o = {
name: 'andy'
}
function fn(a, b) {
console.log(this); //andy
console.log(a + b);
}
//修改指向 不调用函数
var f = fn.bind(o, 1, 2);
f(); //这么调用函数
//按钮定时功能
var btn = document.querySelector('button');
btn.onclick = function() {
this.disabled = true; //this指向的是btn按钮
setTimeout(function() {
this.disabled = false; //按钮开启
}.bind(this), 3000); //this指向btn
}
</script>
</body>
</html>
案例-tab栏的应用(改进)
vscode中有!
3.call apply bind 总结
相同点:都可以改变函数内部的this指向
区别点:call和apply会调用蛤属,并且改变函数内部的this指向。call和apply 传递参数不一样,call传递参数aru1 ,aru2…的形式,apply必须用数组的形式。bind不会调用函数 ,只会改变函数内部的this指向
应用场景:call经常用于继承,apply经常和数组一起操作,但不想调用函数还想改变其内部指向就用bind方法!
三.严格模式
1.简介
JavaScript除了提供正常模式外,还提供了严格模式。ES5的严格模式是采用具有限制性的JavaScript变体的一种方式,即在严格的条件下执行js代码。在IE10以上的版本才会被支持,旧版本的浏览器中会被忽略。
目的:消除了JavaScript语法不合理、不严谨的地方、减少一些怪异行为,消除代码运行不安全的地方,提高效率,增加运行速度。
2.开启严格模式
为脚本开启严格模式
在所有语句前放一个特定的语句:‘use strict’;
<script>
(function(){
//开启严格模式
'use strict'
})();
</script>
为函数开启严格模式
<script>
function fn(){
'use strict';
// 只给第一个函数添加严格模式 只有里面才是严格模式
}
function fun(){
//按照普通模式执行
}
</script>
3.严格模式的变化
变量变化
必须先声明在使用 前面加var
严格模式下this指向问题:
以前在全局作用域函数中的this指向window对象。
严格模式下全局作用域中函数中的this是undefined。
以前构造函数 不加new也可以调用,当普通函数,this指向全局对象。
严格模式下,构造函数不用new调用,this会报错。
new实例化的构造函数指向创建对象的实例。
定时器的this还是指向window。
事件、对象还是指向调用者
函数变化
不能有重名的参数
四.高阶函数
高阶函数是对其他函数进行操作的函数,他接收函数作为参数或将函数作为返回值输出。此时就称之为高阶函数。
<!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>
</head>
<body>
<script>
//高阶函数- 函数作为参数传递 回调函数就是高级函数
function fn(a, b, callback) {
console.log(a + b);
//如果callback存在就执行
callback && callback();
}
fn(1, 2, function() {
console.log('我是最后调用的');
});
</script>
</body>
</html>
五.闭包
1.变量作用域
全局变量:函数内部可以使用全局变量
局部变量:函数外部不可以使用全局变量
当函数执行完毕,本作用域内的局部变量会销毁
2.闭包概念
闭包指有权访问另一个函数作用域中变量的函数。闭包就是一个函数!(用return 匿名函数实现)
主要作用:延伸了变量的作用范围
<!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>
</head>
<body>
<script>
//闭包closure函数fn
function fn() {
var num = 1;
return function() {
//只要一个作用域访问了 另一个作用域中的局部变量就会产生闭包
//内访问的函数称之为闭包函数
//console.log(num);验证
};
}
//在外面全局作用域 访问了局部变量num
var f = fn();
//f存的是fn函数中的匿名函数
f();
</script>
</body>
</html>
案例-点击li打印当前索引号
<!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>案例-点击li打印当前索引号</title>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>罐头</li>
<li>披萨</li>
</ul>
<script>
//点击一个小li输出当前li
var lis = document.querySelector('.nav').querySelectorAll('li');
//利用闭包得到当前li的索引号
for (var i = 0; i < lis.length; i++) {
//利用for循环创建四个立即执行函数
//立即执行函数 称为小闭包 因为立即执行函数中任何一个函数都可以使用他的i这个变量
(function(i) {
lis[i].onclick = function() {
console.log(i);
}
})(i);
}
</script>
</body>
</html>
案例-3秒钟之后打印li的内容
<!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>案例-3秒钟之后打印li的内容</title>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>罐头</li>
<li>披萨</li>
</ul>
<script>
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function(i) {
setTimeout(function() {
console.log(lis[i].innerHTML);
}, 3000)
})(i);
}
</script>
</body>
</html>
案例-计算打车价格
<!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>
</head>
<body>
<script>
var car = (function() {
var start = 13; //起步价
var total = 0; //总价
return {
price: function(n) {
if (n <= 3) {
total = start;
} else {
total = (n - 3) * 5 + 13
}
return total;
},
yd: function(flag) {
//堵车
if (flag) {
return flag ? total + 10 : total
}
}
}
})();
console.log(car.price(1)); //13
console.log(car.yd(true)); //23
console.log(car.price(5)); //23
console.log(car.yd(true)); //33
</script>
</body>
</html>
3.闭包总结
闭包是一个函数(一个作用不同于可以访问到另外一个函数的局部变量)
作用:延伸变量的作用范围
六.递归
如果一个函数在调用本身就称为递归!注意加限定条件!不然会栈溢出
案例-利用递归
<!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>
</head>
<body>
<script>
//求阶乘
function prop(n) {
if (n == 1) {
return n = 1;
}
return n * prop(n - 1);
}
console.log(prop(3));
//斐波那契厄数列
function fei(n) {
while (n == 1 || n == 2) {
return 1;
}
return fei(n - 1) + fei(n - 2);
}
console.log(fei(3)); //2
//利用递归遍历数据
var data = [{
id: 1,
name: '家电',
goods: [{
id: 11,
gname: '冰箱'
}, {
id: 12,
gname: '洗衣机'
}]
}, {
id: 2,
name: '服饰',
goods: [{
id: 13,
gname: 'nike'
}, {
id: 14,
gname: 'adidas'
}]
}];
//利用foreach遍历 里面的每一个对象
var o = {};
function getId(json, id) {
json.forEach(function(item) {
if (item.id == id) {
o = item;
// console.log(item); 没有必要直接打印
} else if (item.goods && item.goods.length > 0) { //里面应该有goods数组
o = getId(item.goods, id);
}
});
return o;
}
console.log(getId(data, 1));
console.log(getId(data, 2));
console.log(getId(data, 11));
console.log(getId(data, 12));
console.log(getId(data, 13));
console.log(getId(data, 14));
</script>
</body>
</html>
浅拷贝和深拷贝
浅拷贝:只拷贝一层,更深层次对象级别的只拷贝引用
深拷贝:拷贝多层,每一级别的数据都会拷贝
Object.assign(拷贝到的对象,拷贝对象) ES6新增的方法可以实现浅拷贝
深拷贝
<!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>
</head>
<body>
<script>
//旧对象
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
//新对象
var o = {
};
//深拷贝函数封装
function deepCopy(newObj, oldObj) {
for (var k in oldObj) {
//判断属性值属于那种数据类型
var item = oldObj[k];
//判断值是否是数组
if (item instanceof Array) {
newObj[k] = [];
o.color = [];
deepCopy(newObj[k], oldObj);
} else if (item instanceof Object) {
//判断是否属于对象
newObj[k] = {};
deepCopy(newObj[k], item);
} else {
//属于简单数据类型
newObj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);
</script>
</body>
</html>
正则表达式
一.正则表达式概述
用于匹配字符串组合的模式,在JavaScript中,正则表达式也是对象,
二.正则表达式在JavaScript中的使用
<!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>正则表达式在JavaScript中的使用</title>
</head>
<body>
<script>
//1.利用RegExp对象来创建 正则表达式
var regexp = new RegExp(/123/);
//利用字面量创建 正则表达式
var rg = /123/;
//test 方法测试字符串是否复合正则表达式要求的规范
console.log(rg.test(1234)); //true
console.log(rg.test('abc')); //false
</script>
</body>
</html>
三.正则表达式中的特殊字符
1.正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以由简单和特殊字符的组合,/ab*c/。其中特殊字符也被称为元字符,在正则表达式中具有特殊意义的专用符号,比如:^、$、+等。
2.边界符
^……$:一起使用能有精确匹配的意思
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本,以谁开始 |
$ | 表示匹配行尾的文本,以谁结束 |
字符类 | |
[] | 表示有一系列字符可供选择,只要匹配其中一个就可以了 |
- | 表示一个范围 |
量词 | |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 中间不能有空格 |
<!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>
</head>
<body>
<script>
//正则表达式里面不需要加引号 不管是数值型还是字符串型
//边界符
var rg = /^abc$/; //必须是以abc开头 abc结尾
console.log(rg.test('aabc')); //false
console.log(rg.test('abc')); //true
console.log(rg.test('abcabc')); //false
console.log(rg.test('abcd')); //false
console.log('=========================');
//字符类
var rg1 = /[abc]/; //只要包含abc其中一个,都会返回true
var rg2 = /^[abc]$/ //只有是a b 或者 c 这三个字母才返回true
console.log(rg1.test('aabc')); //true
console.log(rg1.test('abc')); //true
console.log(rg1.test('abcabc')); //true
console.log(rg1.test('abcd')); //true
console.log('=========================');
console.log(rg2.test('a')); //true
console.log(rg2.test('b')); //true
console.log(rg2.test('c')); //true
console.log(rg2.test('abcd')); //false
console.log('=========================');
var rg3 = /^[a-z]$/; //26个英文字母任何一个字母 都返回true
console.log(rg3.test('a')); //true
console.log(rg3.test('b')); //true
console.log(rg3.test('c')); //true
console.log(rg3.test('A')); //false
console.log('=========================');
//字符组合
var rg4 = /^[a-zA-Z]$/; //26个英文字母任何一个字母不区分大小写 都返回true
console.log(rg4.test('a')); //true
console.log(rg4.test('b')); //true
console.log(rg4.test(1)); //false
console.log(rg4.test('A')); //true
console.log('=========================');
//ps:如果中括号里面有^ 表示取反的意思 不要和[]外面的弄混了!
//量词符:用来设定某个模式出现的次数
var reg5 = /^a*$/; //允许a出现0次 或者 很多次
var reg6 = /^a+$/; //允许a出现1次 或者 很多次
var reg7 = /^a?$/; //允许a出现1次 或者 不出现
var reg9 = /^a{3}$/; //允许a出现3次
var reg8 = /^a{3,}$/; //允许a出现3次以上的次数
var reg10 = /^a{3,10}$/; //允许a出现3到10次 {3,10}中间不能有空格
var reg11 = /^[a-zA-Z0-9_-]{3,10}$/; //允许前面的格式出现3到10次 {3,10}中间不能有空格
console.log(reg11.test('and_red')); //true
console.log(reg11.test('and-qwer')); //true
console.log(reg11.test(145248)); //true
console.log(reg11.test('AvgsyeSS')); //true
console.log('=========================');
</script>
</body>
</html>
案例-用户表单验证
<!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>
input {
width: 100px;
height: 15px;
}
.right {
font-size: 11px;
color: green;
}
.wrong {
font-size: 11px;
color: red;
}
.normal {
font-size: 11px;
color: #ccc;
}
</style>
</head>
<body>
<input type="text" class="uname">
<span class="normal">请输入用户名</span>
<script>
var reg = /^[a-zA-Z0-9_-]{6,13}$/;
var uname = document.querySelector('.uname');
var span = document.querySelector('span');
uname.onblur = function() {
if (reg.test(this.value)) {
span.className = 'right';
span.innerHTML = '用户名输入正确!';
} else {
span.className = 'wrong';
span.innerHTML = '用户名输入错误!';
}
}
</script>
</body>
</html>
3.括号总结
<!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>
</head>
<body>
<script>
//中括号 字符集合,匹配方括号中的任意字符
var reg = /^[abc]$/; //a可以 b可以 c可以
//大括号 量词符 里面表示重复次数
var reg2 = /^abc{3}$/; //只让c重复三次
console.log(reg2.test('abc')); //false
console.log(reg2.test('abcabcabc')); //false
console.log(reg2.test('abccc')); //true
//小括号 表示优先级 优先计算
var reg3 = /^(abc){3}$/; //abc重复三次
console.log(reg3.test('abc')); //false
console.log(reg3.test('abcabcabc')); //true
console.log(reg3.test('abccc')); //false
</script>
</body>
</html>
在线测试工具:https://c.runoob.com/
4.预定义类
指某些常见的格式简写
预定义类 | 说明 |
---|---|
\d | 匹配0-9之间的任意数字,相当于[0-9] |
\D | 匹配0-9以外的任意数字,相当于[ ^ 0-9 ] |
\w | 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_] |
\W | 匹配任意的字母、数字和下划线以外的字符,相当于[ ^ A-Za-z0-9_] |
\s | 匹配空格(包括换行符、制表符、空格符等),相当于[\t\r\n\v\f] |
\S | 匹配非空格的字符,相当于[ ^ \t\r\n\v\f] |
案例-号码验证
<!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>
</head>
<body>
<script>
//座机号码
var reg = /^\d{3}-\d{8} | \d{4}-\d{7}$/;
//手机号码
var phone = /^1[3|4|5|6|7|8]\d{9}$/;
//qq号
var qq = /^[1-9]\d{4,10}$/;
</script>
</body>
</html>
四.正则表达式中的替换
1.replace替换
replace()方法可以实现替换字符串的操作,用来替换的参数可以是一个字符串或是一个正则表达式。
格式:stringObject.replace(regexp/substr, replacement);
第一个参数:被替换掉字符串或者正则表达式
第二个参数:替换为的字符串
返回值是一个替换完毕的新的字符串
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>替换关键字</title>
<style>
textarea {
width: 300px;
height: 100px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<textarea name="" id="message"></textarea> <button>提交</button>
<div></div>
<script>
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function () {
//替换敏感词 激情,gay 为 **
div.innerHTML = text.value.replace(/激情|gay/g, '**');
}
</script>
</body>
</html>
2.正则表达式参数
格式:/正则表达式/[switch]
switch(也称为修饰符)按照什么样的模式来匹配 有三种值:
g:全局匹配
i:忽略大小写
gi:全局匹配+忽略大小写
ES6
一.概述
ES全称ECMAScript,是由ECMA国际标准化组织,制订的一项脚本语言的标准化规范,6是版本号!
ES6是一个泛指,指ES2015及其后续的版本。
二.ES6新增语法
1.let
ES6中新增的用于声明变量关键字,let声明的变量只在 处于的块级({}就是大括号)中有效。
特点:
1.防止循环变量变成全局变量
2.不存在变量提升,变量得先声明在使用!
3.暂时性死区
2.const
用来声明常量,常量就是值(内存地址)不能变化的量。
特点:
1.具有块级作用域
2.声明时必须给初始值
3.常量赋值后不能更改!(基本数据类型值不能被更改,复杂数据类型数组数据结构内部的值可以更改,数据值本身不能更改)
3.var、let、const区别
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可以更改 | 值可以更改 | 值不能更改 |
4.解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现解构。更加简便的从数组中提取值
数组解构
允许我们按照一一对应的关系从数组中提取值 然后赋值给变量
<!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>
</head>
<body>
<script>
//ES6新增
//定义数组
let [a, b, c, d, e] = [1, 2, 3];
//直接取值
console.log(a); //1
console.log(b); //2
console.log(c); //3
console.log(d); //undefined
console.log(e); //undefined
</script>
</body>
</html>
对象解构
允许我们使用变量的名字匹配对象的属性,匹配成功将对象的值赋值给变量
<!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>
</head>
<body>
<script>
//对象
let person = {
name: '张三',
age: 20
};
//对象解构 方式一
let {
name,
age,
sex
} = person;
console.log(name); //张三
console.log(age); //20
console.log(sex); //undefined 未定义的显示undefined
//方式二
let {
//左边用于属性匹配 右边是真正的解构变量名
name: myName,
age: myAge
} = person;
console.log(myName);
console.log(myAge);
</script>
</body>
</html>
5.箭头函数
ES6中新增的定义函数的方式!
<!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>
</head>
<body>
<script>
//正常形式
const fun = () =>{
console.log(123);
}
fun();
//当{}中语句只有一句时 {}可以省略!
const fn = (x, y) => x + y;
console.log(fn(1, 3));
//但小括号中的参数只有一个时 ()也可以省略
const f = v => v;
console.log(f(20));
</script>
</body>
</html>
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
<!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>箭头函数中的this</title>
</head>
<body>
<script>
function fn() {
console.log(this);
return ()=>{
console.log(this);
}
}
const obj = {
name: 'zhangsan'
};
fn.call(obj); //obj
const resFn = fn.call(obj);
resFn(); //obj
</script>
</body>
</html>
箭头函数面试题
<!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>
</head>
<body>
<script>
var age = 100;
var obj = {
age: 20,
say: () => {
//箭头函数 this弹出的对象是window中的对象所以是100 不是20!
alert(this.age);
}
}
obj.say(); //100
</script>
</body>
</html>
6.剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
<!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>
</head>
<body>
<script>
//剩余参数的基本使用
const sum = (...args) => {
let total = 0;
args.forEach(item => {
total += item;
})
return total;
};
console.log(sum(10, 20, 30));
console.log(sum(10, 20));
//剩余参数和解构一起使用
let arr = ['张三', '李四', '王五'];
let [s1, ...s2] = arr;
console.log(s1); //张三
console.log(s2); //一个数组Array(2)包含 李四和王五
</script>
</body>
</html>
三.ES6的内置对象扩展
1.Array的扩展方法
拓展运算符…
可以将数组或者对象转为逗号分隔的参数序列
<!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>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<script>
//扩展运算符可以将数组拆分成为以逗号分割的参数序列
let arr = ['a', 'b', 'c'];
//...扩展运算符! 可以把arr数组的参数 按逗号分开
console.log(...arr); //a b c
//扩展运算符可以运用在合并数组上
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
//方式一
let arr3 = [...arr1, ...arr2];
console.log(arr3); //(6) [1, 2, 3, 4, 5, 6]
//方式二 合并数组
arr1.push(...arr2);
console.log(arr1); //(6) [1, 2, 3, 4, 5, 6]
//将伪数组转换为 数组
//目地:让伪数组能使用数组的一些方法
var oDivs = document.getElementsByTagName('div');
console.log(oDivs); //HTMLCollection(8) [div, div, div, div, div, div, div, div]
var arrs = [...oDivs];
console.log(arrs); //(8) [div, div, div, div, div, div, div, div]
</script>
</body>
</html>
Array.from(要转换的伪数组, 函数)
将伪数组或可遍历对象转换为真正的数组,
<!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>Array.from(要转换的伪数组, 函数)</title>
</head>
<body>
<script>
//伪数组
var arrayLike = {
"0": 1,
"1": 2,
"length": 2
}
//第一个参数是要改变的数组
//第二个参数是 对变化的数组元素的变化
var ary = Array.from(arrayLike, item => item * 2);
console.log(ary); //(2) [2, 4]
</script>
</body>
</html>
find(函数限定条件)
用于找出第一个符合条件的数组成员,没有找到返回underfined
<!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>find(函数限定条件)</title>
</head>
<body>
<script>
var ary = [{
id: 1,
name: '张三'
}, {
id: 2,
name: '李四'
}, {
id: 3,
name: '王五'
}]
let target = ary.find(item => item.id == 2);
let target1 = ary.find(item => item.id == 4);
console.log(target); //{id: 2, name: '李四'}
console.log(target1); //undefined
</script>
</body>
</html>
findIndex(函数限定条件)
用于查找第一个符合条件的数组成员的位置,找不到返回-1
<!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>findIndex(函数限定条件)</title>
</head>
<body>
<script>
let arr = [10, 20, 50];
//返回满座()里面条件的数组元素索引
let index = arr.findIndex(item => item > 15);
console.log(index);
</script>
</body>
</html>
includes(查找的值)
检查数组是否包含给定的值,返回是布尔值
<!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>includes(查找的值)</title>
</head>
<body>
<script>
let arr = ['a', 'b', 'c'];
//查找()里面的元素有就返回true 没有返回false
let result = arr.includes('a');
let result1 = arr.includes('f');
console.log(result); //true
console.log(result1); //false
</script>
</body>
</html>
2.String的拓展方法
模板字符串
ES6新增的创建支付喜欢的方式,使用反引号定义。
特点:可以解析变量,可以换行,模板字符串可以调用函数
<!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>
</head>
<body>
<span></span>
<script>
//注意用的是 反引号` 使用的时候用${}取值
let name = `这是一个模板字符串`;
let sayHello = `Hello ${name}`;
console.log(sayHello);
//模板字符串可以换行
let result = {
name: "zhangsan",
age: 20
}
let html = `
<div>
<span>${result.age}</span>
<span>${result.name}</span>
</div>
`;
console.log(html);
//模板字符串可以调用函数
const fn = () => {
return '我是fn函数';
}
let html1 = `调用函数 ${fn()}`;
console.log(html1);
</script>
</body>
</html>
startsWith(‘字符串’)和endsWith(‘字符串’)
判断参数字符串是否在源字符串的头部/尾部,返回布尔值:满足true或者不满足false
<!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>startsWith('字符串')和endsWith('字符串')</title>
</head>
<body>
<script>
let str = 'hello ECMAScript 2015';
//中间传入字符串!
let flag = str.startsWith('hello');
let flag1 = str.endsWith('2015');
console.log(flag); //true
console.log(flag1); //true
</script>
</body>
</html>
repeat(n)
该方法表示把原字符串重复n次!
<!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>repeat(n)</title>
</head>
<body>
<script>
let str = "y".repeat(5);
console.log(str);
</script>
</body>
</html>
3.Set数据结构
ES6提供了新的数据结构Set 。类似于数组,成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。Set函数可以接受数组作为参数,用来初始化
<!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>Set数据结构</title>
</head>
<body>
<script>
const s1 = new Set();
//创建成功 s1.size长度是0
console.log(s1.size); //0
const s2 = new Set([1, 2, 3, 4]);
console.log(s2.size); //4
const s3 = new Set(["a", "a", "b", "b"]);
console.log(s3); //Set(2) {'a', 'b'} 会自动去掉重复的
const ary = [...s3]; //转换为数组!
console.log(ary); //(2) ['a', 'b']
</script>
</body>
</html>
Set常用实例方法
实例方法 | |
---|---|
add(value) | 添加某个值,返回Set结构本身 |
delete(value) | 删除某个值,返回一个布尔值,true成功 |
has(value) | 返回一个布尔值,表示该值是否为Set的成员 |
clear() | 清除所有成员,没有返回值 |
<!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>Set常用实例方法</title>
</head>
<body>
<script>
const s = new Set();
//先s中添加值 用add方法
s.add('a').add('b');
console.log(s); //Set(2) {'a', 'b'}
//删除set中的值 用delete方法
const f = s.delete('a');
console.log(f); //true删除成功
console.log(s); //Set(1) {'b'}
//检查元素是否在集合中
const f1 = s.has('a');
console.log(f1); //false a不是s中的成员
//清空set值
s.clear();
console.log(s.size); //0 清空完毕
</script>
</body>
</html>
Set的遍历
Set结构的实例和数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
dth, initial-scale=1.0">
repeat(n)
该方法表示把原字符串重复n次!
<!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>repeat(n)</title>
</head>
<body>
<script>
let str = "y".repeat(5);
console.log(str);
</script>
</body>
</html>
3.Set数据结构
ES6提供了新的数据结构Set 。类似于数组,成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。Set函数可以接受数组作为参数,用来初始化
<!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>Set数据结构</title>
</head>
<body>
<script>
const s1 = new Set();
//创建成功 s1.size长度是0
console.log(s1.size); //0
const s2 = new Set([1, 2, 3, 4]);
console.log(s2.size); //4
const s3 = new Set(["a", "a", "b", "b"]);
console.log(s3); //Set(2) {'a', 'b'} 会自动去掉重复的
const ary = [...s3]; //转换为数组!
console.log(ary); //(2) ['a', 'b']
</script>
</body>
</html>
Set常用实例方法
实例方法 | |
---|---|
add(value) | 添加某个值,返回Set结构本身 |
delete(value) | 删除某个值,返回一个布尔值,true成功 |
has(value) | 返回一个布尔值,表示该值是否为Set的成员 |
clear() | 清除所有成员,没有返回值 |
<!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>Set常用实例方法</title>
</head>
<body>
<script>
const s = new Set();
//先s中添加值 用add方法
s.add('a').add('b');
console.log(s); //Set(2) {'a', 'b'}
//删除set中的值 用delete方法
const f = s.delete('a');
console.log(f); //true删除成功
console.log(s); //Set(1) {'b'}
//检查元素是否在集合中
const f1 = s.has('a');
console.log(f1); //false a不是s中的成员
//清空set值
s.clear();
console.log(s.size); //0 清空完毕
</script>
</body>
</html>
Set的遍历
Set结构的实例和数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。