JavaScript高级(面向对象)

文章目录


1 面向对象编程介绍

在这里插入图片描述

1.2 面向过程编程 POP(Process-oriented programming)

在这里插入图片描述

1.3 面向对象编程 OOP (Object Oriented Programming)

向对象是以对象功能来划分问题,而不是步骤。
面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。

在这里插入图片描述
在这里插入图片描述

1.4 面向过程和面向对象的对比

在这里插入图片描述

2 Es6 中的类和对象

2.1 对象

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

在这里插入图片描述

2.2 类 class

类抽象了对象的公共部分,它泛指某一大类(class)
对象特指某一个,通过类实例化一个具体的对象 

在这里插入图片描述

2.3 创建类&创建实例:

class name {
 // class body
}
var xx = new name(); 
 注意: 类必须使用 new 实例化对象

2.4 类 constructor 构造函数

在这里插入图片描述

class Person {
 constructor(name,age) { // constructor 构造方法或者构造函数
 this.name = name;
 this.age = age;
 }
} 

创建实例:

var ldh = new Person('刘德华', 18);
console.log(ldh.name) 

2.5 类添加方法

class Person {
 constructor(name,age) { // constructor 构造器或者构造函数
 this.name = name;
 this.age = age;
 }
 say() {
 console.log(this.name + '你好');
 }
} 

创建实例:

var ldh = new Person('刘德华', 18);
ldh.say() 

在这里插入图片描述

3 类的继承

程序中的继承:子类可以继承父类的一些属性和方法。
class Father{ // 父类
}
class Son extends Father { // 子类继承父类
} 

实例:

class Father {
 constructor(surname) {
 this.surname= surname;
 }
 say() {
 console.log('你的姓是' + this.surname);
 }
}
class Son extends Father{ // 这样子类就继承了父类的属性和方法
}
var damao= new Son('刘');
damao.say();

3.1 super 关键字-可以调用父类的构造函数

在这里插入图片描述

class Person { // 父类
 constructor(surname){
 this.surname = surname;
 }
}
class Student extends Person { // 子类继承父类
 constructor(surname,firstname){
 super(surname); // 调用父类的constructor(surname)
this.firstname = firstname; // 定义子类独有的属性
 }
} 
注意: 子类在构造函数中使用super, 必须放到 this 前面 (必须先调用父类的构造方法,在使用子类构造方法)

案例:
在这里插入图片描述

3.2 super关键字 也可以调用父类的普通函数。

class Father {
 say() {
 return '我是爸爸';
 }
}
class Son extends Father { // 这样子类就继承了父类的属性和方法
 say() {
 // super.say() super 调用父类的方法
 return super.say() + '的儿子';
 }
}
var damao = new Son();
console.log(damao.say()); 

3.3 三个注意点:

在这里插入图片描述

4 tab栏切换案例(面向对象编程)

Html部分
在这里插入图片描述

var that = ''; //用于保存this对象
class Tab {
    constructor(id) {
            //获取大盒子
            this.main = document.querySelector(id);
            //获取加号
            this.add = this.main.querySelector('.tabadd');
            //li 的父亲
            this.ul = this.main.querySelector('.fisrstnav ul:first-child');
            //获取盒子内容的父亲
            this.fsection = this.main.querySelector('.tabscon');
            //页面加载调用
            this.init();
            that = this;
        }
        //初始化
    init() {
            this.updateNode()
                //点击加号调用
            this.add.onclick = this.addTab;
            //绑定tab点击
            for (var i = 0; i < this.lis.length; i++) {
                this.lis[i].index = i;
                index = i + 1;
                //点击后调用taggleTab
                this.lis[i].onclick = this.taggleTab;
                //删除按钮
                this.remove[i].onclick = this.removeTab;
                //修改文本
                this.spans[i].onclick = this.editTab;
                //修改盒子内容
                this.sections[i].onclick = this.editTab;
            }
        }
        //获取动态的标签
    updateNode() {
            //lis
            this.lis = this.main.querySelectorAll('li');
            // 盒子内容
            this.sections = this.main.querySelectorAll('section');
            //删除按钮
            this.remove = this.main.querySelectorAll('.icon-guanbi');
            //修改文本内容
            this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child');
        }
        //1.切换功能
    taggleTab() {
            that.clearClass();
            //this指向lis
            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 = ''
            }
        }
        //2.添加功能
    addTab() {
            that.clearClass()
                //创建元素li
            var li = '<li class="liactive"><span>新增测试</span><span class="iconfont icon-guanbi"></span></li>'
                //追加元素
            that.ul.insertAdjacentHTML('beforeend', li);
            var section = '<section class="conactive">测试' + Math.random() + '</section>'
            that.fsection.insertAdjacentHTML('beforeend', section);
            that.init();

        }
        //3.删除功能
    removeTab(e) {
            e.stopPropagation(); //阻止冒泡
            var n = this.parentNode.index

            //删除对应li 和内容
            that.lis[n].remove();
            that.sections[n].remove();
            that.init();
            n--;
            if (document.querySelector('.liactive')) return;
            that.lis[n] && that.lis[n].click();

        }
        //4. 修改功能
    editTab(e) {
        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();
        //离开文本框,重新赋值
        input.onblur = function() {
            this.parentNode.innerHTML = this.value;
        };
        //按下回车键赋值
        input.onkeyup = function(e) {
            if (e.keyCode === 13) {
                this.blur();
            }
        }

    }
}
new Tab('#tab');

展现:
在这里插入图片描述

二. 构造函数和原型

在 ES6之前 ,对象不是基于类创建的,而是用一种称为构建函数的特殊函数来定义对象和它们的特征。

1 构造函数

构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面
在这里插入图片描述
在这里插入图片描述

1.1静态成员& 实例成员

在这里插入图片描述

<script>
        // 构造函数中的属性和方法我们称为成员, 成员可以添加
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            this.sing = function() {
                console.log('我会唱歌');

            }
        }
        var ldh = new Star('刘德华', 18);
        // 1.实例成员就是构造函数内部通过this添加的成员 uname age sing 就是实例成员
        // 实例成员只能通过实例化的对象来访问
        console.log(ldh.uname);
        ldh.sing();
        // console.log(Star.uname); // 不可以通过构造函数来访问实例成员
        // 2. 静态成员 在构造函数本身上添加的成员  sex 就是静态成员
        Star.sex = '男';
        // 静态成员只能通过构造函数来访问
        console.log(Star.sex);
        console.log(ldh.sex); // 不能通过对象来访问
    </script>

1.2构造函数的问题(存在浪费内存)

构造函数方法很好用,但是存在浪费内存的问题。
在这里插入图片描述

1.3 构造函数原型 prototype

在这里插入图片描述
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
在这里插入图片描述

1.4 对象原型 proto

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.5 constructor 构造函数

对象原型( proto构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称
为构造函数,因为它指回构造函数本身
在这里插入图片描述

1.6 构造函数、实例、原型对象三者之间的关系

在这里插入图片描述

1.7 原型链

在这里插入图片描述

1.8 JavaScript 的成员查找机制(规则)

在这里插入图片描述

1.9 原型对象this指向

构造函数中的this 指向我们实例对象.
原型对象里面放的是方法, 这个方法里面的this 指向的是 这个方法的调用者, 也就是这个实例对象.

1.10 扩展内置对象

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

  <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];
        console.log(arr.sum());
        console.log(Array.prototype);
        var arr1 = new Array(11, 22, 33);
        console.log(arr1.sum());
    </script>

2 继承

ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

2.1 call()

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

fun.call(thisArg, arg1, arg2, ...)

在这里插入图片描述

2.2 借用构造函数继承父类型属性 cell()

 // 父类
 function Person(name, age, sex) {
 this.name = name;
 this.age = age;
 this.sex = sex;
 }
 // 子类
 function Student(name, age, sex, score) {
 Person.call(this, name, age, sex); // 此时父类的 this 指向子类的 this,同时调用这个函数
 this.score = score;
 }
 var s1 = new Student('zs', 18, '男', 100);
 console.dir(s1);

2.3 借用原型对象继承父类型方法

一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。
在这里插入图片描述

 <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('刘德华', 18, 100);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);
    </script>
</body>

3 ES5 中的新增方法(数组,字符串,对象)

3.1 数组方法

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

3.1.1 forEach()
array.forEach(function(currentValue, index, arr))

在这里插入图片描述

3.1.2 filter() 筛选数组

注意它直接返回一个新数组
在这里插入图片描述

3.1.3 some()返回值是布尔值

在这里插入图片描述

    <script>
        // some 查找数组中是否有满足条件的元素 
        // var arr = [10, 30, 4];
        // var flag = arr.some(function(value) {
        //     // return value >= 20;
        //     return value < 3;
        // });
        // console.log(flag);
        var arr1 = ['red', 'pink', 'blue'];
        var flag1 = arr1.some(function(value) {
            return value == 'pink';
        });
        console.log(flag1);
        // 1. filter 也是查找满足条件的元素 返回的是一个数组 而且是把所有满足条件的元素返回回来
        // 2. some 也是查找满足条件的元素是否存在  返回的是一个布尔值 如果查找到第一个满足条件的元素就终止循环
    </script>

3.2 字符串方法 trim()

trim() 方法会从一个字符串的两端删除空白字符。
str.trim()
trim() 方法并不影响原字符串本身,它返回的是一个新的字符串。

3.3 对象方法

3.3.1 Object.keys() 方法返回一个所有元素为字符串的数组。
Object.keys(obj)

在这里插入图片描述

3.3.1 Object.defineProperty() 定义新属性或修改原有的属性。
Object.defineProperty(obj, prop, descriptor)

在这里插入图片描述

在这里插入图片描述

三 函数进阶

1 函数的定义和调用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. this

这些 this 的指向,是当我们调用函数的时候确定的。 调用方式的不同决定了this 的指向不同
一般指向我们的调用者.
在这里插入图片描述

2.1 改变函数内部 this 指向 bind()、call()、apply()

2.1.1 call()

在这里插入图片描述

2.1.2 apply 方法

在这里插入图片描述

2.1.3 bind() 不调用

在这里插入图片描述

2.2 call apply bind 总结

在这里插入图片描述

3. 严格模式

在这里插入图片描述

3.1 开启严格模式

严格模式可以应用到整个脚本个别函数中。因此在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式两种情况。
在这里插入图片描述

<script>
 "use strict";
 console.log("这是严格模式。");
</script>

将 “use strict” 放在函数体的第一行,则整个函数以 “严格模式” 运行。

3.2 严格模式中的变化

  1. 变量规定
    在这里插入图片描述
  2. 严格模式下 this 指向问题
    在这里插入图片描述
  3. 函数变化
    在这里插入图片描述
    更多严格模式要求参考:https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Reference/Strict_mode

4 . 高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数将函数作为返回值输出
在这里插入图片描述

5. 闭包

5.1 变量作用域

在这里插入图片描述

5.2 什么是闭包

闭包(closure)指有权访问另一个函数作用域中变量的函数。 ----- JavaScript 高级程序设计
闭包作用:延伸变量的作用范围。

<script>
function fn1(){ // fn1 就是闭包函数
 var num = 10;
 function fn2(){
 console.log(num); // 10
 }
 fn2()
}
 fn1();
</script>

在这里插入图片描述
在这里插入图片描述

    <script>
        // 闭包应用-计算打车价格 
        // 打车起步价13(3公里内),  之后每多一公里增加 5块钱.  用户输入公里数就可以计算打车价格
        // 如果有拥堵情况,总价格多收取10块钱拥堵费
        // function fn() {};
        // fn();
        var car = (function() {
            var start = 13; // 起步价  局部变量
            var total = 0; // 总价  局部变量
            return {
                // 正常的总价
                price: function(n) {
                    if (n <= 3) {
                        total = start;
                    } else {
                        total = start + (n - 3) * 5
                    }
                    return total;
                },
                // 拥堵之后的费用
                yd: function(flag) {
                    return flag ? total + 10 : total;
                }
            }
        })();
        console.log(car.price(5)); // 23
        console.log(car.yd(true)); // 33

        console.log(car.price(1)); // 13
        console.log(car.yd(false)); // 13
    </script>

6 递归 (调用自身)

在这里插入图片描述
利用递归遍历数据

    <script>
        var data = [{
            id: 1,
            name: '家电',
            goods: [{
                id: 11,
                gname: '冰箱',
                goods: [{
                    id: 111,
                    gname: '海尔'
                }, {
                    id: 112,
                    gname: '美的'
                }, ]
            }, {
                id: 12,
                gname: '洗衣机'
            }]
        }, {
            id: 2,
            name: '服饰'
        }];
        // 我们想要做输入id号,就可以返回的数据对象
        // 1. 利用 forEach 去遍历里面的每一个对象
        function getID(json, id) {
            var o = {};
            json.forEach(function(item) {
                // console.log(item); // 2个数组元素
                if (item.id == id) {
                    // console.log(item);
                    o = item;
                    // 2. 我们想要得里层的数据 11 12 可以利用递归函数
                    // 里面应该有goods这个数组并且数组的长度不为 0 
                } else if (item.goods && item.goods.length > 0) {
                    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, 111));
    </script>

7 深拷贝& 浅拷贝

7 .1 浅拷贝

    <script>
        // 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
        // 深拷贝拷贝多层, 每一级别的数据都会拷贝.
        var obj = {
            id: 1,
            name: 'andy',
            msg: {
                age: 18
            }
        };
        var o = {};
        // for (var k in obj) {
        //     // k 是属性名   obj[k] 属性值
        //     o[k] = obj[k];
        // }
        // console.log(o);
        // o.msg.age = 20;
        // console.log(obj);

        console.log('--------------');
        Object.assign(o, obj);
        console.log(o);
        o.msg.age = 20;
        console.log(obj);
    </script>

7 . 深拷贝

  <script>
        // 深拷贝拷贝多层, 每一级别的数据都会拷贝.
        var obj = {
            id: 1,
            name: 'andy',
            msg: {
                age: 18
            },
            color: ['pink', 'red']
        };
        var o = {};
        // 封装函数 
        function deepCopy(newobj, oldobj) {
            for (var k in oldobj) {
                // 判断我们的属性值属于那种数据类型
                // 1. 获取属性值  oldobj[k]
                var item = oldobj[k];
                // 2. 判断这个值是否是数组
                if (item instanceof Array) {
                    newobj[k] = [];
                    deepCopy(newobj[k], item)
                } else if (item instanceof Object) {
                    // 3. 判断这个值是否是对象
                    newobj[k] = {};
                    deepCopy(newobj[k], item)
                } else {
                    // 4. 属于简单数据类型
                    newobj[k] = item;
                }

            }
        }
        deepCopy(o, obj);
        console.log(o);

        var arr = [];
        console.log(arr instanceof Object);
        o.msg.age = 20;
        console.log(obj);
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值