微信公众号:全栈者 作者:TinRongGao 欢迎关注我,一起学习,一起进步!
本文来由:今天下午,笔者和一个做后端的同学一起聊天,聊到了JavaScript语言本身的相关内容,不可否认JavaScript本身确实有很多不可回避的问题,同学还指出说JavaScript连面向对象的没有,我告诉他虽然JavaScript在面向对象实现上因为和其他大多数后端语言不一样,但是它确实是支持面向对象的,故写此篇记录一下,分享给有需要的同学。
首先给出结论,JavaScript 的本身是支持面向对象的,它本身具备着强大灵活的 OOP 语言能力。但是对于使用过基于类的语言 (如 Java 或 C++) 的开发人员来说,JavaScript 确实有点令人困惑,因为它是动态的,并且本身不提供一个 class 实现。虽然在 ES6 中引入了 class 关键字,但它只是一个语法糖,本质还是基于JavaScript 的原型来实现的。
说起JavaScript的面向对象,就必须要聊Javascript的原型。
我们知道JavaScript 语言本身只有一种数据结构,就是对象(Object),万物皆生于与对象,像我们常使用的函数,正则等均是对象(Object)衍生出来的实例对象。
Function instanceof Object //true
RegExp instanceof Object //true
Number instanceof Object //true
Date instanceof Object //true
在每个实例对象中,都有一个私有属性( proto__ 属性),这个私有属性指向它的构造函数的原型对象(构造函数的prototype属性指向的对象 ),该原型对象也会有一个自己的私有属性( __proto ) ,然后它指向的构造函数的prototype属性指向的对象,然后这样一层层的向上直到一个对象的原型对象为 null,即代表JavaScript的原型到了顶层。出现了一个非常有趣的现象,从无到有对象,然后从对象再到万物。
看一下我之前画的一个图:
// 构造函数Person
function Person(name){
this.name = name
}
Person.prototype.sayName = function(){
console.log(this===me) //true
console.log(this.__proto__===Person.prototype) //true
return this.name
}
var me = new Person('FantasyGao')
var obj = {}
me.sayName()
console.log(me.constructor===Person) //true 实例对象指向Person
console.log(me.__proto__.constructor===Person) //true 实例对象的__proto__指向Object
console.log(obj.constructor===Object) //true 定义对象指向Object
console.log(obj.__proto__.constructor===Object) //true 定义对象的__proto__指向Object
console.log(Person.constructor===Function) //true 构造函数对象指向Function
console.log(Person.__proto__.__proto__.constructor===Object) //true 构造函数对象的__proto__.__proto__指向Object
console.log(Person.__proto__.constructor===Function) //true Object.prototype的__proto__即null
console.log(Function.constructor===Function) //true Function函数对象指向Function
console.log(Function.__proto__.constructor===Function) //true Function函数对象的__proto__指Function
console.log(Object.constructor===Function) //true Object指向Function
console.log(Object.__proto__.constructor===Function) //true Object的__proto__指向Function
console.log(me.__proto__===Person.prototype) //true 实例对象的__proto__即构造函数的prototype
console.log(obj.__proto__===Object.prototype) //true 定义对象的__proto__即Object的prototype
console.log(Person.__proto__===Function.prototype) //true 构造函数对象的__proto__即Function的prototype
console.log(Object.__proto__===Function.prototype) //true Object的__proto__即Function的prototype
console.log(Function.__proto__===Function.prototype) //true Function的__proto__即Function的prototype
console.log(Function.prototype.__proto__===Object.prototype) //true Function.prototype的__proto__即Object的prototype
console.log(me.__proto__.__proto__===Person.__proto__.__proto__) //true 实例对象的__proto__的__proto__的__proto__即null
console.log(me.__proto__.__proto__===obj.__proto__) //true 实例对象的__proto__的__proto__的__proto__即null
console.log(Function.prototype.__proto__.__proto__===null) //true Function.prototype的__proto__的__proto__即null
console.log(Person.__proto__.__proto__.__proto__===null) //true Object.prototype的__proto__即null
console.log(Object.prototype.__proto__===null) //true Object.prototype的__proto__即null
console.log(me.__proto__.__proto__.__proto__===null) //true 实例对象的__proto__的__proto__的__proto__即null
console.log(obj.__proto__.__proto__===null) //true 定义对象的__proto__的__proto__即null
console.log(me.prototype) //undefined
console.log(obj.prototype) //undefined
console.log(Person.__proto__.prototype) //undefined
console.log(me.__proto__.prototype) //undefined
console.log(me.__proto__.__proto__.prototype) //undefined
function Person(name,age) {
let obj = {
name:name,
age:age
}
return obj
}
var me = Person('FantasyGao', 22)
var you = Person('Demi', 21)
console.log(me.name)
// new 构造函数生成对象
function Person(name,age) {
this.name = name
this.age = age
}
var me = new Person('FantasyGao', 22)
console.log(me.name)
// prototype承载属性/方法
function Person(name,age) {
this.name = name
this.age = age
}
Person.prototype.country = 'China'
Person.prototype.say = function(){
return 'i am Chinese'
}
var me = new Person('FantasyGao', 22)
var you = new Person('Demi', 21)
console.log(me.name) //FantasyGao
console.log(me.say()) //China
console.log(you.say()) //China
console.log(me === you) //false
console.log(me.say === you.say) //true(地址相同)
// 继承其他构造函数属性方法
function Status(identity) {
this.identity = identity
}
function Person(name,age) {
this.name = name
this.age = age
}
var me = new Person('FantasyGao', 22)
Status.call(me,'developer')
//Status.apply(me,['developer'])
//Status.bind(me)('developer')
console.log(me.identity) // developer
// 继承其他构造函数属性方法结合prototype
function Status(identity) {
this.identity = identity
}
function Person(name,age) {
this.name = name
this.age = age
}
Person.prototype = new Status('developer') //利用prototype给Person绑定继承属性
var me = new Person('FantasyGao', 22)
console.log(me.identity) // developer 原型链查找identity
// 原型链指示器错误修正
console.log(Person.prototype.constructor) // Status
Person.prototype.constructor = Person
console.log(Person.prototype.constructor) // Person
// 拷贝继承
function deepCopy(obj,newObj={}){
for(var k in obj){
newObj[k]=obj[k]
if(typeof(obj[k])==='object'){
newObj[k]=(obj[k].constructor===Array)?[]:{}
deepCopy(obj[k],newObj[k])
}else {
newObj[k]=obj[k]
}
}
return newObj
}
var myObj={
name:'FantasyGao',
details:{
sex:'男',
data:[
2,
4,
6
]
},
func:function() {
this.status = 'func’s status'
}
}
var myO= deepCopy(myObj)
var my1= deepCopy(myObj)
console.log(myO==my1) //false
7、ES6中的class继承
class Person {
constructor(name, sex) {
this.name = name;
this.sex = sex;
}
print() {
return `my name is ${this.name}`;
}
}
class Someone extends Person {
constructor(name, sex, girlFriend) {
super(name, sex);
this.girlFriend = girlFriend
}
print() {
console.log(super.print());
console.log(`${this.name} have a ${this.girlFriend}`);
}
}
const me = new Someone('FantasyGao', '男', 'Demi');
me.print() //my name is FantasyGao "FantasyGao have a Demi"
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
如上内容均为自己总结,难免会有错误或者认识偏差,如有问题,希望大家留言指正,以免误人,若有什么问题请留言,会尽力回答之。如果对你有帮助不要忘了分享给你的朋友或者点击右下方的“在看”哦!也可以关注作者,查看历史文章并且关注最新动态,助你早日成为一名全栈工程师!