构造函数
提到原型就不得不说一下构造函数,我们先来看一个简单的构造函数的例子:
function Foo (name,age) {
this.name = name;
this.age = age;
//return this;
}
var f = new Foo ("zhangsan",20);
var f1 = new Foo ("lisi",21); //创建多个对象
需要说明的是:① 构造函数需以大写字母开头,这样提高了代码的易读性;② return this 那句可有可无,因为它是默认存在的。
在上面的例子中,我们首先创建了一个空对象,再让this指向这个对象,然后执行代码,即给this.name赋值,最后返回this,并将值赋给f和f1。这其实也是new一个对象的过程。
在这里我们稍稍拓展一下构造函数的知识:
① 所有的引用类型都有构造函数
var a = {}其实是var a = new object()的语法糖
var b = []其实是var b = new Array()的语法糖
function Foo() {....}其实是var Foo = new Function()的语法糖
在实际写代码中,我们更推荐使用前者的写法
② 可以使用instanceof判断一个函数是否是一个变量的构造函数,例如
var a = new Array()
alert (a instanceof Array) // true
同时alert (a instanceof Object)也会返回true,这是因为Array是object的子类。再如
function Test () {}
var a = new Test()
alert (a instanceof Test) // true
什么是原型呢?
原型就是一个普通的对象,每个对象都有一个原型(Object除外),原型能存储我们的方法,构造函数创建出来的实例对象能够引用原型中的方法。
Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的。换句话说,在对象创建时会存在预定义的属性,其中有一个属性就是原型对象。
下面,我们来说说原型规则:
① 所有的引用类型(数组,对象,函数)都具有对象特性,即可自由扩展属性(除了“null”)
var obj = {};
obj.a = 100;
var arr = [];
arr.a = 100;
function fn1 () {}
fn1.a = 100;
② 所有的引用类型(数组,对象,函数)都有一个_proto_(隐式原型)属性,属性值也是一个普通的对象
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn1.__proto__);
③ 所有的函数,都有 一个prototype(显式原型)属性,属性值也是一个普通的对象
console.log(fn1.prototype);
④ 所有引用类型(数组,对象,函数)的_proto_属性值指向它的构造函数的prototype属性值
console.log(obj.__proto__ === Object.prototype);
console.log(arr.__proto__ === Array.prototype);
console.log(fn1.__proto__ === Function.prototype);
⑤ 当试图得到一个对象的属性时,如果这个对象本身没有这个属性,那么就会去它的_proto_(即构造函数的prototype)中寻找
//构造函数
function Foo(name) {
this.name = name;
}
Foo.prototype.alertName = function () {
alert(this.name);
}
//创建实例
var f = new Foo("xiaohui");
f.printName = function () {
console.log(this.name);
}
//测试
f.printName();
f.alertName();
就刚才的例子,如果想要循环得到对象本身的属性可以通过for in 实现
var item;
for (item in f) {
//高级浏览器已经在for in中屏蔽了来自原型的属性
//但是还是加上判断,保证程序的健壮性
if (f.hasOwnProperty(item)) {
console.log (item);
}
}
如果现在我想要得到f.toString(),我们会发现f和Foo都没有这个方法,于是就去f._proto._proto(Foo.prototype._proto)中寻找,此时找到并调用。
如图,我们要找f的一个属性时首先会在f._proto中寻找,因为f._proto的属性值是一个对象,所以也有_proto属性,如果没找到,就会去f._proto._proto中找,同理,如果还没找到就继续向上,直到结果为null为止。这个由_proto串起来的直到Object.prototype._proto为null的链就是原型链。
以前一般使用对象的 _proto_属性,ES6推出后,推荐用Object.getPrototypeOf()方法来获取对象的原型 :给定对象的原型。如果没有继承属性,则返回null。
网友评论