JavaScript基础12.原型与原型链深入、对象继承

文章详细介绍了JavaScript中的原型和原型链机制,包括对象的原型、原型链的构建、原型链的查找过程以及如何通过Object.create()创建对象。此外,还讨论了原型方法的重写、call和apply方法用于改变this指向的应用,并给出了具体的代码示例,展示了如何在实际编程中实现继承和组合功能。
摘要由CSDN通过智能技术生成

12.1原型

所有的对象都有自己的原型,包括原型本身也有自己的原型

function Car(){}

var car = new Car();
console.log(Car.prototype);
console.log(car);

image.png

12.2原型链

沿着proto去找原型里的属性,一层一层的去继承原型的属性的这条链条叫做原型链

Professor.prototype.tSkill = 'JAVA';
function Professor(){}

var professor = new Professor();

// 原型链继承
Teacher.prototype = professor;
function Teacher(){
  this.mSkill = 'JS/JQ';
}
var teacher = new Teacher();

Student.prototype = teacher;
function Student(){
  this.pSkill = 'HTML/CSS';
}

var student = new Student();
console.log(student);
student.mSkill;	// JS/JQ
student.tSkill;	// JAVA

原型链的顶端是 Object.prototype

原型上的引用值可以修改

Professor.prototype.tSkill = 'JAVA';
function Professor(){}

var professor = new Professor();

Teacher.prototype = professor;
function Teacher(){
  this.mSkill = 'JS/JQ';
  this.success = {
    alibaba: '28',
    tencent: '30'
  }
}
var teacher = new Teacher();

Student.prototype = teacher;
function Student(){
  this.pSkill = 'HTML/CSS';
}

var student = new Student();
student.success.baidu = '100';
student.success.alibaba = '29';
console.log(teacher, student);

原型上的原始值不能修改

祖先原型上的原始值不能修改,修改原始值,会认为是给自己添加一个属性值

Professor.prototype.tSkill = 'JAVA';
function Professor(){}

var professor = new Professor();

Teacher.prototype = professor;
function Teacher(){
  this.mSkill = 'JS/JQ';
  this.students = 500;
}
var teacher = new Teacher();

Student.prototype = teacher;
function Student(){
  this.pSkill = 'HTML/CSS';
}

var student = new Student();
student.students++;
console.log(student.students);
console.log(teacher, student);

image.png

student.students++相当于student.students+1=501,然后将其赋值给student的students

面试题

function Car(){
  this.brand = 'Benz';
}

Car.prototype = {
  brand: 'Mazda',
  intro: function(){ 
    // 这里的 this 指向的是 Car 自己,Car 自己有 brand,所以不回去原型上找了,谁在使用 this 就指向谁
    console.log('我是' + this.brand + '车');
  }
}

var car = new Car();

car.intro(); // Benz

function Person(){
  // this = {
  // 	weight: 129
  // }
  this.smoke = function(){
    this.weight--;
  }
}

Person.prototype = {
  weight: 130
}

var person = new Person();
person.smoke();
console.log(person.weight);
console.log(Person.prototype);
console.log(Person);

image.png

为什么控制台执行函数,函数没有返回值的时候回打印undefined
因为普通函数没有写返回值,默认返回undefined;
构造函数通过实例化以后,返回的是this

自定义的构造函数的构造器指向自定义的构造函数

// 字面量构造
var obj1 = {}; 
console.log(obj1);// Object顶端原型

// 系统内置对象构造,一般不使用
var obj2 = new Object();
console.log(obj2);// Object顶端原型


// 自定义构造函数
function Obj(){}
var obj3 = new Obj();
console.log(obj3);//自定义的构造函数的构造器指向自定义的构造函数

image.png

原型也有原型

function Obj(){}
var obj = new Obj();
console.log(obj.__proto__);

image.png

12.3 Object.create(对象 / null) 创建对象

提供了一个自定义原型的功能

function Obj(){}
Obj.prototype.num = 1;
var obj1 = Object.create(Obj.prototype);
var obj2 = new Obj();
console.log(obj1);
console.log(obj2);
// obj1 和 obj2 产生的效果是一模一样的

image.png

var test = {
  num: 2
}

function Obj(){}
Obj.prototype.num = 1;

// Object.create 提供了一个自定义原型的功能
var obj1 = Object.create(test); 
// 将 test 作为原型传递进来
var obj2 = new Obj();
//new做了什么
//实例化obj2
//调用构造函数Obj的初始化属性和方法
//指定实例对象的原型
console.log(obj1);
console.log(obj2);

image.png

Object.create 把其它的对象作为原型来使用

// 创建 obj1 空对象
var obj1 = Object.create(null);
console.log(obj1); // {} 里面什么都没有,也没有原型

image.png

var obj1 = Object.create(null);
console.log(obj1); 

obj1.num = 1;
var obj2 = Object.create(obj1);
console.log(obj2); // obj1 作为 obj2 的原型传递进来,所以挂载到了 proto 上

image.png

不是所有的对象都继承于 Object.prototype,如 Object.create(null)

var obj = Object.create(null);

obj.num = 1;
console.log(obj); // 没有原型

var obj = Object.create(null);
obj.num = 1;

var obj1 = {
  count: 2
}
// 这只是自己自定义的一个属性,而不是原型
// proto 必须得是系统内置的,可以更改它,但不能自造
obj.__proto__ = obj1; 


console.log(obj);// 没有原型
console.log(obj.count); // undefined
console.log(obj1); 

image.png

undefined 和 null 能否使用 toString 方法

不能,因为 undefined 和 null 不能经过包装类转为 对象,它也没有原型,所以无法继承Object.prototype
原始值是没有属性的。

var num = 1;
var obj = {};
var obj2 = Object.create(null);

document.write(num);//1
// document.write 是一定是经过一个隐式转换,转换为 string 的

document.write(obj); // [object Object]: 对象形式的 Object

document.write(obj2); // 报错:cannot convert object to primitie value
// 因为 obj2 里面什么都没有,没有办法继承 Object.prototype,便没有办法使用 toString 方法,所以报错


obj2.toString = function(){
  return '你好';
}
console.log(obj2.toString()); // 你好

12.4原型方法的重写

Obeject.prototype 上有 toString 方法,Number.prototype 上也有自己的 toString方法,这就是对原型方法的重写

Object.prototype.toString.call(1); // '[object Number]':对象类型的 Number 构造函数
Object.prototype.toString.call('a'); // '[object String]'

Number.prototype.toString.call(1); // '1'

包装类(系统内置的构造函数)里都有 toString 方法

为什么Number没有继承Object的toString方法,为什么要自己写一个?
因为 Obeject.prototype 的 toString 打印的值是 [object, 构造函数名],不想要的返回值,所以需要重写一个,是原型里重写了toString 这个方法

12.5call / apply 更改 this 指向

function test(){
  console.log('a');
}
test(); // 相当于 test.call();系统隐式的加了 call

call
第一个参数是一个对象,将使用前面构造函数的属性和方法

    function Car(brand, color){
        this.brand = brand;
        this.color = color;
      //相当于
      //newCar.brand = brand;
      //newCar.color = color;
    }
    var newCar = {};

    Car.call(newCar, 'Benz', 'red');
    console.log(newCar);

image.png
apply
和call一样,后面参数用数组

    function Car(brand, color){
        this.brand = brand;
        this.color = color;
    }
    var newCar = {};

    Car.apply(newCar, ['Benz', 'red']);
    console.log(newCar);

image.png

12.6应用

计算器

function Compute(){
  this.plus = function(a, b){
    console.log(a + b);
  }
  this.minus = function(a, b){
    console.log(a - b);
  }
}

function FullCompute(){
  // 通过 apply 借用 Compute 的功能
  Compute.apply(this); // this代表我的实例
  this.mul = function(a, b){
    console.log(a * b);
  }
  this.div = function(a, b){
    console.log(a / b);
  }
}

var compute = new FullCompute();
compute.plus(3, 5);
compute.minus(3, 5);
compute.mul(3, 5);
compute.div(3, 5);

题目

年龄为多少岁姓名为XX 买了一辆排量为xx的什么颜色的什么牌子的车
利用 call 和 apply 合并 Car 和 Person 两个构造函数,打印出上面的这句话

   function Car(brand, color, displacement) {
        this.brand = brand;
        this.color = color;
        this.displacement = displacement;
        this.info = function(){
            return '排量为' + this.displacement + '的' + this.color
                + this.brand
        }
    }

    function Person(opt) {
        Car.call(this, opt.brand, opt.color, opt.displacement)

        this.name = opt.name;
        this.age = opt.age;
        this.say = function(){
            console.log('年龄' + this.age + '岁姓名为' + this.name + '买了一辆' + this.info());
        }

    }

    var p = new Person({
        name: '张三',
        age: 28,
        brand: '奔驰',
        color: '红色',
        displacement: '3.0'
    });
    p.say();

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值