目录
前言
一、原型的指向问题?
1.要了解原型继承,我们首先要知道原型的指向问题。在这里,我们要弄清楚两个问题:1.原型的指向是否可以改变;2.原型链最终指向哪里。
2.要知道构造函数继承,先要知道call方法
3.要知道拷贝继承,要先知道什么是拷贝
二、继承
1.原型继承
2.构造函数继承
3.拷贝继承
前言
js中的继承并不是真正的继承,而是模拟的继承
一、原型的指向问题?
1.要了解原型继承,我们首先要知道原型的指向问题。在这里,我们要弄清楚两个问题:1.原型的指向是否可以改变;2.原型链最终指向哪里。
1.既然这么问,那肯定是能够改变的
function Person(name, age) {this.name = name;this.age = age;}function Student(sex, name) {this.sex = sex;this.name = name;}console.log(Student.prototype.constructor);Student.prototype = new Person("张三", 18);console.log(Student.prototype.constructor);
打印结果如下:
我们发现原本Student.prototype指向的是Student,当我们用了“Student.prototype=newPerson("张三",18);”后,Student.prototype指向的就是Person
2.我们知道每一个实例的__proto__会指向它的构造函数的prototype属性(这个属性也是对象,也就是原型),他们俩是等同的,一层一层向上找,最终会找到Object,然后再向上找就没有了,所以会返回null
2.要知道构造函数继承,先要知道call方法
call有3(也可以说4)个作用:
1.调用函数
function a() {console.log(111);}a();a.call();//打印效果等同
2.call会改变this的指向,分两种情况,一种是没有参数,一种是有一个参数
//没有参数,this指向window,打印“我叫狗”var Cat = {name: "猫",callName: function () {console.log("我叫" + this.name);},};var name = "狗";Cat.callName.call();//有参数,this指向参数,打印“我叫狗”var cat = {name: "猫",callName: function () {console.log("我叫" + this.name);},};var dog = {name: "狗",};cat.callName.call(dog);
4. call会改变this的指向,有多个参数,this指向第一个参数,剩下的是个参数列表
3.要知道拷贝继承,要先知道什么是拷贝
拷贝分为浅拷贝和深拷贝
按我的理解来说,复制后的改变了里面的内容,原来的值也改变就是浅拷贝;复制后的值改变里面的内容,原来的不受影响就是深拷贝。也就是传址和传值得区别。
深拷贝的4种方法:
// 1.for循环(数组)var f = [1, 2, 3, 4, 5];var g = [];for (var i = 0; i < f.length; i++) {g.push(f[i]);}console.log(g);g.push(100);console.log(g);console.log(f);
// 2.slice(数组)切割var h = [2, 3, 4, 5];var j = h.slice(0);console.log(j);j.push(100);console.log(j);console.log(h);
// 3.concat(数组)拼接var l = [1, 2, 3, 4, 5];var m = [6, 7, 8, 9];var k = l.concat(m);console.log(k);k.push(100);console.log(k);console.log(l);
// 4.for..in(对象)function N(name, age, height, weight) {this.name = name;this.weight = weight;this.age = age;this.height = height;}var q = new N("uzi", 108, "130cm", "150kg");var p = {};for (var key in q) {p[key] = q[key];}console.log(p);p.long = "1cm";console.log(p);console.log(q);
每个的最后都会把拷贝后的添加东西,再去打印被拷贝的,会发现添加的东西并不会出现在里面,说明拷贝后的不会影响被拷贝的
二、继承
1.原型继承
原型继承是通过原型链来实现继承的,上面提到的指向问题说明了原型的指向是可以改变的,当我们想让a去继承b时,就让a的原型去指向b,即a.prototype=new b()
有个动物Animal构造函数,Animal构造函数本身有名字name、体重weight属性,动物Animal的原型中有个吃eat方法,可以吃骨头还有个狗Dog构造函数,Dog构造函数本身有颜色color属性,狗Dog的原型中有个吃咬人bitePerson方法,可以咬人还有个哈士奇ErHa构造函数,ErHa构造函数本身有性别sex属性,哈士奇ErHa的原型中有和主人玩palyHost方法,可以和主人玩要求让实例化的哈士奇的reHa,继承Animal、Dog、ErHa构造函数及原型中所有的属性和方法(请使用原型继承)function Animal(name, weight) {this.name = name;this.weight = weight;}Animal.prototype.eat = function () {console.log("吃骨头");};function Dog(color) {this.color = color;}Dog.prototype = new Animal("二哈", "20kg");Dog.prototype.bitePerson = function () {console.log("咬人");};var ErHa = new Dog("black");console.log(ErHa);console.log(ErHa.color);console.log(ErHa.name);console.log(ErHa.weight);console.log(ErHa.eat);console.log(ErHa.bitePerson);
比如在这道题中,狗就通过原型继承了动物的所有属性,它的实例化对象就有了它与动物的所有属性 。
2.构造函数继承
还是那个问题,如果我们想让a继承b的所有属性和方法,可以在a里面用call调用b(因为b是构造函数,可以调用),利用传参数改变this的指向,在a里面this就是指向a的,这样a就继承了b,不过注意,构造函数a的形参要写全,比如下面的例子中的Cat不能只有一个color
有个动物Animal构造函数,Animal构造函数本身有名字name、体重weight属性、年龄age属性、性别sex属 性,以及吃eat方法。有个猫Cat构造函数,猫Cat构造函数本身有颜色color属性,要求实例化猫cat对象继承动物Animal构造函数所有的属性和方法(请使用构造函数继承)function Animal(name, weight, sex) {this.name = name;this.weight = weight;this.sex = sex;this.eat = function () {console.log("吃吃吃就知道吃");};}console.log(Animal);function Cat(color, name, weight, sex) {this.color = color;Animal.call(this, name, weight, sex);}console.log(Cat);var cat = new Cat("red", "xiaohua", "5kg", "公");console.log(cat);
3.拷贝继承
最简单的继承方式,通过for(var key in 实例对象){继承者[key]=实例对象[key]}就可以让继承者继承实例对象的所有属性和属性值
有个动物animal对象,animal对象本身有名字name、体重weight属性,有个老虎tiger对象,老虎tiger对象本身有性别sex属性,要求实例化老虎tiger对象继承动物animal对象所有的属性(请使用拷贝继承)function Animal(name, weight) {this.name = name;this.weight = weight;}var animal = new Animal("销户", "150kg");function Tiger(sex) {this.sex = sex;}var tiger = new Tiger("母");for (var key in animal) {tiger[key] = animal[key];}console.log(tiger);
如果觉得《js高级之面向对象继承》对你有帮助,请点赞、收藏,并留下你的观点哦!