function A(){ this.a = '1'; this.b = '2'; this.init(); } A.prototype.init = function(){ console.log('000000'); } new A()
上面的这个可以输出000000
,而下面这个就不行:
function A(){ this.a = '1'; this.b = '2'; this.init(); } A.init = function(){ console.log('000000'); } new A()
这是为什么呢?
使用new的时候大概就像这个样子:
(摘抄自《JavaScript语言精粹》)
也就是说,先从原型创建一个对象,然后调用构造函数的内容,你这里的话就是执行
这些内容
所以你直接给A加一个init函数是没用的。
prototype可以理解为一个Javascript类的各个对象全部共有的一个属性。通过prototype属性才能调用对象的属性或者方法。
A.init是一个类方法,A.prototype.init是一个成员方法! 类方法必须使用类才能调用!成员方法,只有实现出来的成员才能调用
prototype屬性是保存所有實例方法真正的所在,也就是說諸如toString(),valueOf()等方法實際都是保存在prototype名下。
第一種聲明的init,可以通過new聲明來繼承(偽),第二種不行,因為prototype裡面沒有。
你也可以按照語言精粹方式去理解,但是那不是真實的過程。
因为 new A()的时候,实际上创建出来的是一个对象,你可以把this.init()注释掉。
可以看出,返回的是一个对象,function A(){}实际就是当作一个构造函数来使用,用来生成对象。
而A.init=function()是给A这个函数,函数本身也是个对象,相当于给他绑定了一个属性叫init,init是个函数。
prototype就是原型了,每个函数都有prototype这个属性,这个属性是个对象。
通过构造函数创造出来的对象,都会继承构造函数的原型就是prototype。对象内部有个__proto__指向构造函数的prototype。
关于this,this是JS中的函数内部的一个对象,this就是,谁调用了这个函数,this就指向谁。
![](http://img.php.cn/upload/image/000/000/000/897564a8b2e099f1ed1d04d5897f4115-0.png)
prototype可以搜索一下,我讲的不详细,如果有误,请指正我修改。谢谢了。
实在理解不了的话,我们可以换位思考。
new一个A的实例对象之后,他就继承了构造函数中所有对象都要实现的init方法。可是init在哪呢?构造函数中并没有定义函数体,那么重要的来了,他会沿着原型链往上找,找谁呢?找A.prototype对应的原型对象,看看它,有没有init方法,如果有,则调用,如果没有呢?很简单,继续A.prototype.prototype,以此类推,直到原型对象是null为止。那么真相来了?它有找A.init()这个方法吗?没有,所以,添加在构造函数上的方法,只有A能调用,属于私有的类方法和类变量,实例对象是无法调用的
因为init不在对象的原型链上。
A.prototype在对象的原型链上,而A不在对象的原型链上,所以如果将init定义在A上,对象是找不到的。定义在A.prototype上才能找到。
通过构造函数创建对象,会使用构造函数的prototype属性作为原型。而init不在prototype属性上,是不会继承的。
定义一个function(无论是构造函数还是普通函数),其实也是定义了一个对象(Function对象)。A.init就是给这个function对象定义了一个方法。
而在A里面调用this.init,调用的是另一个对象的方法(new出来的新对象)。
这是你原来的代码: 首先运行代码会出现错误,找不到init方法,为什么呢? 将
new A()
对象打印出来就可以看到,其实init
函数实际上是在constructor
属性上的,并没有在prototype上所以找不到,也不在new A()
对象的原型链上,所以使用this
调用init
就会出错