对象
1 function f1(){
2 };
3 typeof f1 //"function"函数对象
4
5
6 var o1 = new f1();
7 typeof o1 //"object"普通对象
8
9 var o2 = {};
10 typeof o2 //"object"普通对象
JavaScript中将对象分为普通对象和函数对象。
使用函数对象可以创建普通对象,普通对象没法创建函数对象。
凡是通过new Function创建的对象都是函数对象,其他都是普通对象(通常通过Object创建),可以通过typeof来判断。
原型对象(prototype)
Prototype
Prototype有原型、蓝本的意思,只有函数对象才会有原型(prototype)。
所谓原型,就是函数用来创建实例(普通)对象的蓝本(原型)。
每个原型都有一个 constructor 属性指向关联的构造函数。
__proto__
每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型(prototype)。
constructor
构造函数,即用来创建实例的函数,即关联的函数对象本身。
验证
在火狐或者谷歌浏览器控制台中新建一个普通对象,查看他的属性。
1 var o = {};
2 console.log(o.prototype); //undefined 普通对象没有prototype属性
3 console.log(o instanceof Object); //true o是Object的实例
4 console.log(o.__proto__ === Object.prototype) //true o的__proto__指向Object的prototype
5 console.log(Object === Object.prototype.constructor) //true Object.prototype.constructor指向Object本身
6 console.log(Object.prototype.constructor) //function Object() 函数对象原型的构造函数指向这个函数
7 console.log(Object.prototype.__proto__); //null Object.prototype的__proto__为null,为原型链终点
新建一个函数对象,查看他的属性。
1 function Demo() { };
2 var f1 = new Demo();
3 console.log(f1.prototype); //undefined 通过函数对象穿创建的是普通对象,Demo本身是函数对象
4 console.log(f1 instanceof Demo); //true f1是Demo的实例
5 console.log(f1.__proto__ === Demo.prototype); //true
6 console.log(Demo === Demo.prototype.constructor);//true
7 console.log(Demo.prototype.__proto__ === Object.prototype);//true Demo原型的__proto__指向Object的原型prototype
8 console.log(Object.prototype.__proto__); //null
原型的重要功能就是用作继承。
原型链(prototype chain)
javascript中,每个对象都会在内部生成一个__proto__ 属性,当我们访问一个对象属性时,如果这个对象不存在就回去__proto__ 指向的对象里面找,一层一层找下去,这就是javascript原型链的概念。
提升:
- 在原型链上查找属性比较耗时,对性能有副作用,这在性能要求苛刻的情况下很重要。另外,试图访问不存在的属性时会遍历整个原型链。
- 遍历对象的属性时,原型链上的每个可枚举属性都会被枚举出来。要检查对象是否具有自己定义的属性,而不是其原型链上的某个属性,则必须使用对象从Object.prototype继承的 hasOwnProperty 方法。(使用 for in 遍历对象时推荐总是使用 hasOwnProperty 方法)
继承
JavaScript 并没有其他基于类的语言所定义的“方法”。在 JavaScript 里,任何函数都可以添加到对象上作为对象的属性。函数的继承与其他的属性继承没有差别。
继承意味着复制操作,在Java和C#中,继承是完全复制生成新的对象。然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。
在编写使用它的复杂代码之前,理解原型继承模型是至关重要的。此外,请注意代码中原型链的长度,并在必要时将其分解,以避免可能的性能问题。此外,原生原型不应该被扩展,除非它是为了与新的JavaScript特性兼容。
参考文档: https://www.jb51.net/article/123976.htm
https://github.com/mqyqingfeng/Blog/issues/2
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance\_and\_the\_prototype\_chain