问题:什么是js原型?
js每声明一个function,都有prototype原型,prototype原型是函数的一个默认属性,在函数的创建过程中由js编译器自动添加。
也就是说:当生产一个function对象的时候,就有一个原型prototype。
举个例子:
是不是还看到了一个_proto_的属性?!骚年,你的眼睛不错~待会在解释prototype和_proto_的基友关系!
prototype的属性值是一个对象,是属性的集合,是属性的集合,是属性的集合,重要事情说三遍!
为什么要说他的属性的集合呢?我再来举个例子~:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
alert("使用原型得到Name:"+this.name);
}
var per=new Person("alin",21);
per.sayHello(); //输出:使用原型得到Name:alin
在函数Person里面自定义了属性name和age,而prototype是我们的属性集合,也就是说,我要添加sayHello这个属性到Person,则要这样写:Person.prototype.sayHello,就能添加Person的属性。
(我们可以简单的把prototype看做是一个模板,新创建的自定义对象都是这个模板prototype的一个拷贝,其实准确来说,不应该说是一个拷贝,而是一个连接,只不过这种链接是不可见,新实例化的对象内部有一个看不见的_Proto_指针,指向原型对象)。
使用原型来优化代码:
普通code:
function add(x,y){
return x+y;
}
function subtract(x,y){
return x-y;
}
console.log(add(1,3));
第一种方式用原型优化后:
var Calculator = function(){
};
Calculator.prototype = {
add:function(x,y){
return x+y;
},
subtract:function(x,y){
return x-y;
}
};
console.log((new Calculator()).add(1,3));
第二种方式用原型优化后:
var Calculator = function () {};
Calculator.prototype = function(){
add = function(x,y){
return x+y;
},
subtract = function(x,y){
return x-y;
}
return{
add:add,
subtract:subtract
}
}();
console.log((new Calculator()).add(1,3));
它目的:封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果。
------------------------------------华丽的分割线------------------------------------
js原型链
问题:什么是原型链?
根据《JavaScript高级程序设计》P162页可以作出回答:原型链是实现继承的主要方法。其基本思想是:利用原型让一个引用类型继承另一个应用类型的属性和方法。
简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
JavaScript高级程序设计(第3版)高清完整PDF中文+英文+源码 下载
首先,我觉得有必要先解释一下prototype 和_proto_之间的关系。
每一个基本对象都有自己的_proto_属性,而每一个函数对象都有自己的prototype原型(函数对象也属于基本对象,所以也有_proto_),每当去定义一个prototype的时候,就相当于把该实例的__proto__指向一个结构体,那么这个被指向结构体就称为该实例的原型。 我们还是来看图吧~比较清晰:
var foo = {
x: 10,
y: 20
};
解析:当你定义一个函数对象的时候,其内部就有这样一个链表关系。声明foo对象,自带了_proto_的属性,而这个属性指向了prototype,从而实现对象的扩展(例如继承等操作)。
再看一个例子:
var a = {
x: 10,
calculate: function (z) {
return this.x + this.y + z
}
};
var b = {
y: 20,
__proto__: a
};
var c = {
y: 30,
__proto__: a
};
b.calculate(30); // 60
附上另外说明:
1、一个没有继承操作的函数的_proto_都会指向Object.prototype,而Object.prototype都会指向null。
2、所以,也可以很明显知道,为何null是原型链的终端。
理解了__proto__这个属性链接指针的本质。。再来理解constructor。
prototype默认的有一个叫做constructor的属性,指向这个函数本身。
一般construtor就是我们平时对函数设置的实例化对象