1 function foo () { 2 //新创建一个对象,将 this 绑定到该对象上 3 4 //在这里编写我们想要的代码 5 6 //return this; 7 }
不过需要注意的是,new 操作符只接受 Object 类型的值,如果我们手动返回的是基本类型,则还是会返回 this :
1 function foo () {
2 this.x = 1;
3 this.y = 2;
4 return 0;
5 }
6 var obj = new foo(); //{x:1, y:2}
现在我们现在可以将 new 操作符定义成以下方法:
1 function newOpertor (cls, ...args) {
2 var obj = {};
3 cls.apply(obj, args);
4 return obj;
5 }
6
7 function foo (x, y) {
8 this.x = x;
9 this.y = y;
10 }
11
12 var obj = newOpertor(foo, 1, 2); //{x:1, y:2}
JavaScript 中存在类似继承的机制,但是又不是标准面向对象的继承,在 JS 中使用的是原型的机制。要记住,在 JS 中只有对象,没有类,对象的继承是由原型来实现,笼统的来说可以这样理解,一个对象是另一个对象的原型,那么便可以把它比作父类,子类既然也就继承了父类的属性和方法。
1 function foo () {
2 this.x = 1;
3 this.y = 2;
4 }
5
6 foo.prototype.z = 3
7
8 var obj = new foo();
9 console.log(obj.z); //3
[[prototype]] 是函数的一个属性,这个属性的值是一个对象,该对象是所有以该函数为构造器创造的对象的原型。可以把它近似的理解为父类对象,那么相应的,子类自然会继承父类的属性和方法。不过为什么要区分原型继承和类继承的概念呢?标准的面向对象方法,类是不具有实际内存空间,只是一个事物的抽象,对象才是事物的实体,而通过继承得到的属性和方法,同属于该对象,不同的对象各自都拥有独立的继承而来的属性。不过在 JavaScript 当中,由于没有类的概念,一直都是对象,所以我们“继承”的,是一个具有实际内存空间的对象,也是实体,也就是说,所有新创建的子对象,他们共享一个父对象(后面我统称为原型),不会拥有独立的属性:
1 function foo () {
2 this.x = 1;
3 this.y = 2;
4 }
5
6 foo.prototype.z = 3
7
8 var obj1 = new foo();
9
10 console.log(obj1.z); //3
11
12 foo.prototype.z = 2
13
14 console.log(obj1.z); //2
还记得我们之前所说的 new 操作符的原理吗?new 操作符的本质不是实例化一个类,而是引擎贴合习惯了面向对象编程方法的程序员,所以说 [[prototype]] 属性本质上也是 new 操作符的一个副产物。这个属性只在函数上面有意义,该属性定义了 new 操作符产生的对象的原型。除了 [[prototype]] 可以访问到对象原型以外,还有一个非标准的方法,在每一个对象中都有一个 __proto__ 属性,这个属性直接关联到了该对象的原型。这种方法没有写入 W3C 的标准规范,但是却得到了浏览器的广泛支持,许多浏览器都提供了该方法以供访问对象的原型。(个人觉得 __proto__ 比 [[prototype]] 更能体现原型链的本质)