JavaScript课程——Day15(编程思想、对象的读写、面向对象的创建、面向对象的案例)

1、编程思想

  • 面向过程:面向过程思想强调的是步骤,当碰见问题时,思考的是“我该怎么做”,分析出解决问题所需的步骤,一步步的去实现。
  • 面向对象:面向对象思想强调的是对象,当碰见问题时,思考的是“我该让谁来做”。这个“谁”其实就是对象。找合适的对象做合适的事情。而对象如何去做(采用什么样的步骤)我们就不关心了,最终把问题解决掉就可以了。

  相关概念:

var 对象 = {
    key1: value1,
    key2: value2,
    ...
}

 

  1.1、对象:无序的明值对

  1.2、对象组成:

    • 属性:对象的特征描述,静态,名词
    • 方法:对象的行为,动态(函数)

  1.3、对象的基本特征:封装、继承、多态(了解)

  1.4、类和示例

    • 类:类是对象的类型模板
    • 实例:实例是根据类创建的对象
    • 面向对象学习,就是学习创建类(模板),利用类生成实例(月饼)

 

2、对象的读写

var obj = {
    name: 'zs',
    age: 3,
    aa: undefined,
    job: function () {
        console.log(this);
        console.log('前端开发');
    }
};

//
console.log(obj.name); // 点的形式
console.log(obj['age']); // 中括号的形式
obj.job();
var v = obj.job;
v();

// -------------------
//
// 如果原来存在这个属性,则就是修改,如果不存在,则是添加
obj.name = 'ls';
obj.sex = '男';
console.log(obj);

// ----------------------
// 遍历
for (var attr in obj) {
    console.log(attr, '-----', obj[attr]);
}

// -----------------------
// in操作符:检查对象有某个属性没,返回布尔值
// 格式:key in 对象
// 区分清楚属性有不有和值没有一点关系
console.log('name' in obj); // true
console.log('abc' in obj); // false
console.log('aa' in obj); // true

// ----------------------
// 删除对象的某个属性
// 格式:delete 对象.属性名;
delete obj.aa;
delete obj.job;
console.log(obj);

 

3、面向对象的创建

  3.1、字面量创建

var obj = {
    name: 'zs',
    age: 3,
    showNmae: function () {
        console.log(this.name);
    }
}
obj.showNmae();

var obj2 = {
    name: 'ls',
    age: 5,
    showNmae: function () {
        console.log(this.name);
    }
}
console.log(obj2.age);
obj2.showNmae();

// 不足:适用于单个对象的创建,如果要创建多个对象,会代码冗余

 

  3.2、实例创建

var obj = new Object(); // 实例
obj.name = 'zs';
obj.age = 3;
obj.showName = function () {
    console.log(this.name);
}
console.log(obj);



var obj2 = new Object(); // 实例
obj2.name = 'ls';
obj2.age = 5;
obj2.showName = function () {
    console.log(this.name);
}
console.log(obj2);

// 不足:适用于单个对象的创建,如果要创建多个对象,会代码冗余

 

  3.3、工厂模式

// 工厂模式:归根到底是一个封装函数
function createPerson(name, age) {
    // 1、准备原料
    var obj = new Object();

    // 2、加工
    obj.name = name;
    obj.age = age;
    obj.showNmae = function () {
        console.log(this.name);
    }

    // 3、出厂
    return obj;
}

var o1 = createPerson('zs', 3);
console.log(o1);

var o2 = createPerson('ls', 5);
console.log(o2);

// 优点:可以大量创建
// 不足:不能标识出它是由谁创建的

 

instanceof

// 格式:对象 instanceof 函数
// 作用:运算符,一个对象是否为指定的构造函数的实例,返回布尔值

console.log([] instanceof Array); // true
console.log([] instanceof Object); // true  因为Object是我们js世界里的老大,一切对象都是由它创建的

console.log(o1 instanceof createPerson); // false 这是工厂模式的不足,不能标识出由谁创建的
console.log(o1 instanceof Object); // true

 

  3.4、构造函数模式

  构造函数的特点:

  1、构造函数名首字母大写(为了区分普通函数,不是必须,是约定)

  2、构造函数方法没有显示的创建对象(new object())

  3、直接将属性和方法赋值给this对象

  4、没有return语句,不需要返回对象

  5、通过构造函数创建对象,必须使用new运算符(直接调用跟普通函数一样)

function CreatePerson(name, age) {
    this.name = name;
    this.age = age;
    this.showName = function () {
        console.log('小张');
    }
}
var p1 = new CreatePerson('zs', 3);
console.log(p1);
console.log(p1.showName)
console.log(p1.name);
p1.showName();

var p2 = new CreatePerson('ls', 5);
console.log(p2);
console.log(p2.showName)

// 问题:同样的方法,在每个实例上都要重新生成,耗内存
console.log(p1.showName == p2.showName); // false

  以这种方式调用构造函数实际上会经历以下4个步骤

  (1)创建一个新对象;

  (2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

  (3)执行构造函数中的代码(为这个新对象添加属性);

  (4)返回新对象(隐式返回)。(因此p1就是这个新对象,同时p1也是this)

var o = CreatePerson('zs', 3); // 直接调用就是普通函数调用,则这些属性和方法加给了window,同时没有返回值,所以o是undefined。所以构造函数一定要能过new调用

 

  对象的比较

// 基本类型,基本类型的比较,是值的比较
console.log(5 == 5); // true

// 引用类型,引用类型的比较,是地址的比较
var a = [];
var b = [];
console.log(a == b); // false

 

  3.5、原型创建对象

  (1)原型

  js每声明一个function,都有prototype原型,prototype原型是函数的一个默认属性,在函数的创建过程中由js编译器自动添加。

  也就是说,当生产一个function对象的时候,就有一个原型prototype。原型中存储对象共享的属性和方法。

 

  (2)原型链

  当查找对象的属性的时候,先找自身,如果自身没有,则顺着__prototype__找到原型,如果原型也没有,则继续向上找,一直找到Object的原型。这个查找链表就是原型链。

// 原型对象:存储对象公共属性和方法的地方
// 每写一个函数,都会有一个原型对象prototype

var arr = new Array(); // Array就是构造函数
console.log(arr); // arr就是实例

console.log(arr.__proto__); // 原型对象,通过实例找到原型
console.log(Array.prototype); // 原型对象,通过构造函数找到原型

console.log(arr.__proto__ == Array.prototype); // true

 

  原型创建对象

function CreatePerson() { }

// 每声明一个函数,都会有一个原型对象,原型对象默认有一个constructor的属性,它又指向构造函数
// console.log(CreatePerson.prototype); // CreatePerson的原型   {constructor: ƒ}
// console.log(CreatePerson.prototype.constructor); // constructor

CreatePerson.prototype.name = 'zs';
CreatePerson.prototype.age = 3;
CreatePerson.prototype.showName = function () {
    console.log('小张');
}

// console.log(CreatePerson.prototype);

// --------------------------
var p1 = new CreatePerson();
console.log(p1);
// console.log(p1.name);
// p1.showName()
// console.log(p1.constructor);
// console.log(p1.toString);

var p2 = new CreatePerson();
console.log(p2);

console.log(p1.showName == p2.showName); // true
// 优点:原型方法完美的解决了构造函数会方法会重复创建的问题
// 不足:不能似参,创建的结果都一样


console.log(p2.abc); // undefined

 

  3.6、混合模式创建对象

// 是我们创建对象的标准方法
// 混合模式:构造函数+原型
// 每个对象独有的写在构造函数里,公有的写在原型上
function CreatePerson(name, age) {
    this.name = name;
    this.age = age;
}
CreatePerson.prototype.showName = function () {
    console.log(this.name);
}

var p1 = new CreatePerson('zs', 3);
console.log(p1);
// console.log(p1.name);
// p1.showName();

var p2 = new CreatePerson('ls', 5);
console.log(p2);

 

  3.7、动态混合模式

// 动态混合模式
// 好处:代码有一个封装的感觉
// 执地原理:同混合模式
function CreatePerson(name, age) {
    this.name = name;
    this.age = age;
    if (typeof CreatePerson.prototype.showName !== 'function') {
        CreatePerson.prototype.showName = function () {
            console.log(this.name);
        }
        CreatePerson.prototype.showAge = function () {
            console.log(this.age);
        }
    }
}

var p1 = new CreatePerson('zs', 3);
console.log(p1);

var p2 = new CreatePerson('ls', 5);
console.log(p2);

 

4、面向对象的案例

  面向对象的选项卡

  原则:先写出普通的写法,然后改成面向对象方法

  1、普通方法变型

  尽量不要出现函数嵌套函数

  可以有全局变量

  把onload中不是赋值的语句放到单独函数中(init)

  2、改成面向对象()

  先写构造函数

  onload中创建对象,并init调用

  全局变量就是属性

  函数就是方法

  (属性和方法前面,都要加this)

  改this指向问题(尽量让this指向对象)

 

  结论:我们改成面向对象之后,感觉是不是更复杂了?确实是这样,确实是复杂了,但是我们这个面向对象特别适合复杂的开发,对于简单的,不太推荐使用面向对象。面对复杂开发时,它特别容易扩展,同时,复用性特别强。上面的例子,多添加几个,就可以发现特别方便复用和扩展。

 

  普通方法实现和变形

<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>Document</title>
    <style>
        span {
            display: inline-block;
            width: 100px;
            height: 30px;
            background-color: #ccc;
            line-height: 30px;
            text-align: center;
            color: white;
            cursor: pointer;
        }

        .active {
            background-color: red;
        }

        #box div {
            width: 330px;
            height: 150px;
            border: 2px solid #ccc;
            font-size: 40px;
            line-height: 150px;
            text-align: center;
            display: none;
        }
    </style>
    <script>
        // 普通方法实现
        // window.onload = function () {
        //     var box = document.getElementById('box');
        //     var span = box.querySelectorAll('span');
        //     var div = box.querySelectorAll('div');

        //     for (var i = 0; i < span.length; i++) {
        //         span[i].index = i; // 自定义下标

        //         span[i].onclick = function () {
        //             // 1、所有的span去掉样式,所有的div隐藏
        //             for (var i = 0; i < span.length; i++) {
        //                 span[i].className = '';
        //                 div[i].style.display = 'none';
        //             }

        //             // 2、当前的span加上样式,对应的div显示
        //             this.className = 'active';
        //             div[this.index].style.display = 'block';

        //         }
        //     }
        // }


        // ---------------------------------------
        // 普通方法变形
        var box = null;
        var span = null;
        var div = null;

        window.onload = function () {
            box = document.getElementById('box');
            span = box.querySelectorAll('span');
            div = box.querySelectorAll('div');
            init();
        }

        function init() {
            for (var i = 0; i < span.length; i++) {
                span[i].index = i; // 自定义下标

                span[i].onclick = change;
            }
        }

        function change() {
            // 1、所有的span去掉样式,所有的div隐藏
            for (var i = 0; i < span.length; i++) {
                span[i].className = '';
                div[i].style.display = 'none';
            }

            // 2、当前的span加上样式,对应的div显示
            this.className = 'active';
            div[this.index].style.display = 'block';
        }
    </script>
</head>

<body>
    <div id="box">
        <span class="active">html</span>
        <span>css</span>
        <span>js</span>
        <div style="display: block;">html</div>
        <div>css</div>
        <div>js</div>
    </div>
</body>

 

  改成面向对象

<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>Document</title>
    <style>
        span {
            display: inline-block;
            width: 100px;
            height: 30px;
            background-color: #ccc;
            line-height: 30px;
            text-align: center;
            color: white;
            cursor: pointer;
        }

        .active {
            background-color: red;
        }

        #box div {
            width: 330px;
            height: 150px;
            border: 2px solid #ccc;
            font-size: 40px;
            line-height: 150px;
            text-align: center;
            display: none;
        }
    </style>
    <script>
        // var box = null;
        // var span = null;
        // var div = null;

        // window.onload = function () {
        //     box = document.getElementById('box');
        //     span = box.querySelectorAll('span');
        //     div = box.querySelectorAll('div');
        //     init();
        // }

        // function init() {
        //     for (var i = 0; i < span.length; i++) {
        //         span[i].index = i; // 自定义下标

        //         span[i].onclick = change;
        //     }
        // }

        // function change() {
        //     // 1、所有的span去掉样式,所有的div隐藏
        //     for (var i = 0; i < span.length; i++) {
        //         span[i].className = '';
        //         div[i].style.display = 'none';
        //     }

        //     // 2、当前的span加上样式,对应的div显示
        //     this.className = 'active';
        //     div[this.index].style.display = 'block';
        // }

        // -------------------------------------
        function Tab() {
            this.box = document.getElementById('box');
            this.span = this.box.querySelectorAll('span');
            this.div = this.box.querySelectorAll('div');
        }
        Tab.prototype.init = function () {
            var that = this; // 对象存给了that
            for (var i = 0; i < this.span.length; i++) {
                this.span[i].index = i; // 自定义下标
                this.span[i].onclick = function () {
                    // this--span
                    that.change(this);
                }
            }
        }
        Tab.prototype.change = function (ele) {
            // 1、所有的span去掉样式,所有的div隐藏
            for (var i = 0; i < this.span.length; i++) {
                this.span[i].className = '';
                this.div[i].style.display = 'none';
            }
            // 2、当前的span加上样式,对应的div显示
            ele.className = 'active';
            this.div[ele.index].style.display = 'block';
        }

        window.onload = function () {
            var t1 = new Tab();
            t1.init();
        }
    </script>
</head>

<body>
    <div id="box">
        <span class="active">html</span>
        <span>css</span>
        <span>js</span>
        <div style="display: block;">html</div>
        <div>css</div>
        <div>js</div>
    </div>
</body>
posted @ 2021-05-10 21:45  别动我咖喱  阅读(65)  评论(0编辑  收藏  举报