JS中new运算符和原型链继承
看下面的这些东西之前,先好好看看高程的第六章面向对象部分!里面提到了很多基本概念,比如:
只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
对原型所做的修改,能够立即在所有实例中得到反映。
因为new运算符会返回一个指向构造器函数原型的对象,所以通常情况下this就指向返回的这个对象。
其中new运算符创建对象的过程,实际上就是:
- 先克隆Object.prototype对象,得到一个空对象,并把它的prototype属性指向构造器函数的原型对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码
- 返回新对象
在Chrome和Firefox等向外暴露了对象proto属性的浏览器下,我们可以通过下面这段代码理解new运算的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function Person(name){ this.name=name; };
Person.prototype.getName=function(){ return this.name; }; var objectFactory=function(){ var obj=new Object(), //1. 先克隆Object.prototype对象,得到一个空对象 Constructor=[].shift.call(arguments); //把第一个参数赋给Constructor变量 obj.__proto__=Constructor.prototype; //1.指向正确的原型 var ret=Constructor.apply(obj,arguments); //2. 将构造函数的作用域赋给新对象+3. 执行构造函数中的代码 return typeof ret === "object" ? ret : obj; //4. 返回新对象 };
var a=objectFactory(Person,"sven");
console.log(a.name);//sven console.log(a.getName());//sven console.log(Object.getPrototypeOf(a) === Person.prototype);//true
|
然后我们就能理解构造器模式是如何创建对象的了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function Point(x=10,y=6){ this.x=x; this.y=y; } Point.prototype.z=20; Point.prototype.getX=function(){ alert(this.x);//不要忘了这里的this也是动态绑定的 }
var p=new Point();//此时Point函数里的this动态绑定到p对象上,都是给p加的x,y属性
p.getX(); //10 this绑定到p上,相当于alert(p.x) alert(p.__proto__.x); //undefined p.__proto__.getX() //undefiend this绑定到p的原型对象上也就是构造器原型对象上,当然没有x啦 alert(p.z); //20 虽然p对象本身没有z属性,但如果对象无法响应某个请求,它会把这个请求委托给它的构造器的原型
|
相关理解图示:原型继承示意图