通过代码探究javascript是如何实现面向对象的

javascript如何实现面向对象的?

之前使用javascript大多是编写一些页面的动态效果,比较少用到面向对象方面的内容,但是随着越来越多人使用node写后端,就在这里使用代码去探究何为javascript面向对象。

  1. 先定义一个方法并且在控制台打印它的prototype.
function Person(){
    console.log(`i am a boy`);
}
console.log(Person);
console.log(Person.prototype);

获得如下输出
打印javascript方法的原型对象
这里打印的prototype就是Person方法原型对象,每个js方法都会有一个原型
那么,我们再脑海里就有这样一幅初始图了。(先不要考虑为啥会有个prototype)
javascript对象关系图
我们再加多一条打印语句

console.log(Person);
console.log(Person.prototype);
console.log(Person.prototype.constructor);

看到如下控制台输出
javascript对象模型
显然,Person以及Person.prototype.constructor是相同的,那么我们可以在刚刚那幅图上再加一条指向关系
javascript对象关系图
知道了方法以及每个方法都有一个的原型对象有什么意义呢,接下来看一下javascript里我们如何创建一个对象,有过其它面向对象编程语言例如java的编程经验的同学应该知道new这个关键字创建一个指定类的实例对象的。

var obj1 = new Person();
console.log(obj1);

代码结果
看到上面的代码以及控制台的输出,我们不难看出,javascript里面我们对方法进行new functionName()之后,会将方法里的代码执行一遍然后返回一个对象,这个对象就是实例对象,我们看到这里的实例对象赋值给了obj1并且打印出来了Person{},这个貌似和我们之前打印的Person.prototype,也就是方法的原型对象貌似是一个东西,那么我们看一下到底是否相同。如下:

Person.prototype.run = function(){
    console.log(`i am running`);
}
var obj1 = new Person();
console.log(Person.prototype);
console.log(obj1);
obj1.run();

运行结果:
代码运行结果
所以,实例对象与原型对象不是同一个东西,这里注意一下,如果对结果图红框部分为何有Person在前头感觉疑惑,可以当做是一个类型标记即可,因为我们平时定义的json对象打印出来是不会有那个标记的。最后一行的打印可以看出实例对象可以运行原型对象中定义的方法。那么我们的关系图又可以进一步更新了
在这里插入图片描述
可以看到,实例对象里面有一个__proto__属性,如果我们尝试在控制台打印console.log(obj1.proto)是无法打印的,这个属性我们无法访问,js引擎可以访问,在这里我们直接理解为实例对象是通过这个属性访问原型对象中定义的方法的。

到这里已经差不多对整个对象模型有个初步的了解,我们再用更多的代码实际体会一下,javascript里的面向对象基本操作。

function Person(name,age){
    this.name = name;
    this.age = age;
    this.run = function(){
        console.log(`running --------function from object`);
    }
    console.log(`-----------------------------------------------------打印函数内部的this如下`);
    console.log(this);
}
Person.prototype.run = function(){
    console.log(`i am running-----function from prototype`);
}
Person.prototype.jump = function(){
    console.log(`jump-----function from prototype`);
}
var obj1 = new Person('张四',22);
console.log(`-----------------------------------------------------打印函数原型对象如下`);
console.log(Person.prototype);
console.log(`-----------------------------------------------------打印实例对象如下`);
console.log(obj1);
console.log(`-----------------------------------------------------原型对象里的方法会被实例对象里定义的同名方法覆盖`);
obj1.run();

得到如下输出:
javascript running result
我们在方法中使用了this,这个隐式参数,从打印我们也可以看出this其实就是创建后的实例对象,我们可以将看作person 方法最后返回了一个this。像这样

function Person(name,age){
    this.name = name;
    this.age = age;
    return this;
}

所以我们再方法内对this进行的操作就是对我们实例对象进行操作。且当我们给实例对象添加属性或方法与我们本身的方法原型对象中定义的属性或方法重名时,将会覆盖掉原型中的属性以及方法。我们再外部调用实例的各个方法以及属性时就不会访问原型。例如上面例子的run方法。

那么我们查阅一些资料可以知道,面向对象的重要特性有继承,封装,多态等等,那么再javascript里面要如何实现?简单的做一个继承研究一下。

function Man(){
    this.sex = '男';
    Person.apply(this,arguments);
}
var obj2 = new Man('张四',22);
console.log(`-----------------------------------------------------打印实例对象如下`);
console.log(obj2);
obj2.run();

输出如下:
javascript运行结果
不难发现我们再person类的基础上添加一个sex属性扩展了一个man类,当然这个sex按原则本就该放在person类中,但是这里也就为了举个例子看看javascript的继承实现。至于里面有的apply,arguments等语法以后再作探究。

到最后,还有一个问题可能大家也会有疑惑,既然能够在方法内将实例对象this进行属性等配置,为什么我们还需要一个prototype这样一个原型对象呢,想想看,如果想要一个实例所有的方法都在函数执行的代码块中通过,this.xx = function(){}去定义,那么我们调用这个方法就一定要创建新的对象才行,如果是在prototype中定义的方法,我们就可以直接通过,XXX.prototype.xxx();进行调用,就方便很多。

扫描二维码关注公众号,回复: 5690502 查看本文章

猜你喜欢

转载自blog.csdn.net/A6107907/article/details/86417106
今日推荐