在典型的面向对象语言中,如java
都存在类class
的概念,类就是对象的模板,对象就是类的实例。但是在javaScript
语言体系中,是不存在类的概念。javaSCript
中不是基于类,而是通过构造函数
(constructor)和原型链
(prototype chains)实现的。
1.构造函数
所谓构造函数,就是提供一个生成对象的模板并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构,构造函数就是对象的模板,对象就是构造函数的实例。
但是构造函数有一个缺点就是:同一个构造函数的对象实例之间无法共享属性或方法 。
2.prototype(原型)
为了解决构造函数的对象实例之间无法共享属性的缺点,javaScript
提供了prototype
属性。
原型上的所有属性和方法都会被对象实例所共享。
每一个函数都有一个prototype
属性,也只有函数有prototype属性
。
var a = 2;
var a1 = a.prototype; // undefine
var b = {};
var b1 = b.prototype; // undefine
var c = 'fdc';
var c1 = c.prototype; // undefine
var d = function() {};
var d1 = d.prototype; // {constructor: ƒ, ...}
var e = new Object();
var e1 = e.prototype; // undefine
3.原型继承
所有 JavaScript
对象都从原型继承属性和方法。null
除外它没有自己的原型对象。日期对象继承自 Date.prototype
。数组对象继承自 Array.prototype
。
Object.prototype
位于原型继承链的顶端:日期对象、数组对象和 Person 对象都继承自 Object.prototype
。
var Parent = function(name) {
this.name = name
};
Parent.prototype.sayName = function() {
return 'sayName'
};
var childA = new Parent('childA');
var childB = new Parent('childB');
console.log(childA.name); // childA
console.log(childB.name); // childB
console.log(childA.sayName()); // sayName
console.log(childB.sayName()); // sayName
上述代码中,如果将sayName
放在原型prototype
对象上,那么两个实例就会共享同一个方法。对于构造函数来说,prototype是作为构造函数的属性,对于对象实例来说,prototype是对象实例的原型对象,所以prototype既是属性又是对象。
原型对象的属性不是对象实例的属性。对象实例的属性是它继承的构造函数定义的属性。因为构造函数内部有一个this关键字来指定将要生成的对象实例。对象实例的属性其实指向的就是构造函数内部定义的属性。只要修改原型对象上的属性和方法,改动立刻体现在所有对象实例上。因为对象实例是共享原型对象的属性和方法的。
对象实例通过new
关键字实现继承原型构造器的详解
1.以构造器的prototype
属性为原型,创建新对象;
2.将this
(也就是新创建的对象)和调用参数传给构造器去执行;
3.如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return
的对象。
手动实现构造器:
var Parent = function(name) {
this.name = name;
};
Parent.prototype.sayName = function() {
console.log(this.name);
};
// 自定义一个new方法
var newMethod = function (Parent, name) {
/*
Object.create()方法是ECMAScript 5中新增的方法,这个方法用于创建一个新对象。
被创建的对象继承另一个对象的原型,在创建新对象时可以指定一些属性。
语法: Object.create(proto[,propertiesObject])
proto: 对象,要继承的原型
propertiesObject: 对象,可选参数,为新创建的对象指定属性对象
*/
// 1.以构造器的prototype属性为原型,创建新对象,child其实就是this。
var child = Object.create(Parent.prototype);
// 2.将this(chhild)和调用参数传给构造器执行。
var result = Parent.call(child, name);
// 3.如果构造器没有手动返回对象,则返回第一步的对象。
return typeof result === 'object' ? result : child;
}
// 创建实例,讲构造函数parent与形参作为参数传入
var childTest = newMethod(Parent, 'child');
childTest.sayName();
4.constructor
每一个原型对象都有一个constructor
属性指向关联的构造函数。
function Person() {}
console.log(Person === Person.prototype.constructor);
// true
5.proto
每一个javaSCript
对象除了null
,都具有一个属性proto
,这个属性是指向该对象的原型。
function Person() {}
var person = new Person();
console.log(person.__proto__ === Person.prototype);
// true
原型对象的proto指向的是Object的prototype
function Person() {}
console.log(Person.prototype.__proto__ === Object.prototype);
// true
6.原型链
对象与原型之间的指向链条,我们称为原型链。