总是听说面向对象,类,继承,__proto__,prototype,constructor.......于是乎小整理一下。
首先说,JS里的继承是怎么弄的呢?
首先创建类(Person)
var Person = { male: 0, age:0, name:'nothing', say:function(){ console.log('Hello World'); }}
如何创建一个人呢?
var createPerson = function(){ return Object.create(Person);}
创建学生
var Student = createPerson();Student.say() //Hello WorldStudent.__proto__ === Person //trueStudent.constructor === Person //Student的构造器还是Object
从这个可以看出什么呢?可以看出所谓的继承,就是下面的代码而已:
SSSSS.__proto__ = BBBBB
但是呢?也没有prototype啥关系嘛,因为压根就和他没关系,好像也不太好,换一种写法好了。
function Person (props){ this.name = props.name || 'nothing'; this.male = props.male || 0; this.age = props.age || 0; this.say = function(){ console.log('Hello world!'); }}
继续创建student
var Student = new Person();Student.__proto__ === Person.prototype //trueStudent.constructor === Person //trueStudent.say() //Hello world!
从上面代码可以看出,Student继承了Person.
如果我们想改变一下呢?Student.say = function(){ console.log('Hello teacher, my name is ' + this.name);//Hello teacher, my name is nothing}
那好,再创建一个coder类
var Coder = new Person();Coder.say(); //Hello world!
这个不错嘛,这样在想创建Coder的子类,js和html,那就修改一下代码
function Coder (props){ Person.call(this,props); this.tip = props.tip?props.tip.toUpperCase():''; this.intro = function(){ console.log('I know '+(this.tip?this.tip:'nothing')); } this.say= function(){ console.log('hello, my name is ' + this.name); }}var JSer = new Coder({ name:'Tony', age:26, tip:'js'});var htmler = new Coder({ name:'Jermy', age:26, tip:'html'});JSer.say(); //hello, my name is Tonyhtmler.say(); //hello, my name is JermyJSer.intro(); //I know JShtmler.intro();//I know HTML
这样得到了我们想要的结果,验证一下继承关系:
JSer instanceof Coder; //truehtmler instanceof Coder;//trueCoder instanceof Person;//false
这样就不好了,为什么不是继承关系呢?查看一下Coder情况如何?
Coder.__proto__ === Person.prototype; //falseCoder.__proto__ //function () { [native code] }
看来问题就出在这里,写一个中间函数补充一下?
var pass = function(child,parent){ var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child;}
为了实现这一点,参考道爷(就是发明JSON的那个道格拉斯)的代码,中间对象可以用一个空函数F来实现,大神写的代码,就是特么让人深思。
仔仔细细想了下,我个人是这么理解的。首先定义空函数这个不用解释,然后把这个空函数的原型指向为Parent的原型,然后再把Child的原型指向这个新的F对象,一个完美传递;最后,在把Child原型的构造方法定义成Child;华丽的转身,结果如下:function Coder (props){ Person.call(this,props); this.tip = props.tip?props.tip.toUpperCase():''; this.intro = function(){ console.log('I know '+(this.tip?this.tip:'nothing')); } this.say= function(){ console.log('hello, my name is ' + this.name); }}var pass = function(Child,Parent){ var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child;}pass(Coder, Person);var JSer = new Coder({ name:'Tony', age:26, tip:'js'});var htmler = new Coder({ name:'Jermy', age:26, tip:'html'});JSer.say(); //hello, my name is Tonyhtmler.say(); //hello, my name is JermyJSer.intro(); //I know JShtmler.intro();//I know HTMLJSer instanceof Coder; //truehtmler instanceof Coder;//trueCoder instanceof Person;//false
结果还是不对,于是我又在大神的肩膀上垫了一下脚。
var pass = function(Child,Parent){ var F = function(){}; F.prototype = Parent.prototype; Child.__proto__ = new F(); Child.__proto__.constructor = Child;}
结果就正确了......
又查了一下,总结一下:
所有的对象都有__proto__属性,该属性对应该对象的原型.
所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的_proto_属性.
所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例的构造函数.
函数对象和原型对象通过prototype和constructor属性进行相互关联.
虽说弄懂了些表面的东西,实际上最主要的原因还是没明白,那就是原型链到底有什么用呢?
好了,以上就是今天总结的一些内容,希望相互学习帮助,能够在未来更好的工作生活。
信息来源:(↓相关一些对我帮助很大,Git的学习就是在这里看的,说的很详细也很生动↓)