原型和原型链是js中的难点也是重点,明白了原型和原型链会让我们在后面不管是学习还是工作都会更加高效,并且原型和原型链会是面试中必不可少的话题。
接下来我就说一下我对原型、原型链以及继承的理解,如果有不对的地方,希望可以留言指出。
一、万物皆对象(看似如此) undefined, number, string, boolean四种属于简单的值类型,不是对象,使用基本类型变量可以调用方法是因为产生了包装对象(临时的)。剩下的几种情况——函数、数组、对象、null、new Number(10)都是对象,他们都是引用类型。
二、对象都是通过函数创建的 1、构造函数创建对象
函数也是一个对象,由Function函数创建。
2、字面量创建对象
var obj = { a: 10, b: 20}; var arr = [5, ‘x’,true]; 这类定义其实只是一个下面的语法糖而已
3、Function也是一个对象,由它自己创建,有趣吧
function test() {}; console.log(test instanceof Object); // true很明显函数是一种对象,但你不能说函数是对象的一种。因为他俩之间是没有包含关系的。有点像鸡蛋和鸡的关系
三、所有的函数都有prototype属性(原型)
注意,是函数才有prototype,普通对象没有
函数创建时就自动带有这个属性,也就是我们讲的“原型”,这也绝对是js中最基础也是最难的部分。
这个prototype的属性值是一个对象(属性的集合,再次强调!),默认的只有一个叫做constructor的属性,指向这个函数本身。
prototype可以添加自定义属性,你可以试试Object.prototype,可以看到很多自定义的属性: 四、 所有的对象都有__proto__属性 所有的对象都有__proto__,指向创建它的函数的prototype,注意,你要这样来理解这句话的意思,那就是同一个函数new出来的对象的__proto__都统一指向了这个函数的prototype,根据后面要讲述的原型链规则,也就是说通过这个函数new出来的所有对象都可以直接使用该函数原型上的任意属性和方法!
在Javascript中,每个函数都有一个原型属性prototype指向自身的原型,而由这个函数创建的对象也有一个proto属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个proto指向自己的原型,这样逐层深入直到Object对象的原型,这样就形成了原型链。
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。那么,Object.prototype对象有没有它的原型呢?回答是有的,就是没有任何属性和方法的null对象,而null对象没有自己的原型。
“原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
举例来说,如果让某个函数的prototype属性指向一个数组,就意味着该函数可以当作数组的构造函数,因为它生成的实例对象都可以通过prototype属性调用数组方法
var MyArray = function () { }; // MyArray.prototype = new Array(); var mine = new MyArray(); mine.push(1, 2, 3); mine.length //上面代码中,mine是构造函数MyArray的实例对象,由于MyArray的prototype属性指向一个数组实例,使得mine可以调用数组方法(这些方法定义在数组实例的prototype对象上面)。
大家理解刚才的过程,相信下面这些应该也都明白
//Function function Function(){} console.log(Function); //Function() console.log(Function.prototype.constructor); //Function() console.log(Function.prototype.__proto__); //Object.prototype console.log(Function.prototype.__proto__.__proto__); //NULL console.log(Function.prototype.__proto__.constructor); //Object() console.log(Function.prototype.__proto__ === Object.prototype); //true总结:
查找属性,如果本身没有,则会去__proto__中查找,也就是构造函数的显式原型中查找,如果构造函数中也没有该属性,因为构造函数也是对象,也有__proto__,那么会去它的显式原型中查找,一直到null,如果没有则返回undefined
p.proto.constructor == function Person(){}
p._proto.proto== Object.prototype
p._proto.proto.proto== Object.prototype.proto ==null
通过__proto__形成原型链而非protrotype
原型链继承
原型链继承就是将一个构造函数的原型指向另一个构造函数的实例对象来实现继承。
function Box() { //Box构造 this.name = 'Lee'; } function Desk() { //Desk构造 this.age = 100; } Desk.prototype = new Box(); //Desc继承了Box,通过原型,形成链条 var desk = new Desk(); alert(desk.age); alert(desk.name); //得到被继承的属性