JavaScript面向对象编程

类与对象,继承,构造函数,原型,ES6语法,闭包等

1. 面向对象介绍

1.1. 面向对象OOP vs 面向过程POP

面向过程 preocess-oriented programming分析出解决问题的步骤,函数一步步实现,使用时一个个调用

面向对象 object-oriented programming 事务分解为对象,对象分工完成

把大象放进冰箱

面向过程:打开冰箱 -> 放入大象 -> 关闭冰箱

面向对象: 冰箱.打开,大象.进去,冰箱.关闭

面向对象特性:封装,继承,多态

1.2. 面向对象思维

面向对象更贴近实际生活,使用对象描述现实世界事物。

事物又分具体事物抽象事物。泛指的手机和特指的这个手机

故可以:

  1. 抽取共用的属性和行为封装成一个模板 —> 类
  2. 对类进行实例化,获取类的对象

1.3. 对象

万物皆对象

对象是一个具体的事物,看得见摸得着的实物。一本书,一支笔…

在JavaScript中,对象是一组无序的相关属性和方法的集合,所有事物都是对象。字符串,数值

对象由属性方法组成:

  • 属性:事物的特征,在对象中用属性来表示 - 名词
  • 方法:事物的行为,在对象中用方法来表示 - 动词

1.4. 类

ES6中,使用class关键字声明一个类

类是抽象了对象的公共部分,泛指某一大类

对象特指一个

类实例化一个具体的对象

1.5. 语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1.创建类
class Person{
// 构造器 无须调用
constructor(name){
this.uname = name;
}

// 方法
sing(some){
return this.uname+" sing "+some;
}

}
// 2.实例化
var user = new Person("John");
// 3.调用
// John sing 小星星
console.log(user.sing("小星星"));

2. 父类

调用父类方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Father{
say(){
return 'Father';
}
}

class Son extends Father{
say(){
return super.say()+"'s Son";
}
}

var user = new Son();
console.log(user.say());

3. this

类里面的共有属性和方法一定要加this

constructor里面的this指向实例对象,方法里面的this指向方法调用者

4. 案例:动态添加标签页

4.1. 源码

https://www.aliyundrive.com/s/LAXNHxbZAG6

4.2. html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!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>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/tab.css">
<script src="js/index.js"></script>
</head>
<body>
<main>
<h4>
Js 面向对象 动态添加标签页
</h4>
<div class="tabsbox" id="tab">
<!-- tab 标签 -->
<nav class="firstnav">
<ul>
<li class="liactive"><span>测试1</span><span class="iconfont icon-guanbi"></span></li>
<li><span>测试2</span><span class="iconfont icon-guanbi"></span></li>
<li><span>测试3</span><span class="iconfont icon-guanbi"></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>
</body>
</html>

4.3. css

tab.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
* {
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;
cursor: pointer;
}

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;
}

4.4. js

ondblclick - 双击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
window.addEventListener("load",function(){
// this
var obj;
var tab;
var nav;
var content;
// 测试1
var li;
// 内容 测试1
var section;
// 添加按钮
var tabadd;
class Tab{
constructor(id){
obj=this;
tab = document.querySelector(id);
nav = tab.querySelector(".firstnav ul");
content = tab.querySelector(".tabscon");
tabadd = tab.querySelector(".firstnav .tabadd");
this.init();
}

// 刷新组件
upload(){
li = nav.querySelectorAll("li");
section = content.querySelectorAll("section");
}

// 注册点击事件
init(){
this.upload();
var len = li.length;
for( var i = 0;i<len;i++){
li[i].onclick=this.toggle;
// li添加index属性
li[i].index = i;

//删除按钮
var removeBtn = li[i].querySelector(".iconfont");
// 按钮中添加索引
removeBtn.index=i;
removeBtn.onclick=this.removeTab;
// console.log(removeBtn.index);

// span内容
var span = li[i].querySelector("span");
span.ondblclick=this.editTab;

// section内容
section[i].ondblclick=this.editTab;
}
tabadd.onclick=this.addTab;
}

// 切换
toggle(){
// console.log(this.innerHTML);
var len = li.length;
// console.log(this);
for( var i = 0;i<len;i++){
li[i].className='';
section[i].className='';
}
// this - 调用者
this.className='liactive';
// 对应li中的索引号
section[this.index].className='conactive';
}

// 添加
addTab(){
var str = '<li class="liactive"><span>选项</span><span class="iconfont icon-guanbi"></span></li>';
// 'beforebegin':元素自身的前面。
// 'afterbegin':插入元素内部的第一个子节点之前。
// 'beforeend':插入元素内部的最后一个子节点之后。
// 'afterend':元素自身的后面。
nav.insertAdjacentHTML('beforeend',str);

str = '<section class="conactive">选项'+Math.random()+'</section>';
content.insertAdjacentHTML('beforeend',str);
// 重置绑定
obj.init();
// 默认最后项选中
li[li.length-1].click();
}

// 删除
removeTab(e){
// 阻止冒泡 - 父组件li的点击事件
e.stopPropagation();
var idx = this.index;
li[idx].remove();
section[idx].remove();
// 如果当前li点击事件的索引号和当前删除事件索引号不同,不进行以下操作
if(nav.querySelector(".liactive")){
return false;
}
idx--;
if(idx>=0){
li[idx].click();
}

// 重置绑定
obj.init();
}

// 修改
editTab(e){
// console.log(this);
// 取消双击选中文本
window.getSelection? window.getSelection().removeAllRanges():document.selection.empty();
var str = this.innerText;
// 添加输入框
this.innerHTML='<input type="text" value="">';
// 获取输入框
var input = this.querySelector("input");
// 放入原有标题
input.value = str;
// 文字处于选中状态
input.select();

// 按下回车键
input.onkeyup=function(e){
if(e.keyCode==13){
this.blur();
}
}

// 鼠标离开
input.onblur = function(){
this.parentNode.innerHTML=this.value;
}



}
}
new Tab("#tab");
});

5. 构造函数 ES5

ES6,全称ECMAScript6.0,2015.06发版。

浏览器JavaScript是ES5版本。高版本支持ES6,不过只实现其部分特性和功能

在ES6之前,对象基于构建函数来定义对象和它们的特征

5.1. 创建对象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.类实例化
var obj = new Object();

// 2.字面量
obj = {};

// 3.构造函数
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log(name+' '+age+' sing');
}
}
obj1 = new Star("John",18);
obj1.sing();

5.2. 静态成员

在构造函数上添加的成员,只能由构造函数本身访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log(name+' '+age+' sing');
}
}

Star.num=1;
obj1 = new Star("John",18);
//undefined
console.log(obj1.num);
//1
console.log(Star.num);

5.3. 实例成员

构造函数内部创建的对象成员,只能由实例化对象访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log(name+' '+age+' sing');
}
}

obj1 = new Star("John",18);

//18
console.log(obj1.age);
// undefined
console.log(Star.age);

5.4. 不同对象,不同内存

1
2
3
4
5
6
7
8
9
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log(name+' '+age+' sing');
}
}
//false
console.log(obj1.sing==obj2.sing);

5.5. 原型 prototype

构造函数通过原型分配的函数是所有对象所共享的

js规定,每一个构造函数都有一个prototype属性,指向另一个对象

prototype就是这个对象,对象中所有属性和方法,都会被构造函数拥有

console.dir(Star);

把不变的方法,直接定义在prototype对象上,实现实例共享

1
2
3
4
5
6
7
8
9
10
11
12
13
function Star(name,age){
this.name=name;
this.age=age;
}
Star.prototype.sing=function(){
console.log(name+' '+age+' sing');
}

obj1 = new Star("John",18);
obj2 = new Star("Amy",19);

//true
console.log(obj1.sing==obj2.sing);

5.6. 对象原型 _proto_

对象属性中都有一个_proto_指向构造函数的prototype原型对象

所以对象可以使用构造函数原型对象的属性和方法

  • _proto_prototype是等价的
  • _proto_存在的意义是为对象的查找机制提供一个方向,但是它是非标准属性,实际开发中,不可以使用这个属性

5.7. 构造函数 constructor

对象原型和构造函数原型对象里面都有一个属性constructor,称其为构造函数,它指回构造函数本身

手动指回constructor

1
2
3
4
5
6
7
8
9
Star.prototype={
constructor: Star,
sing: function(name){
console.log(name+' sing');
},
movie: function(){
console.log("movie");
}
};

5.8. 成员查找机制

  1. 访问一个对象的属性时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找原型,_proto_指向的prototype原型对象
  3. 如果还没有就查找原型对象的原型 Object
  4. 依次类推至null
  5. _proto_为对象成员查找机制提供一个方向

5.9. 利用原型对象扩展内置对象方法

原型对象this指向实例对象

可以把自定义方法写在原型对象中,调用方法

1
2
3
4
5
6
7
8
9
10
11
Array.prototype.sum = function(){
var sum = 0;
for (var i=0;i<this.length;i++) {
sum = this[i];
}
return sum;
}
var arr = new Array(11,22,33);
var ans = arr.sum();
console.log(ans);
console.log(Array.prototype);

5.10. 改变this指向

5.10.1. call(对象,参数1,参数2,...)

调用函数并且修改函数运行时的this指向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//call(对象,参数1,参数2,...);

function fn(a,b){
console.log(this);
console.log(a+b);
}
//Window {window: Window, self: Window, document: document, name: '', location: Location, …}
fn();

//Window {window: Window, self: Window, document: document, name: '', location: Location, …}
fn.call();

var obj = {name:'obj'};
//{name: 'obj'}
fn.call(obj,1,2);

5.10.2. apply(对象,[参数])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
thisArg - this值
[argsArray] - 传递的值,必须包含在数组里面
*/
fun.apply(thisArg,[argsArray]);

function Father(uname,age){
this.uname = uname;
this.age = age;
}

function Son(uname,age){
Father.apply(this,[uname,age]);
}

var son = new Son('John',18);
console.log(son);

应用:求数组最大值

1
2
3
var ans = Math.max.apply(Math,[1,2,0,5,3]);
//5
console.log(ans);

5.10.3. bind(对象,参数1,参数2,...)

方法不会调用函数,但能改变函数内部this指向

1
2
3
4
5
6
7
8
var o = {
name: 'John'
};
function fn(){
console.log(this);
}
var f = fn.bind(o);
f();

按钮

1
2
3
4
5
6
7
8
9
10
11
btn.addEventListener("click",function(){
// 按钮禁用
this.disabled=false;
// 3秒后恢复使用
setTimeout(function(){
// 原本this指向window
// 利用bind转换this指向
this.disabled=true;
// bind并不会直接调用,this指向btn
}.bind(this),3000);
})

5.11. 继承

构造函数+原型对象 模拟实现继承

5.11.1. 继承属性 - call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//借用父构造器继承属性
function Father(a,b){
// this指向父构造器对象实例
this.a=a;
this.b=b;
}
// 子构造函数
function Son(a,b){
// this指向子构造器函数对象实例
Father.call(this,a,b);
}

var obj = new Son(3,4);
console.log(obj);

5.11.2. 继承方法 - prototype

采用实例化父构造器对象 Son.prototype = new Father();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//借用父构造器继承属性
function Father(a,b){
// this指向父构造器对象实例
this.a=a;
this.b=b;
}
// 父构造器原型对象
Father.prototype.sum=function(){
console.log(this.a+this.b);
}
// 子构造函数
function Son(a,b){
// this指向子构造器函数对象实例
Father.call(this,a,b);
}
// 导致父子原型指向同一个对象,修改子原型会影响父原型
// Son.prototype = Father.prototype;
// 子原型指向父构造器实例,不影响父原型
// 但导致子原型的constructor指向父构造器
Son.prototype = new Father();
// 手动修改构造器指向
Son.prototype.constructor=Son;
var obj = new Son(3,4);
obj.sum();
console.log(new Father(5,6));
console.log(obj);

5.12. ES5新增方法

5.12.1. forEach()

forEach()中return并不会终止遍历

1
2
3
4
5
6
/*
currentValue - 值
index - 索引号
array - 数组本身
*/
array.forEach(function(currentValue,index,array));

js

1
2
3
4
5
6
var arr = [1,21,322,4311];
arr.forEach(function(value,idx,arr){
console.log("value "+value);
console.log("idx "+idx);
console.log("arr "+arr);
});

5.12.2. map()

5.12.3. filter()

创建一个新数组,新数组中的元素通过检查指定数组中符合条件所有元素,用于筛选数组

1
array.filter(function(currentValue,index,array));

js

1
2
3
4
5
6
7
8
var arr = [1,21,322,4311];
var arrNew = arr.filter(function(value,idx,arr){
return value>300;
});
// [1, 21, 322, 4311]
console.log(arr);
// [322, 4311]
console.log(arrNew);

5.12.4. some()

检测数组中的元素是否满足指定条件

返回值是布尔值,查找到该元素返回true,否则返回false

找到第一个满足条件的元素,终止循环,不再继续查找

1
array.some(function(currentValue,index,array));

js

1
2
3
4
5
6
var arr = [1,21,322,4311];
var flag = arr.some(function(value,idx,arr){
return value>300;
});
// true
console.log(flag);

5.12.5. every()

5.12.6. trim()

从字符串两端删除空白符

并不影响原字符串,返回新的字符串

5.12.7. keys()

获取对象自身所有属性

返回属性名组成的数组

1
Object.keys(obj)

js

1
2
3
4
5
6
7
8
var obj = {
name: 'A',
age: 18
}
var arr = Object.keys(obj);
arr.forEach(function(key){
console.log(obj[key]);
});

5.12.8. defineProperty()

定义对象中新属性或修改原有属性

1
2
3
4
5
6
/*
obj - 必需。目标对象
prop - 必需。定义或修改的属性名字
descriptor - 必需。目标属性所拥有的特性
*/
Object.defineProperty(obj.prop,descriptor);

descriptor以对象{}书写

  • value:设置属性值

    默认为undefined

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var obj = {
    name: 'A',
    age: 18
    }
    Object.defineProperty(obj,'name',{
    value: 'B'
    });
    // {name: 'B', age: 18}
    console.log(obj);
  • writable:值是否可以重写

    默认为false

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var obj = {
    name: 'A',
    age: 18
    }
    Object.defineProperty(obj,'name',{
    writable: false
    });
    obj.name='B';
    // {name: 'A', age: 18}
    console.log(obj);
  • enumerable:目标属性是否可以被遍历

    默认为false

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var obj = {
    name: 'A',
    age: 18
    }
    Object.defineProperty(obj,'num',{
    value: 01,
    enumerable: false
    });
    // {name: 'A', age: 18}
    console.log(obj);
  • configurable:目标属性是否可以被删除或可以再次修改目标属性

    默认为false

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var obj = {
    name: 'A',
    age: 18
    };
    Object.defineProperty(obj,'age',{
    // 可以被删除或再修改第三个参数
    configurable: true
    });

    delete obj.age;
    //{name: 'A'}
    console.log(obj);

6. 函数

6.1. 函数定义方式

1
2
3
4
5
6
7
8
9
10
11
// 1.自定义函数
function fn(){}
fn();

// 2. 函数表达式 - 匿名函数
var fun = function(){}
fun();

// 3. 利用new Function('参数1','参数2','函数体')
var func = new Function('a','b','console.log(a+b)');
func(1,2);

所有函数都是Function的实例

函数也属于对象

6.2. 函数调用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 1.普通函数
function fn(){}
// 调用
fn();
fn.call();

// 2. 对象的方法
var obj = {
say: function(){

}
}
// 调用
obj.say();

// 3. 构造函数
function Star(){

}
// 调用
new Star();

// 4.绑定事件函数
window.onclick=function(){

}
// 调用
window.click();

// 5.定时器函数
var timer = setInterval(function(){},1000);

// 立即执行函数
(function(){})();

6.3. 函数内部this指向

调用方式 this指向
普通函数 window
构造函数 实例对象,原型对象里面的方法也指向实例对象
对象方法 该方法所属对象
事件绑定方法 绑定事件对象
定时器函数 window
立即执行函数 window

7. 严格模式

JavaScript除了提供正常模式外,还提供严格模式。

ES5的严格模式是采用具有限制性

在IE10以上才会被支持

严格模式对正常的JavaScript语义做出的更改:

  1. 变量必须声明后使用

  2. 严禁删除已声明的变量

  3. 全局作用域中函数的this是undefined

  4. 构造函数不加new调用,this会报错

  5. new实例化的构造函数指向创建的对象实例

  6. 定时器中的this还是指向window

  7. 函数参数不可能重名

  8. 禁用ECMAScript的未来版本中可能会定义的一些语法,为未来版本的JavaScript做好铺垫。

    保留了class,enum,export,extends,import,super等保留字

严格模式可以应用到整个脚本或个别函数时中。因此使用时,将严格模式分为为脚本开启严格模式为函数开启严格模式两者情况。

7.1. 为脚本开启严格模式

在所有语句之前放一个特定语句use strict

1
2
3
4
5
6
7
8
9
10
11
<script>
'use strict';
</script>

<!-- 或者 -->

<script>
(function(){
'use script';
})();
</script>

7.2. 为函数开启严格模式

1
2
3
4
5
6
7
8
9
10
11
<script>
//开启严格模式
function fn(){
'use script';
}

//依然按照普通模式
function fn2(){

}
</script>

8. 高阶函数

对其他函数进行操作的函数,接收函数作为参数或者将函数作为返回值输出

1
2
3
4
5
6
function fn(callback){
callback&&callback();
}
fn(function(){
alert('hi');
});

9. 闭包

有权访问另一个函数作用域中变量的函数

一个作用域可以访问另一个函数内部的局部变量,这个局部变量所在的函数称为闭包

延长了变量的作用范围

1
2
3
4
5
6
7
8
9
10
11
12
13
// fn - 闭包
function fn(){
var num = 10;

function fun(){
console.log(num);
}

return fun;
}

var f = fn();
f();

10. 正则表达式

用于匹配字符串中字符组合的模式。

在JavaScript中也是对象

通常被用来检索,替换那些符合某个模式的文本:

  1. 验证表单(匹配)
  2. 过滤页面内容中的一些敏感词(替换)
  3. 从字符串中获取特定部分(提取)

10.1. 创建正则表达式

  1. 通过RegExp对象的构造函数创建

    1
    var 变量名 = new RegExp(/表达式/);
  2. 通过字面量创建

    1
    var 变量名 = /表达式/;   

js

1
2
3
var rg = /123/;
//true
rg.test(123);

10.2. 字符类

只要匹配其中一个就可以

1
2
3
4
5
6
var rg = /[abc]/;

//true
rg.test('andy');
//false
rg.test('dy');

三选一:只有是a或者b或者c才返回true

1
2
3
4
var rg = /^[abc]$/;

//false
rg.test('aa');

26个英文字母任何一个字符:-表示范围

1
var rg= /^[a-z]$/;

字母+数字

1
var rg= /^[a-zA-Z0-9]$/;

取反:不可以是字母或数字

1
var rg= /^[^a-zA-Z0-9]$/;

10.3. 量词

量词 说明 用法
* 重复零次或更多次 /^a*$/
+ 重复一次或更多次 /^a+$/
? 重复零或一次 /^a?$/
{n} 重复n次 /^a{3}$/
{n,} 重复n次或更多次 /^a{3,}$/
{n,m} 重复n到m次 /^a{3,6}$/

10.4. 替换

1
2
var rg= /^[激情|感觉]$/;
rg.replace(rg,'**');

11. let

ES6新增的用于声明变量的关键字

  1. let声明的变量只在所处于的块级有效

  2. 不存在变量提升

    1
    2
    3
    4
    5
    if(true){
    //num is not defined
    console.log(num);
    let num = 5;
    }
  3. 声明的关键字具有暂时性死区,一旦在块级作用域使用let定义变量,这个变量就和块级进行了绑定,在当前这个区域使用变量必须先定义

    1
    2
    3
    4
    5
    6
    var num = 10;
    if(true){
    //num is not defined
    console.log(num);
    let num = 5;
    }

12. const

声明常量,值定义后不能更改

声明的常量具有块级作用域

13. 解构赋值

按照一定模式,从数组中或对象中提取值,将提取出来的值赋值给另外的变量

1
2
3
4
let [a,b,c]=[1,2,3];
console.log(a);
console.log(b);
console.log(c);

对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let person = 
{
name: 'A',
age: 18
};
// 同一变量名
let {name,age }=person;
console.log(name);
console.log(age);


// 别名
let {name:myName,age:myAge }=person;
console.log(myName);
console.log(myAge);

14. 箭头函数

箭头函数不绑定this

箭头函数没有自己的this关键字

如果在箭头函数中使用this,this关键字将指向箭头函数定义位置的this

1
2
3
4
5
6
7
8
9
10
11
12
function fn(){
//this指向obj
console.log(this);
return ()=>{
//this指向obj
console.log(this);
}
}

const obj = {name: 'zhangsan'};
var refun = fn.call(obj);
refun();

面试题

this关键字将指向箭头函数定义位置,对象没有作用域,故this指向全局作用域,window,而window中没有age,打印undefined

1
2
3
4
5
6
7
8
var obj = {
age: 20,
say: ()={
alert(this.age);
}
}

obj.say();
本文结束  感谢您的阅读