js——prototype、__proto__、constructor
Object
1. Object是一个函数(typeof Object;//function)。Object构造器创建了一个对象包装器
1 //Object{} 2 var o = new Object(null); 3 //Object{} 4 var o = new Object(defined); 5 //Number 6 var o = new Object(1); 7 //Boolean 8 var o = new Object(true);
2. Object.prototype属性是Object的原型对象
3. js中几乎所有objects都是Object的实例,一个object会继承Object.prototype的所有属性,这些属性也可能被屏蔽。
4. JavaScript没有子类对象,原型用于为某些表现为对象的函数创建一个“基类”对象
Constructor
Foo函数在声明时,Foo.prototype有一个默认属性.constructor,这个属性默认指向Foo
它不表示“由。。。构造”!
var a = new Foo(); a.constructor === Foo;//true //a.__proto__ == Foo.prototype //a.constructor被委托给Foo.prototype //Foo.prototype.constructor默认为Foo
对象的constructor默认指向一个函数,这个函数可以通过对象的.prototype引用
__proto__
1. __proto__属性是个可访问的属性,它可以用来访问[[Prototype]]
2. __proto__的使用不被鼓励。它一开始并没有被包含在EcmaScript中,但是浏览器却一定要实现它。为了保证兼容性,未来将会在ECMAScript2015中规范并支持。
更推荐使用Object.getPrototypeOf/setPrototypeOf
3.__proto__ 的实现,get和set:
1 Object.defineProperty(Object.prototype, "__proto__", { 2 get: function(){ 3 return Object.getPrototyperOf(this); 4 }, 5 set: function(o){ 6 Object.setPrototypeOf(this, o); 7 return o; 8 } 9 });
prototype
1. 函数中有prototype对象,非函数没有prototype对象
2. 函数的prototype在new的时候起作用。让new func()出来的对象的__proto__指向func.prototype
3. 那没有自己设置prototype的函数的prototype是什么值?
function a(){} //a.__proto__ -->function(){[native code]} //a.constructor -->function Function{[native code]} //a.prototype.__proto__ -->Object.prototype //a.prototype.constructor --> a
继承和原型链
1. 继承:js只有一个构造器objects。每个object有一个私有属性[[Prototype]],它指向另一个对象,称为它的prototype对象。
2. prototype对象也有它的prototype对象,最后达到null。null没有prototype对象,因此它是原型链的最后节点
3. 原型链:当想要访问一个对象属性时,它从当前对象开始一直沿着它的原型向上访问,直到null
4. 基于原型链的继承
- 继承属性
myObject.foo = "bar";
myObject有foo属性,修改foo的值(屏蔽原型链上的)
myObject无foo属性,沿myObject原型链向上查找,且原型链上有foo属性
-
- 可写:在myObject添加foo属性(屏蔽原型链上的)
- 不可写:语句被忽略/报错(严格模式)
- 是setter:不改变
- 继承方法
与继承属性类似
5. 创建对象的不同方法及原型链
1 //1. 普通语法 2 //o --> Object.prototype 3 var o = {a:1}; 4 //o --> Array.prototype -->Object.prototype 5 var o = [1, 2]; 6 //f --> Function.prototype -->Object.prototype 7 function f(){ 8 return 2; 9 } 10 11 //2. new 12 function Graph(){ 13 this.vertices = []; 14 this.edges = []; 15 } 16 Graph.prototype = { 17 addVertex: function(v){ 18 this.vertices.push(v); 19 } 20 }; 21 //g-->Graph.prototype--> Object.prototype 22 var g = new Graph(); 23 24 //3. Object.create 25 //a-->Object.prototype 26 var a = {a:1}; 27 //b-->a-->Object.prototype 28 var b = Object.create(a); 29 30 //4. class关键字
6. 性能
- 在原型链上查找属性比较耗时,试图访问不存在的属性时会遍历整个原型链
- 遍历对象的属性时,原型链上的每个可枚举属性都会被枚举出来
- hasOwnProperty是js中唯一一个只涉及对象自身属性而不会遍历原型链的方法
- 仅判断值是否为undefined不足以检测一个属性是否存在,它可能存在而值恰好为undefined
var a = { b: undefined }; a.b;//undefined
7. 不好的实践:扩展原生对象的原型
prototype和getPrototypeOf(__proto__)
在函数中有一个属性prototype,它是和new操作符相关的特殊属性。
在内存中创建一个对象,在运行函数前,会把[[prototype]]链接到函数的prototype
var o = new Foo();
等价于:
var o = new Object(); o.[[prototype]] = Foo.prototype; Foo.call(o); //返回o
总的来说:
prototype is for types, while Object.getPrototypeOf() is the same for instance
在prototype中定义的属性可以被new出来的对象共享
我的总结吧~
1. __proto__是每个对象都有的属性,用于访问对象的原型,形成原型链路
2. prototype是函数才有的属性,它在new的时候起作用。
var a = new A();//使得a.__proto__ = A.prototype
3. 为什么要在函数中加一个prototyp属性?(个人理解)
如果不加的话,只能有两种情况:a.__proto__ = A 或者a.__proto__ = A.__proto__
A是一个函数,而a希望是一个对象,这样会使得一个对象有函数的属性,这就不太合理了吧。
4. 与C++类的简单比较
C++ | js |
class A(){ public: A(){} } |
function A(){ } A.prototype={ } |
- C++:定义一个类A,A中包括了一个构造函数A(),并封封装了需要的属性
- js:定义一个function A(){},A有prototype属性,A.prototype中定义需要的属性
- 所以,这两个的构造函数和封装属性的对象有点反过来的意思吧
5. constructor
function A(){}//定义一个函数 A.prototype.constructor == A;//true
下面图的关联关系是从chrome运行结果整理出来的
参考:
1. 《你不知道的javascript》上卷
2. MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
最后,
不企图只看一篇文章然后懂得所有,还是要多翻几篇文章吧。