原型链是js面向对象的基础,非常重要。
一,创建对象的几种方法:
1,字面量
var o1 = { name:'o1' };
2,构造函数
var M = function(name){ this.name = name; }; var o2 = new M('o2');
var a = {} 其实是 var a = new Object()的语法糖,推荐使用前者
var a = [] 其实是 var a = new Array()的语法糖,推荐使用前者
function Foo(){} 其实是 var Foo = new Function()的语法糖,推荐使用前者
3,Object.create(
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 )
var P = {name:'o3'}; var o3 = Object.create(P);
二,原型链
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
Object.getPrototypeOf(Object.prototype) //null
Object.prototype === Object.getPrototypeOf( {} ); //true
5条原型规则
1,所有的引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性
2,所有的引用类型(数组,对象,函数),都有一个__proto__属性(隐式原型),属性值是一个普通的对象
3,所有的函数,都有一个prototype属性(显式原型),属性值也是一个普通的对象
4,所有的引用类型(数组,对象,函数)__proto__属性值指向它的构造函数的prototype属性值
5,当试图得到一个引用类型(数组,对象,函数)的某个属性时,如果这个引用类型本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找
看下图
三,instanceof原理
判断一个函数是否是一个变量的构造函数
工作原理:判断实例对象的__proto__属性和构造函数的prototype是否同一个地址,只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数。如图:
// 判断实例对象的proto属性和构造函数的prototype是否同一个地址 // 只要在原型链上的构造函数,都会被instanceof认为是实例的构造函数 var M = function(name) { this.name = name; }; var o2 = new M('o2'); o2.__proto__ === M.prototype //true M.prototype.__proto__ === Object.prototype //true o2.__proto__.__proto__ === Object.prototype //true o2 instanceof M //true o2 instanceof Object //true // 用constructor属性判断更严谨 o2.__proto__.constructor === M //true o2.__proto__.constructor === Object //false
四,new运算符工作原理
// new运算符及背后工作原理 new后跟构造函数 // 1,一个新对象被创建,它继承自func.prototype(构造函数的原型对象) // 2,构造函数func被执行,执行的时候,相应的传参会被传入,同时上下文(this)会被指定为这个新实例 // 3,如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果,如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象 var new2 = function(func) { var o = Object.create(func.prototype); var k = func.call(o); if (typeof k === 'object' && k != null) { return k; } else { return o; } };
五,原型链继承的例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>proto</title> </head> <body> <div id="div1">123</div> <script> // 封装DOM查询 function Elem(id) { this.elem = document.getElementById(id); } Elem.prototype.html = function(val) { var elem = this.elem; if (val) { elem.innerHTML = val; return this;//方便链式操作 } else { return elem.innerHTML; } } Elem.prototype.on = function(type, fn) { var elem = this.elem; elem.addEventListener(type, fn); return this;//方便链式操作 } var div1 = new Elem('div1'); console.log(div1.html()); div1.html('<p>234p</p>').on('click', function() { alert('1'); }).html('<p>js</p>'); </script> </body> </html>