A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

首先我们先来讨论下面向对象与面向过程:
举个例子: 企业要举行晚会交给张经理负责,那么张经理需要做得就是:
    找演员(1)---->找舞台(2)----->找设备(3)---->设计晚会环节(4)---->购买一些零食饮料(5)等等
    其实任何的编程来源于生活,那么以上的例子本质上来讲就是面向过程,一步一步的去做,做完第一个才可以做第二个,按照步骤来。那么我们完全可以换一种思维方式去解决以上的问题,以上每一步要做的没有直接的关系,所以,把这个交给每一个去做,比如说:张三负责找演员,李四负责找舞台,王五负责找设备。。。,通过这种方式我们就可以大大提高办事效率,我们把这种方式称为面向对象。不用再去关注每一步,所有的事同时进行。
    总结:面向过程:一步一步去做,看重的是过程。
          面向对象:分配给某一个对象去做,看重的是对象。
在js中面向对象方式编程到底如何通过代码实现的呢? function Preject(name) {
    this.name = name
    // 定义找演员方法
    this.actor = function () {
        console.log(this.name + "找演员")
    },
        // 定义找舞台方法
        this.stage = function () {
            console.log(this.name + "找舞台")
        },
        // 找设备方法
        this.equipment = function () {
            console.log(this.name + "找设备")
        }
}
// 实例化对象
// let mzhang = new Preject("张三")
// // 调用找演员的方法
// mzhang.actor()
// let mzhang = new Preject("李四");
// // 调用找舞台的方法
// mzhang.stage()
解析:
    首先需要定义一个构造函数(本质上就是构造对象的模板)定义任何的方法或者属性都需要在构造函数里面去完成,定义好了必须要通过new关键字去执行下,此时构造函数内部的方法或者属性就指向了当前new出来的实例对象。
总结:通过以上代码,就是面向对象的编程方式优点:是提高的编程效率,使每一个方法都是一个独立的模块,模块与模块之间没有关联,一个方法没有实现不应影响另一个方法的实现。

以上代码存在问题:
     let mzhang = new Preject("张三")
     let mzhang1 = new Preject("李四");
     console.log(mzhang.actor == mzhang1.actor)//false
当两个实例对象的方法比较(引用与引用的比较)是false就意味着内存地址不一样。开辟了多个内存地址,这是不友好的,怎么办呢?引出原型:
首先:我们知道,构造函数是生成对象的模板,一个构造函数可以生成多个对象,每个对象都有相同的结构。构造函数的缺点就是,每当你实例化两个对象时,需要调用两次构造函数的某一个方法,这带来的坏处就是占用内存,而且没必要。
其次:为了解决构造函数的属性和方法无法被对象实例所共享的问题,我们可以把需要共享的属性和方法放在原型(prototype)对象上。原型对象上的所有属性和方法,都会被对象实例所共享。对于构造函数来说,prototype是作为构造函数的属性;对于对象实例来说,prototype是对象实例的原型对象。所以prototype即是属性,又是对象。
更改:
function Preject(name) {
    this.name = name
}
Preject.prototype.actor = function () {
    console.log(this.name + "找演员")
}
Preject.prototype.stage = function () {
    console.log(this.name + "找舞台")
}
Preject.prototype.equipment = function () {
    console.log(this.name + "找设备")
}
// 实例化对象
let mzhang = new Preject("张三")
let mzhang1 = new Preject("李四");
console.log(mzhang.actor == mzhang1.actor)
把方法定义在原型上。就实现了方法共享。

原型与构造函数以及实例对象的关系是什么呢?
读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。

通过这张图我们就可以知道:
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。② 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。③ 如果还没有就查找原型对象的原型(Object的原型对象)。 ④ 依此类推一直找到 Object 为止(null)。⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
原型与构造函数与实例对象的指向的一些属性和方法:
1.构造函数prototype------->原型对象
2.构造函数new-------->实例对象
3.实例对象访问proto---->原型对象
4.原型对象constructor--->构造函数
5.返回对象的原型对象:Object.getPrototypeOf(mzhang)
6.判断一个对象是否是另一个对象的原型Preject.prototype.isPrototypeOf(mzhang)
7.查看当前对象的属性Object.getOwnPropertyNames(mzhang|Preject.prototype)
8.对象自身属性中是否具有指定的属性(也就是,是否有指定的键注意:该方法会忽略掉那些从原型链上继承到的属性)mzhang.hasOwnProperty("name")
9.可以返回其可枚举属性的键值对的对象。Object.entries(mzhang)
Object和Object.prototype的区别
来看看Object构造函数和构造函数的原型Object.prototype都有哪些属性和方法。Object的属性和方法:



Object.prototype属性和方法:

总结:Object是构造函数,而Object.prototype是构造函数的原型对象。构造函数自身的属性和方法无法被共享,而原型对象的属性和方法可以被所有实例对象所共享。上面例子中,Object拥有自己的方法prototype,getPrototypeOf(),setPrototypeOf()等,这些方法无法被实例所共享。而Object.prototypeOf()的hasOwnProperty,isPrototypeOf(),constructor等属性和方法是可以被实例对象所共享的,本质上new就是一个语法糖,相当于给一个对象设置对象的原型let mzhang = new Preject()等价于mzhang.proto
对象,函数,构造函数之间的联系:
继承:
直接进入主题:
function Person(name) {
    this.name = name;
    this.age = 18
}
Person.prototype.job = 'frontend';
Person.prototype.sayHello = function () {
    console.log('Hello ' + this.name);
}
var person = new Person('大飞哥');
person.sayHello(); // Hello 大飞哥
function Child() {
    this.name = "child"
}
Child.prototype = new Person();
let child = new Child();
child.sayHello() //Hello child
// 判断元素是否属于另一个对象的原型
console.log(child instanceof Person) //true
console.log(child.age)//18
1.无法向父类传递参数
2.所有实例都会继承父类的属性 原型上的属性是共享的,一个实例修改属性另一个实例属性也会被修改。
function Child() {
    // 父类的函数呼叫当前的this来调用
    Person.call(this, "child")
}
let child = new Child();
console.log(child.name)
只继承父类构造函数的属性,没有继承原型的属性
子实例中可以向父实例传参。
无法实现构造函数的复用
原型链继承+借用构造函数的组合
function Child(name) {
    Person.call(this, name);
}
Child.prototype = new Person();
var child = new Child('jia');
child.sayHello(); // Hello jia
console.log(child instanceof Person); // true
可以传递参数可以继承父类的属性
每个实例都是私有的
调用两次构造函数耗内存
function object(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}
var super0 = new Person();
var super1 = object(super0);
console.log(super1 instanceof Person); // true
console.log(super1.job); // frontend
    name: {
        value: "zhangsan"
    }
});
console.log(author.name)
function F(){}
F.prototype = obj;
return new F();
this.age = 100;
Person.call(this); // 这个继承了父类构造函数的属性
解决了组合式两次调用构造函数属性的特点
// 重点Sub.prototype = obj;console.log(Sub.prototype.constructor); // Personobj.constructor = Sub; // 一定要修复实例console.log(Sub.prototype.constructor); // Subvar sub1 = new Sub();// Sub实例就继承了构造函数属性,父类实例,object的函数属性console.log(sub1.job); // frontendconsole.log(sub1 instanceof Person); // true





0 个回复

您需要登录后才可以回帖 登录 | 加入黑马