原型链
在典型的oop的语言中都存在类的概念,对象就是类的模板,对象就是类的实例,但是在ES6之前,JS并没有引入类的概念,在ES6之前对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特征
// 创建一个构造函数 // 构造函数首字母需要大写 // 实例成员就是构造函数内部通过this添加成员uname,age,sing就是实例成员 // 实例成员只能通过实例化的对象来访问 function Star(uname, age){ // 这里的this指向的是实例对象谁是构造函数的实例就会指向谁 this.name = uname; this.age = age; // this.sing = function(){ // console.log(this.uname); // }; }; // 原型的作用就是共享方法 Star.prototype.sing = function(){ console.log(this.uname); console.log("aaa"); }; var ldh = new Star("刘德华",18); var zxy = new Star("张学友",10); Star.prototype.sing();// 构造函数只能通过一步一步来调用sing方法 for (var i in ldh) { console.log(i);//name,age,sing }; // 静态成员 只能在构造函数本身上添加的成员 // 静态成员 只能通过构造函数本身来访问 Star.sex = "男"; console.log(Star.sex);//男 // 构造函数的方法虽然很好用,但是存在浪费内存的问题,每创建一个实例对象都会开辟一个内存空间 console.log(ldh.sing === zxy.sing);// false // 构造函数通过原型分配的函数是所有对象所共享的 // js种规定,每一个构造函数里面都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的属性和方法,都会被构造函数所拥有。 // 我们可以把那些不变的方法,直接定义在prototype对象上面,这样所有的对象的实例就可以共享这些方法 console.log(Star.prototype);// {sing: ƒ, constructor: ƒ} // 在我们实例对象身上系统自动添加一个__proto__指向构造函数的原型对象Star.prototype console.log(ldh.__proto__);// {sing: ƒ, constructor: ƒ} console.log(Star.prototype === ldh.__proto__);// true 放法的查找规则就近原则,首先看看对象身上是否都有sing方法,如果有就执行这个对象上的sing没有就去通过实例的隐示原型到构造函数的显示原型上面查找,最后找到Object.prototype的里面没有的话就返回undefined // __proto__的意义就在于为实例对象的查找机制提供了一个方向,或者说是一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性 ldh.__proto__.a = "aa" console.log(ldh.a);// "aa"可以定义但是实际开发不能用 // constraint返回构造函数 console.log(Star.prototype.constructor); // 很多情况下,我们需要手动的利用construct这个属性指向原来的构造函数 Star.prototype = { chi: function(){ console.log("吃"); }, he: function(){ console.log("喝"); }, constructor: Star //如果我们修改了原来的原型对象,则必须手动的利用construct指向原来的函数 }; console.log(ldh.__proto__);// {a: "aa", sing: ƒ, constructor: ƒ} console.log(Star.prototype);// {chi: ƒ, he: ƒ} for (var i in ldh) { console.log(i);//name,age,sing };