JavaScript中的对象和原型链
原型对象概念:无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个
prototype
属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor
(构造函数)属性,这个属性包含一个指向prototype
属性所在函数的指针。
创建对象的几种方法
-
通过字面量方式创建
var person={ name:'lili', sex:'girl', job:function(){} } person.job();
-
通过object方式创建
var person=new Object({ name:'lili', sex:'girl', job:function(){} });
-
工厂模式创建
function createPerson(name, sex) { var o = {}; o.name = name; o.sex = sex; o.job = function() {}; return o; } var p1 = new Person("lili", "girl"); p1.job();
但是工厂模式有个缺点,就是对象识别问题,即它不知道一个对象的类型。
-
构造函数方式创建
function Person(name,sex){ this.name = name; this.sex = sex; this.job = function(){}; } var p1 = new Person("lili", 29); p1.job();
使用自定义的构造函数,可以将它的实例标识为一种特定的类型,这正是构造函数模式胜过工厂模式的地方。在原型对象中有一个属性
constructor
构造函数,记录了创建该对象的构造函数。 比如(
instanceof
用于检测对象类型):person1 instanceof Person //true 这里可以看到person1也是Person的实例,而工厂模式没有能具体检测对象类型的这一特定 person1 instanceof Object //true 所有对象均继承自Object
对象实例中有一个
__proto__
属性,__proto__
属性等于对象Person的prototype
原型,所以对象实例可以引用对象原型中的方法。 但是构造函数创建对象也有一个缺点,在多次创建实例对象时,对象的方法会多次创建,这样会浪费内存
-
构造函数+原型方法
function Person(name,sex){ this.name = name; this.sex = sex; } Person.prototype.job = function(){}; var p1 = new Person("lili", 29); p1.job();
将构造函数添加到对象原型里,避免创建多个实例多次创建对象方法。
当方法比较多的时候,可以重新设置
prototype
减少代码重复:function Person(name,sex){ this.name = name; this.sex = sex; } Person.prototype = { job: function(){}, say: function(){} }; var p1 = new Person("lili", 29); p1.job();
但这种方法需要两个注意点:
-
重新设置
prototype
使原型对象失去constructor
属性,浏览器回去对象原型的原型中找到object
的constructor
属性,为:Object
对象。解决:Person.prototype = { constructor: Person, job: function(){}, say: function(){} };
-
需要先重新设置
prototype
,再去使用。
-
-
通过
object.create
方式创建var person={ name:'lili', sex:'girl', job:function(){} } var p1=Object.create(person);
被创建的对象继承另一个对象的原型,在创建新对象时可以指定一些属性。
原型链图示
构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
通俗的说就是,实例的__proto__
属性等于构造函数的prototype
,实例__proto__
中的constructor
属性指向构造函数,证明了这个实例是由哪个构造函数创建的。
ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。
其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。