javascript-高级进阶篇(1)

5/28/2020

js高级

# 一、面向对象

  1. 通过class 关键字创建类 类名 我们还是习惯性定义首字母大写
  2. 类里面有个 constructor 函数 可以接受传递过来的参数 同时返回实例对象
  3. constructor 函数 只要 new 生实例时 就会自动调用这个函数 如果我们不写这个函数 类也会自动生成这个函数
  4. 生成实例 new 不能省略
  5. 最后注意语法规范 创建类 类名后面不要加小括号 生成实例 类名后面加小括号 构造函数不需要加 function
1.创建类和生成实例

<!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>1.创建类和生成实例</title>
</head>
<body>
    <script type="text/javascript">
        class Start{
            constructor(name,age,year){
                this.name=name;
                this.age=age;
                this.year=year;
            }
        }
 
        var zy = new Start('昭阳公主','25','750');
        var jdl = new Start('金多禄','30','750');
 
        console.log(zy.age);
        console.log(jdl.name);
    </script>
</body>
</html>

2.类中添加共有方法
(1) 类的公有属性放到 constructor 里面

(2) 多个函数方法之间不需要添加逗号分隔

<!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>2.类中添加共有方法</title>
</head>
<body>
    <script type="text/javascript">
        class Start{
            constructor(name,age,year){
                this.name=name;
                this.age=age;
                this.year=year;
            }
            sing(song){
                console.log(this.name +"唱"+ song);
            }
        }
 
        var zy = new Start('昭阳公主','25','750');
        var jdl = new Start('金多禄','30','750');
 
        console.log(zy.age);
        console.log(jdl.name);
        zy.sing('皆大')
        jdl.sing('欢喜')
    </script>
</body>
</html>
 3.类继承extends和super关键字
extends:继承

super:调用了父类中的构造函数(传值到父类中使用父类的方法)

<!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>3.类继承extends和super关键字</title>
</head>
<body>
    <script type="text/javascript">
        // class Father{
        //     constructor(){
                
        //     }
        //     money(){
        //         console.log(100);
        //     }
        // }
        // class Son extends Father{
 
        // }
        // var son = new Son();
        // son.money();
 
        class Father{
            constructor(x,y){
                this.x = x;
                this.y = y;
            }
            sum(){
                console.log(this.x + this.y);
            }
        }
        class Son extends Father{
            constructor(x,y){
                super(x,y);//调用了父类中的构造函数
            }
        }
        var son = new Son(22,54);
        son.sum();
    </script>
</body>
</html>
4.super调用父类普通函数以及继承中属性方法查找原则

继承中的属性或者方法查找原则:就近原则
1. 继承中,如果实例化子类输出一个方法 先看子类有没有这个方法 如果有就先执行子类的
2. 继承中,如果子类里面没有 就去查找父类有没有这个方法 如果有 就执行父类的这个方法(就近原则)

<!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>4.super调用父类普通函数以及继承中属性方法查找原则</title>
</head>
<body>
    <script type="text/javascript">
        class Father{
            say(){
                return "我是粑粑";
            }
        }
        class Son extends Father{
            say(){
                console.log(super.say() + "的儿子");
                //super.say()就是调用父类中的普通函数 say()
            }
        }
        var son = new Son();
        son.say();
    </script>
</body>
</html>
5.super必须放到子类this之前

子类在构造函数中使用super, 必须放到 this 前面 (必须先调用父类的构造方法,在使用子类构造方法)

 subtract():减法操作

<!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>5.super必须放到子类this之前</title>
</head>
<body>
    <script type="text/javascript">
        class Father{
            constructor(x,y){
                this.x = x;
                this.y = y;
            }
            add(){
                console.log(this.x + this.y);
            }
        }
 
        //子类继承父类加法方法 同时扩展减法方法
        class Son extends Father{
            constructor(x,y){
                //利用super调用父类的构造函数
                //super必须在子类this之前调用
                super(x,y);
                this.x = x;
                this.y = y;
            }
            subtract(){
                console.log(this.x - this.y);
            }
        }
 
        var son = new Son(98,5);
        son.add();
        son.subtract();
    </script>
</body>
</html>
6.使用类2个注意点
1. 在 ES 6 中类没有变量提升 所以必须先定义类 才能通过实例化对象
2. 类里面的共有的属性和方法一定要加this使用
3. constructor 里面的this指向实例对象 方法里面的this指向这个方法的调用者

<!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>6.使用类2个注意点</title>
</head>
<body>
    <button>点击</button>
    <script type="text/javascript">
        var that;
        var _that;
        class Star{
            constructor(uname,age){
                this.uname = uname;
                this.age = age;
                // this.sing();
                this.btn = document.querySelector('button');
                this.btn.onclick = this.sing;
                console.log(this);
                that = this;
            }
            sing(){
                //这个sing方法里面的this指向的是btn这个按钮,因为这个按钮调用了这个函数
                console.log(this);
                console.log(that.uname);//that里面存储的是constructor里面的this
            }
            dance(){
                //这个_that里面的this 指向的是实例对象 ldh 因为 ldh 调用了这个函数
                _that = this;
                console.log(this);
            }
        }
        var ldh = new Star('离歌笑',20);
        console.log(that === ldh);
        ldh.dance();
        console.log(_that === ldh);
    // 1. 在 ES 6 中类没有变量提升 所以必须先定义类 才能通过实例化对象
    // 2. 类里面的共有的属性和方法一定要加this使用
    // 3. constructor 里面的this指向实例对象 方法里面的this指向这个方法的调用者
    </script>
</body>
</html>
7.面向对象tab栏

init():初始化操作让相关的元素绑定事件

insertAdjacentHTML() :将指定的文本解析为HTML或XML,并将结果节点插入到DOM树中的指定位置。

position是相对于元素的位置,并且必须是以下字符串之一:

beforebegin: 元素自身的前面。
afterbegin: 插入元素内部的第一个子节点之前。
beforeend: 插入元素内部的最后一个子节点之后。
afterend: 元素自身的后面。
text是要被解析为HTML或XML,并插入到DOM树中的字符串。
 select():文本框的文字处于选定状态

 this.blur()/this.click()直接调用事件

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.fsection = this.main.querySelector('.tabscon');
        this.init();
    }
    init(){
        this.updateNode();
        //init初始化操作让相关的元素绑定事件
        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.spans[i].ondblclick = this.editTab;
            this.sections[i].ondblclick = this.editTab;
        }
        this.add.onclick = this.addTab;
    }
    //获取所有的小li和section
    updateNode(){
        this.lis = document.querySelectorAll('li');
        this.sections = document.querySelectorAll('section');
        //全部的关闭按钮
        this.remove = this.main.querySelectorAll('.icon-guanbi');
        this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child');
    }
    //1.切换功能
    toggleTab(){
        // console.log(this.index);
        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 = '';
        }
    } 
    getRandom(min,max)
    {
        return Math.floor(Math.random()*(max-min+1))+min;
    } 
    //2.添加功能
    addTab(){
        //方法1
        // var li = document.createElement('li');
        // li.innerText = 'AA';
        // that.ul.appendChild(li);
        that.clearClass();
        var randoms = that.getRandom(1,100);
        //方法2
        //(1)创建li元素和section元素
        // console.log(that.lis.length);
        var li = '<li class="liactive"><span>测试'+randoms+'</span><span class="iconfont icon-guanbi"></span></li>';
        var section = '<section class="conactive">测试'+randoms+'</section>';
        //(2)把这两个元素追加到相应的父元素里面
        that.ul.insertAdjacentHTML('beforeend', li);
        that.fsection.insertAdjacentHTML('beforeend',section);
        that.init();
        
    }
    //3.删除功能
    removeTab(e){
        //阻止冒泡,防止触发li的切换点击事件
        e.stopPropagation();
        var index = this.parentNode.index;
        that.lis[index].remove();
        that.sections[index].remove();
        //当我们删除了选中状态的这个li的时候,让它的前一个li处于选定状态
        if(document.querySelector('iactive')) return;
        index --;
        //手动调用我们的点击事件 不需要鼠标触发
        that.lis[index] && that.lis[index].click();
        that.init();
    }
    //4.修改功能
    editTab(){
        var str = this.innerHTML;
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        // this.innerHTML='<input type="text" value='+str+'>';
        this.innerHTML='<input type="text">';
        var input = this.children[0];
        input.value = str;
        input.select();//文本框的文字处于选定状态
        //当我们离开文本框就把文本框里面的值给span
        input.onblur = function(){//onblur:失去焦点 onfocus:获得焦点
            this.parentNode.innerHTML = this.value;
        }
        // (1)keyup 松开时触发
        // (2)keydown 按下时触发
        // (3)keypress 按下时触发 不能识别功能键 比如 ctrl shift 左右箭头
        input.onkeyup = function(e){
            if(e.keyCode === 13)
            {
                //手动调用表单失去焦点事件 不需要鼠标离开操作
                this.blur();
            }
        }
    }
}
new Tab("#tab");
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

# 二、构造函数和原型

1.利用构造函数创建对象
<!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>1.利用构造函数创建对象</title>
</head>
<body>
    <script type="text/javascript">
    //1.利用new Object()创建对象
    var obj1 = new Object();
    //2.利用对象字面量创建对象
    var obj2 = {};
    //3.利用构造函数创建对象
    function Star(name,age){
        this.name = name;
        this.age = age;
        this.sing = function(song){
            console.log(song);
        }
    }
    var ldh = new Star('刘德华',18);
    var zxy = new Star('张学友',20);
    ldh.sing('冰雨');
    ldh.sing('练习');
    console.log(ldh.name);
    </script>
</body>
</html>

2.实例成员和静态成员
构造函数中的属性和方法我们称为成员,成员可以添加

实例成员就是构造函数内部通过this添加的成员 name age sing 就是实例成员

实例成员只能通过实例化的对象来访问

静态成员 在构造函数本身上添加的成员 sex就是静态成员

静态成员只能通过构造函数来访问

<!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>1.2.实例成员和静态成员</title>
</head>
<body>
    <script type="text/javascript">
    //构造函数中的属性和方法我们称为成员,成员可以添加
    function Star(name,age){
        this.name = name;
        this.age = age;
        this.sing = function(song='xx'){
            console.log(song);
        }
    }
    var ldh = new Star('刘德华',18);
    //实例成员就是构造函数内部通过this添加的成员 name age sing 就是实例成员
    //实例成员只能通过实例化的对象来访问
    console.log(ldh.name);
    ldh.sing();
    console.log(Star.age);//不可以通过构造函数来访问实例对象
    //2.静态成员 在构造函数本身上添加的成员 sex就是静态成员
    Star.sex='男';
    console.log(Star.sex);
    //2.静态成员只能通过构造函数来访问
    console.log(ldh.sex);
    </script>
</body>
</html>

3.构造函数原型对象prototype
一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上

构造函数通过原型分配的函数是所有对象所共享的
JavaScript规定 每个构造函数都有一个 prototype属性 指向另一个对象。注意这个prototype 就是一个对象 这个对象的所有属性和方法 都会被构造函数所拥有。
我们可以把那些不变的方法 直接定义在prototype 对象上 这样所有对象的实例就可以共享这些方法。
原型就是一个对象,我们也称为prototype为对象
原型的作用就是 共享方法。

<!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>3.构造函数原型对象prototype</title>
</head>
<body>
    <script type="text/javascript">
    function Star(name,age){
        this.name = name;
        this.age = age;
        // this.sing = function(song='xx'){
        //     console.log(song);
        // }
    }
    Star.prototype.sing = function(){
        console.log('不如跳舞');
    }
    var ldh = new Star('刘德华',18);
    var zxy = new Star('张学友',20);
    console.log(ldh.sing===zxy.sing);
    console.dir(Star);
    ldh.sing();
    zxy.sing();
    //2.一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上
    </script>
</body>
</html>

4.对象原型__proto__
对象都会有一个属性 __ proto __ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __ proto __ 原型的存在。
__ proto __ 对象原型和原型对象 prototype 是等价的
__ proto __ 对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是他是一个非标准,因此在实际开发中,不可以使用这个属性,他只是内部向原型对象 prototype。
__ proto __ 对象原型
prototype 原型对象

<!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>4.对象原型__proto__</title>
</head>
<body>
    <script type="text/javascript">
    function Star(name,age){
        this.name = name;
        this.age = age;
    }
    Star.prototype.sing = function(){
        console.log('不如跳舞');
    }  
    var ldh = new Star('刘德华',18);
    var zxy = new Star('张学友',20);
    ldh.sing();//对象身上系统自己添加一个__proto__指向我们构造函数的原型对象
    // console.dir(ldh);
    // console.dir(Star);
    console.log(ldh.__proto__===Star.prototype);
    //方法的查找规则,首先先看ldh对象身上是否有sing方法,如果有就执行这个对象上的sing
    //如果没有sing这个方法,因为有__proto__的存在,就去构造函数原型对象prototype身上去查找sing这个方法
    </script>
</body>
</html>

5.原型constructor构造函数
对象原型(__ proto __)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为他指向会构造函数本身。
constructor 主要用于记录该对象引用那个构造函数,它可以让原型对象重新指向原来的构造函数

如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数

<!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>5.原型constructor构造函数</title>
</head>
<body>
    <script type="text/javascript">
    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('刘德华',18);
    var zxy = new Star('张学友',20);
    console.log(Star.prototype);
    console.log(ldh.__proto__);
    // console.log(Star);
    // console.log(ldh);
    console.log(Star.prototype.constructor);
    console.log(ldh.__proto__.constructor);
    </script>
</body>
</html>

6.构造函数实例和原型对象的三角关系


7.原型链


<!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>7.原型链</title>
</head>
<body>
    <script type="text/javascript">
    function Star(name,age){
        this.name = name;
        this.age = age;
    }
    Star.prototype.sing = function(){
        console.log('不如跳舞');
    }  
    var ldh = new Star('刘德华',18);
    //1.只要是对象就有__proto__原型,指向原型对象
    console.log(Star.prototype);
    //2.我们Star原型对象里面的__proto__原型指向的是 Object.prototype
    console.log(Star.prototype.__proto__ === Object.prototype);
    //3.我们Object。prototype原型对象里面的__proto__原型 指向为null
    console.log(Object.prototype.__proto__);//null
    </script>
</body>
</html>

8.对象成员查找规则
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
如果没有就查找它的原型(也就是__ proto __指向的prototype原型对象)。
如果还没有就查找原型对象的原型(Object的原型对象)。
以此类推一直找到Object为止(null)
__ proto __ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

<!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>8.对象成员查找规则</title>
</head>
<body>
    <script type="text/javascript">
    function Star(name,age){
        this.name = name;
        this.age = age;
    }
    Star.prototype.sing = function(){
        console.log('不如跳舞');
    }  
    Star.prototype.sex = 'Girl';
    // Object.prototype.sex = 'BOY';
    var ldh = new Star('刘德华',18);
    ldh.sex = 'Boy';
    // console.log(ldh.sex);
    console.log(Star.prototype);
    console.log(ldh);
    console.log(Object.prototype);
    console.log(ldh.toString());
    </script>
</body>
</html>

9.原型对象this指向
谁调用指向谁

<!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>9.原型对象this指向</title>
</head>
<body>
    <script type="text/javascript">
    var that;
    function Star(name,age){
        this.name = name;
        this.age = age;
    }
    Star.prototype.sing = function(){
        that = this;
        console.log('不如跳舞');
    }  
    var ldh = new Star('刘德华',18);
    //1.在构造函数中,里面this指向的是对象实例 ldh
    ldh.sing();
    //2.原型对象函数里面的this指向的是实例对象 ldh
    console.log(ldh===that);
    </script>
</body>
</html>

10.利用原型对象扩展内置对象方法
可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给对象增加自定义求偶数和的功能。
注意:数组和字符内置对象不能给原型对象覆盖操作 Array.prototype = {} , 只能是 Array.prototype.xxx = function(){}的方法。

<!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>10.利用原型对象扩展内置对象方法</title>
</head>
<body>
    <script>
    //原型对象的应用 扩展内置对象方法
    Array.prototype.sum = function(){
        var sum = 0;
        for(var i=0;i<this.length;i++)
        {
            sum+=this[i];
        }
        return sum;
    }
    //不可用,覆盖掉了原来内置对象的方法
    // Array.prototype = {
    //     sum:function(){
    //         var sum = 0;
    //         for(var i=0;i<this.length;i++)
    //         {
    //             sum+=this[i];
    //         }
    //         return sum;
    //     }
    // }
    var arr = [1,2,3,40];
    console.log(arr.sum());
    console.log(Array.prototype);    
    var arr1 = new Array(11,22,3);
    console.log(arr1.sum());
    </script>
</body>
</html>

11.call方法的作用
调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg, arg1, arg2, ...)
thisArg : 当前调用函数的this的指向对象
arg1, arg2 : 传递的其他参数

<!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>11.call方法的作用</title>
</head>
<body>
    <script type="text/javascript">
        //call方法
        function fn(x,y){
            console.log('我想喝手磨咖啡');
            console.log(this);
            console.log(x+y);
        }
        var o = {
            uname :'angle',
        }
        // fn();
        //1.call() 可以调用函数
        // fn.call();
        //2.call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
        fn.call(o,1,20);
    </script>
</body>
</html>

12.利用父构造函数继承属性/方法
ES 6之前并没有给我们提供extends继承 我们可以通过构造函数+原型对象模拟实训继承,被称为组合继承

核心原理:通过call() 把父类型的this 指向子类型的this , 这样就可以实现子类型继承父类型的属性。

<!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>12.利用父构造函数继承属性、方法</title>
</head>
<body>
    <script>
        //借用父构造函数继承属性
        //1.父构造函数
        function Father(uname,age){
            //this 指向父构造函数的对象示例
            this.uname = uname;
            this.age = age;
        }   
        Father.prototype.money = function(){
            console.log(100000);
        }
        //2.子构造函数
        function Son(uname,age,score)
        {
            //this 指向子构造函数的对象示例
            Father.call(this,uname,age);
            this.score = score;
        }
        //借用父构造函数继承方法
        // Son.prototype = Father.prototype; //这样直接复制会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
        Son.prototype = new Father();
        //如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的原型对象
        Son.prototype.constructor = Son;
        //这个是子构造函数专门的方法
        Son.prototype.exam = function(){
            console.log("孩子要考试");
        }
        var son = new Son('Ss',28,120);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);
    </script>
</body>
</html>

13.类的本质
class本质还是function
类的所有方法都定义在类的prototype属性上
类创建的实例,里面也有__ proto __指向类的prototype原型对象
所以ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语言而已。
所以ES6的类其实就是语法糖。
语法糖:语法糖就是一种便捷写法,简单理解,有两种方法可以实现同样的功能,但是一种写法更加清晰、方便,那么这个方法就是语法糖。

<!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>13.类的本质</title>
</head>
<body>
    <script>
        // ES6 之前通过 构造函数+ 原型实现面向对象 编程
        // (1) 构造函数有原型对象prototype 
        // (2) 构造函数原型对象prototype 里面有constructor 指向构造函数本身
        // (3) 构造函数可以通过原型对象添加方法
        // (4) 构造函数创建的实例对象有__proto__ 原型指向 构造函数的原型对象
        // ES6 通过 类 实现面向对象编程 
        class Star{}
        console.log(typeof Star);
        //1.类的本质其实还是一个函数 我们也可以简单的认为 类就是 构造函数的另外一种写法
        //(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.dir(ldh);
        console.log(ldh.__proto__);
        // (4) 类创建的实例对象有__proto__ 原型指向 类的原型对象
        console.log(ldh.__proto__ === Star.prototype);
    </script>
</body>
</html>
 数组方法

迭(die)代(遍历)方法:forEach()、map()、filter()、 some()、every()

14.迭代(遍历数组)forEach
array.forEach(function(currentValue, index, arr))

currentValue : 数组当前项的值
index :数组当前项的索引
arr : 数组对象本身
<!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>14.迭代(遍历数组)forEach</title>
</head>
<body>
    <script>
        //forEach迭代(遍历)数组
        var arr = [1,25,20];
        var sum = 0;
        arr.forEach(function(value,index,array){
            console.log('每个数组元素',value);
            console.log('每个数组元素的索引号',index);
            console.log('数组本身',array);
            // sum = value+sum;
            sum += value;
        })  
        console.log(sum);  
    </script>
</body>
</html>

15.筛选数组filter方法
array.filter(function(currentValue, index, arr))

    filter() 方法创建一个新的数组,新数组中的元素时通过检查指定数组中符合条件的所有元素,主要用于筛选数组
    注意它直接返回一个新数组
    currentValue : 数组当前项的值
    index :数组当前项的索引
    arr : 数组对象本身

<!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>15.筛选数组filter方法</title>
</head>
<body>
    <script>
    //filter筛选数组(过滤器)
    var arr = [12,66,103,4,88,3,7];
    var newArr = arr.filter(function(value,index){
        // return value >=20;
        return value % 2 === 0; 
    })
    console.log(newArr);
    </script>
</body>
</html>

16.查找数组中是否有满足条件的元素some方法
array.some(function(currentValue, index, arr))

    some() 方法用于检测数组中的元素是否满足指定条件 通俗点 查找数组中是否有满足条件的元素
    注意它返回值是布尔值,如果查找到这个元素,就返回true,如果查找不到就返回false
    如果找到第一个满足条件的元素,则终止循环,不在继续查找
    currentValue : 数组当前项的值
    index :数组当前项的索引
    arr : 数组对象本身

<!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>16.查找数组中是否有满足条件的元素some方法</title>
</head>
<body>
    <script>
    //filter筛选数组(过滤器)
    var arr = [10,30,4];
    var flag = arr.some(function(value,index){
        // return value >= 20;
        return value <  2;
    })
    console.log(flag);
 
    var arr1 = ['red','blue','purper'];
    var color = arr1.some(function(value){
        return value == 'blue';
    })
    console.log(color);
    </script>
</body>
</html>
1. filter 也是查找满足条件的元素 返回的是一个数组 而且是把所有满足条件的元素返回回来

2. some 也是查找满足条件的元素是否存在 返回的是一个布尔值 如果查找到第一个满足条件的元素就终止循环

 map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

map() 方法按照原始数组元素顺序依次处理元素。

注意: map() 不会对空数组进行检测。

注意: map() 不会改变原始数组。

    var numbers = [4, 9, 16, 25];
    var x = numbers.map(x=>x * 2);
    console.log(x);

17.查询商品案例
<!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>17.查询商品案例</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,
           name:'小米',
           price:3999,
       },
       {
           id:2,
           name:'荣耀',
           price:2999,
       },
       {
           id:3,
           name:'vivo',
           price:1999,
       },
       {
           id:4,
           name:'魅族',
           price:999,
       },
    //    {
    //        id:5,
    //        name:'魅族',
    //        price:999,
    //    }
    ]
    // 1. 获取相应的元素
    var tbody = 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');
    // 2. 把数据渲染到页面中
    setDate(data);
    function setDate(data){
        //先清空原来tbody的数据
        tbody.innerHTML = '';
        data.forEach(function(value){
            var tr = document.createElement('tr');
            tr.innerHTML = '<td>'+value.id+'</td><td>'+value.name+'</td><td>'+value.price+'</td>';
            tbody.appendChild(tr);
        })
    }
 
    //3.根据价格查询商品
    //当我们点击了按钮,就可以根据我们的商品价格去筛选数组里面的对象
    search_price.addEventListener('click',function(){
        var newData = data.filter(function(value){
            return value.price >= start.value && value.price<=end.value;
        })
        //把筛选完之后的对象渲染到页面中
        setDate(newData);
    })
 
 
    // 4. 根据商品名称查找商品
    // 如果查询数组中唯一的元素, 用some方法更合适,因为它找到这个元素,就不在进行循环,效率更高
    search_pro.addEventListener('click',function(){
        var arr =[];
        data.some(function(value){
            if(value.name === product.value)
            {
                arr.push(value);
                return true; // return 后面必须写true  返回true就终止循环,不再查找
            }
        })
        // 把拿到的数据渲染到页面中
        setDate(arr);
    })
 
    //查询多个/模糊查询
    // search_pro.addEventListener('click',function(){
    //     var newData = data.filter(function(value){
    //         // return value.name == product.value;
    //         if(value.name.indexOf(product.value) !=-1)//模糊查询
    //         {
    //             return true;
    //         }
    //     })
    //     setDate(newData);
    // })
    </script>
</body>
 
</html>

18.some和forEach区别
如果是查询数组中唯一的元素 用some方法更合适

<!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>18.some和forEach区别</title>
</head>
<body>
    <script>
    var arr =['red','green','blue','pink','purper'];
    //1.forEach迭代 遍历
    // arr.forEach(function(value){
    //     if(value =='green')
    //     {
    //         console.log('找到了该元素');
    //         return true;//在 forEach 里面return 不会终止迭代
    //     }
    //     console.log(11);
    // })
 
    //some 如果是查询数组中唯一的元素 用some方法更合适
    // arr.some(function(value){
    //     if(value ==='green')
    //     { 
    //         console.log('找到了该元素');//在some里面 遇到 return true 就是终止遍历 迭代效率更高
    //         return true;
    //     }
    //     console.log(22);
    // })
 
    //filter
    arr.filter(function(value){
        if(value ==='green')
        { 
            console.log('找到了该元素');
            return true;//filter 里面return 不会终止迭代
        }
        console.log(22);
    })
    </script>
</body>
</html>

19.trim方法去除字符串两侧空格
​ str.trim()

trim() 方法会从一个字符串的两端删除空白字符
rim() 方法并不影响原字符本身,他返回的是一个新的字符串
<!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>19.trim方法去除字符串两侧空格</title>
</head>
<body>
    <input type="text"/>
    <button>点击</button>
    <div></div>
    <script>
        //trim 方法去除字符串两侧空格
        var str = '  an  dy  ';
        console.log(str);
        var str1 = str.trim();
        console.log(str1);
        var input = document.querySelector('input');
        var button = document.querySelector('button');
        var div = document.querySelector('div');
        button.onclick = function(){
            var str = input.value.trim();
            if(str=='')
            {
                alert('请输入内容');
            }
            else{
                div.innerHTML = str;
                console.log(str);
                console.log(str.length);
            }
        }
    </script>
</body>
</html>

20.Object.keys遍历对象属性
Object.keys 用于获取对象自身所有的属性(属性名)

<!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>20.Object.keys遍历对象属性</title>
</head>
<body>
    <script>
        //用于获取对象自身所有的属性(属性名)
        var obj = {
            id:1,
            name:'小米',
            price:1999
        }
        var arr  =  Object.keys(obj);//获取属性名
        console.log(arr);
        // obj.num = 1000;
        arr.forEach(function(value){
            console.log(value);
        })
    </script>
</body>
</html>

21.Object.defineProperty方法
Object.defineproperty(obj, prop, descriptor)

Object.defineproperty() 定义对象中新属性或修改原有的属性
* obj: 必需,目标对象
* prop:必需,需定义或修改的属性的名字
* descriptor: 必需,目标属性所拥有的特性

 Object.defineproperty() 第三个参数 descriptor 说明:以对象形式{}书写
* value: 设置属性的值 默认为undefined
* writable: 值是否可以重写。true|false 默认为false
* enumerable: 目标属性是否可以被枚举。true|false 默认为false
* configurable: 目标属性是否可以被删除或是否可以再次修改特特性 true|false 默认为false

<!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>21.Object.defineProperty方法</title>
</head>
<body>
    <script>
        //Obj.defineProperty() 定义新属性或修改原有的属性
        var obj = {
            id:1,
            name:'小米',
            price:1999
        };
        //1.以前的对象添加和修改属性的方法
        // obj.num = 1000;
        // console.log(obj);
        //2.Obj.defineProperty() 定义属性或修改原有的属性
        Object.defineProperty(obj,'num',{
            value :20,
            enumerable:true,
        });
        Object.defineProperty(obj,'price',{
            value :9.6,
        });
        console.log(obj);
        Object.defineProperty(obj,'id',{
            //如果值为false 不允许修改这个属性值 默认值也是false
            writable:false,
        })
        obj.id = 20;
        Object.defineProperty(obj,'address',{
            value:'山东蓝翔技校',
            writable:false,
            //enumerable 如果值为false 则不允许遍历,默认的值是false
            enumerable:false,
            //configurable 如果值为false 则不允许删除这个属性,不允许再修改第三个参数里面的特性 默认的值是false
            configurable:false,
        })
        console.log(Object.keys(obj));
        delete obj.address;
        delete obj.name;
        console.log(obj);
    </script>
</body>
</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
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908

转载自 (opens new window)

Last Updated: 5/15/2022, 5:17:53 PM
강남역 4번 출구
Plastic / Fallin` Dild