众所周知,JavaScript是一门面向对象的操做语言,而咱们想要用JavaScript对象化写法的时候,不得不提出一个操做符,叫作new操做符,那么不用new操做符和用new操做符有什么区别呢?javascript
首先,咱们去看下new在JavaScript里面的用法,按照javascript语言精粹中所说,若是在一个函数前面带上new来调用该函数,那么将建立一个隐藏链接到该函数的prototype成员的新对象,同时this将被绑定到那个新对象上。这句话说得很抽象,咱们根据代码来理解。java
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } //没用new关键字 var foo2 = foo(); console.log(foo2);//23 //用new关键字 var foo3 = new foo(); console.log(foo3);//foo {name: "John", age: 23}
经过上面的代码能够明显看出区别,当咱们不用new关键字的时候咱们只是把foo函数运行了一遍,若是有返回值就就得到这个返回值,没有返回值就输出underfind,只是简单的函数运行一遍而已。
可是当咱们用new关键字的时候,咱们就能够看到不一样了,new关键字是生成一个对象,而且生成的对象里面的属性是foo函数公有属性(即只有用this关键字定义的变量),而忽略掉私有变量(即用var定义的变量)和函数返回值,这样上面关于new关键字的解释就好理解了,即经过new操做符建立一个链接到foo函数的对象,对象里包含foo函数里面全部属性和方法。这就是new关键字的做用,而且this是指向咱们当前的对象foo3.chrome
js语言没有类这个概念,因此提出用原型来代替类来实现js面向对象写法。js规定每一个函数都具备prototype对象,而且prototype对象在函数外部是能够访问的,能够经过"prototype.xxx"来为当前函数增长属性和方法,因此prototype属性能够理解为当咱们想为这个函数添加属性或者方法时咱们能够在prototype属性下面添加,而不须要去改变构造函数的代码。编程
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } console.log(foo.prototype);//Object {}
chrome的运行结果以下图:浏览器
能够看到foo函数里的prototype是能够访问的,而且咱们所添加的函数是在prototype对象里的。这样,咱们就能够经过prototype属性向对象添加属性和方法。编程语言
在上面的咱们看到chrome浏览器运行结果的图中,咱们打印foo函数prototype对象能够发现里面包含有constructor属性,因此constructor属性的是prototype对象下的一个属性,即:函数
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } console.log(foo.prototype.constructor == foo);//true
能够看到原型对象下的constructor事指向当前构造函数的,函数在建立时就会自动生成constructor属性来指向当前对象,实例化对象时constructor属性也会一并继承到新的对象下面。this
__proto__属性当咱们经过new关键字构造函数实例化建立一个对象时,这个对象里面含有__proto__属性,__proto__属性指向构造函数prototype属性以及prototype属性下面的对象。即:spa
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } var foo2 = new foo(); console.log(foo2.__proto__ == foo.prototype)//true console.log(foo2.__proto__)//Object {ccc:function(),constructor: foo()}
console.log(foo2.__proto__)在chrome里的运行结果以下图:prototype
能够看到__proto__对象是等于foo.prototype对象的,而且foo.prototype对象下面的方法和属性都已经在实例化对象foo2下的__proto__下面了。
js没有其余面向对象编程语言的多态的概念,因此如何实现多态的概念。这时,js提出了原型链的概念,经过原型链来实现扩展方法以及属性的功能。看以下代码
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } var foo2 = new foo(); foo2.ccc();//John var foo3 = new foo(); foo3.ccc();//John //修改foo3对象下面ccc方法 foo3.ccc = function(){ console.log(this.age); } foo3.ccc();//23
从上面代码实例化对象时新的对象不只克隆了构造的函数属性和方法,也克隆了构造函数原型下的属性以及方法,在foo3对象中,当咱们没有修改ccc方法时,函数会在当前对像下查找,没查找到就会去原型对象里查找该方法,在原型对象里找到了ccc方法,打印出this.name为“John”,当咱们重写了ccc方法时,ccc方法就已经foo3当前对象下面了,因此在当前对象下面找到了ccc方法,运行ccc方法,而且中止查到,不会再继续向下查,因此js原型链会遵循就近查找原则,若是查找不到当前方法会到原型下去查找,查找不到再去原型下面的原型去查找,直到查找到全部原型为止。
咱们答应下foo3对象,console.log(foo3),在chrome运行结果以下图:
能够看出foo3对象下面拥有一个ccc方法,而且在原型对象下面也拥有一个ccc方法,遵循就近查找原则,会找到foo3对象下面的ccc方法,而不会去查到原型对象里的ccc方法。因此经过js的原型链能够修改对象的属性和方法。