问题: 请看如下代码,若是咱们要建立100个对象,应该怎么建立?
前端
function Person(name, sex) {
this.name = name;
this.sex = sex;
this.drink () {
console.log('我想喝手磨咖啡!!')
}
}
for (let i = 0; i < 100; i++) {
var per = new Person('苏大强', '男');
per.drink();
}
复制代码
从上面的代码能够看出,若是咱们要建立100个Person对象,这样要开一百个内存空间,每次都要调用drink()函数,因为drink()函数都是同样的,每一个内存空间里都有它太过于浪费空间,那咱们怎样才能避免这种状况,减小内存呢?咱们接下来引入原型prototype
程序员
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
//为原型添加方法
Person.prototype.drink = function () {
console.log('我想喝手磨咖啡!!')
}
//实例化对象
let per = new Person('苏大强', '男');
per.drink();
复制代码
咱们运用了原型prototype,能够共享数据,减小内存空间。
浏览器
咱们既然清楚了原型,那咱们再来看看原型链。首先咱们打印一下构造函数Person和实例对象per。
bash
console.dir(Person);//构造函数
console.dir(per);//实例对象
复制代码
从图上看,构造函数中的prototype中的属行和实例对象per中的__proto__中的属性如出一辙,那咱们想一想它们相等吗?咱们能够验证一下。
console.log(per.__proto__ === Person.prototype);
复制代码
由此咱们能够判断出,构造函数Person中的prototype原型和实例对象per中的__proto__原型指向是相同的,咱们通常是先有构造函数再有实例对象,实例对象由构造函数建立,因此说实例对象中的__proto__原型指向的是构造函数中的原型prototype
实例对象中__proto__是原型,浏览器使用的。构造函数中的prototype是原型,程序员使用的函数
那接下来咱们看一幅图来看看原型链究竟是什么?
学习
咱们来分析分析整张图
因此从上图咱们能够获得如下几点:
ui
最终咱们能够得出,原型链:它是一种关系,实例对象和原型对象之间的关系,关系是经过原型__proto__来联系的this
原型改变添加方法也无非就是两种:1.在原型改变前添加加方法。2.在原型改变之后添加方法。
spa
首先,咱们来看第一种:
prototype
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.drink = function () {
console.log('我想喝水!!')
}
function Student(name, sex) {
this.name = name;
this.sex = sex;
}
Student.prototype.eat = function () {
console.log('我想吃东西!!')
}
//改变原型指向
Student.prototype = new Person('人', '男');
let stu = new Student('学生', '女');
stu.drink();
stu.eat();
复制代码
咱们来运行如下:
咱们能够看到图中的信息,stu.eat()不是一个函数,刚才咱们明明将eat()添加到了Student的原型上,怎么如今报错了?
缘由是:因为Student的原型指向改变了,它指向了new Person('人', '男'),而且Person的原型上并无eat(),因此报错,那么第一种状况在原型改变以前添加是错误的!
咱们再来看第二种状况:在原型改变以后添加方法。
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.drink = function () {
console.log('我想喝水!!')
}
function Student(name, sex) {
this.name = name;
this.sex = sex;
}
//改变原型指向
Student.prototype = new Person('人', '男');
//为原型添加方法
Student.prototype.eat = function () {
console.log('我想吃东西!!')
}
let stu = new Student('学生', '女');
stu.drink();
stu.eat();
复制代码
咱们来运行如下:
那么,当原型指向改变以后,原型链会发生怎样的改变呢?
那咱们来们分析如下:
咱们先来分析原型指向改变以前:
//人的构造函数
function Person(name) {
this.name = name;
}
//为原型添加方法
Person.prototype.drink = function () {
console.log('我想喝水!!')
}
//学生的构造函数
function Student(name) {
this.name = name;
}
//为原型添加方法
Student.prototype.eat = function () {
console.log('我想吃东西!!')
}
//实例对象
let per = new Person('老师');
let stu = new Student('学生');
console.dir(Person);//构造函数
console.dir(per);//实例对象
console.dir(Student);//构造函数
console.dir(stu);//实例对象
复制代码
咱们运行如下这段代码:
请看每一个prototype和__proto__,咱们能够获得它们的原型链图:
咱们再来看看原型指向改变以后:
//人的构造函数
function Person(name) {
this.name = name;
}
//为原型添加方法
Person.prototype.drink = function () {
console.log('我想喝水!!')
}
//学生的构造函数
function Student(name) {
this.name = name;
}
//为原型添加方法
Student.prototype.eat = function () {
console.log('我想吃东西!!')
}
//改变学生的原型指向
Student.prototype = new Person('老师');
//实例对象
let stu = new Student('学生');
console.dir(Person);//构造函数
console.dir(new Person('老师'))//实例对象
console.dir(Student.prototype)//Student的原型对象
console.dir(Student);//构造函数
console.dir(stu);//实例对象
复制代码
咱们来看看运行结果:
咱们来分析分析:
这里的序号没有任何意义,至关于起的名字!!!
尚未完,咱们再来看图:
原型链改变完毕!
当实例对象中的属性和原型对象中的属性重名时应该先访问那个?
咱们来看一看代码:
//人的构造函数
function Person(age, sex) {
this.age = age;
this.sex = sex;
}
//为原型添加属性
Person.prototype.sex = "女";
//实例化对象
var per = new Person(10,"男");
console.log(per.sex);
复制代码
看图:
若是在实例对象中找不到呢?咱们来看代码:
function Person(age) {
this.age = age;
}
//为原型添加属性
Person.prototype.sex = "女";
//实例化对象
var per = new Person(10);
console.log(per.sex);
复制代码
咱们来看运行结果:
//js中经过原型来实现继承
//人的构造函数
function Person(name, age, sex) {
this.name = name;
this.sex = sex;
this.age = age;
}
//为原型添加方法
Person.prototype.eat = function () {
console.log("人吃东西");
};
Person.prototype.sleep = function () {
console.log("人在睡觉");
};
Person.prototype.play = function () {
console.log("生活就是编代码!");
};
//学生的构造函数
function Student(score) {
this.score = score;
}
//改变学生的原型的指向便可==========>学生和人已经发生关系
Student.prototype = new Person("小明", 10, "男");
//为原型添加方法
Student.prototype.study = function () {
console.log("学习很累很累的哦.");
};
var stu = new Student(100);
console.log(stu.name);
console.log(stu.age);
console.log(stu.sex);
stu.eat();
stu.play();
stu.sleep();
console.log("下面的是学生对象中本身有的");
console.log(stu.score);
stu.study();
复制代码
看运行结果:
//组合继承:原型继承+借用构造函数继承
//人的构造函数
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.sayHi=function () {
console.log("你好吗?");
};
function Student(name, age, sex, score) {
//借用构造函数:属性值重复的问题
Person.call(this, name, age, sex);
this.score = score;
}
//改变原型指向----继承
Student.prototype = new Person();//不传值
Student.prototype.eat = function () {
console.log("吃东西");
};
//实例对象
var stu = new Student("金仔", 20, "男", "100分");
console.log(stu.name, stu.age, stu.sex, stu.score);
stu.sayHi();
stu.eat();
var stu2=new Student("含仔", 20, "女", "100分");
console.log(stu2.name, stu2.age, stu2.sex, stu2.score);
stu2.sayHi();
stu2.eat();
复制代码
看运行结果:
function Person() {};
Person.prototype.age = 10;
Person.prototype.sex = "男";
Person.prototype.height = 100;
Person.prototype.play = function () {
console.log("玩耍!");
};
var Student = {};
//Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是该对象中的属性或者方法
for (let key in Person.prototype) {
Student[key] = Person.prototype[key];
}
console.dir(Student);
Student.play();
复制代码
请看运行结果:
至此,本片文章的所有内容完毕!本人是一个前端新人,本片文章若哪里有不正确的地方,请各位前端大佬不吝斧正!我们携手共同进步!再次感谢!
另外,本人将要参加实习找工做,如果那位大佬以为小学弟能够的话,请给小学弟一个机会。邮箱:1441398660@qq.com