颠覆认知的『JavaScript』篇——11 原型与原型链深入、对象继承

一、原型的深入

prototype:构造函数的原型

__proto__:实例化对象的一个属性,指向构造函数的原型

所有对象都有原型,包括原型本身

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

 二、原型链

1. 

实例化对象通过__proto__属性向上查找属性和方法的链条就叫做原型链。

原型链的顶端是Object.prototype,它有一个内置的to String方法。

// Professor原型上添加属性
Professor.prototype.tSkill = 'JAVA';
function Professor() {}
// 实例化一个Professor对象
var professor = new Professor();

// Teacher构造函数原型指向professor对象
Teacher.prototype = professor;
function Teacher() {
  this.mSkill = 'jS/JQ';
  this.success = {
    alibaba: '28',
    tencent: '30'
  }
  this.students = 500;
}

// 实例化一个Teacher对象
var teacher = new Teacher();
// Student构造函数原型指向teacher对象
Student.prototype = teacher;
function Student() {
  this.pSkill = 'HTML/CSS';
}
// 实例化一个Student对象
var student = new Student();
/**
 * 1. student对象没有success属性,沿着原型链向上查找
 * 2.	student.success = student.__proto__.success
 * 3. student.students.baidu = '100'
 * 4. student.success.alibaba = '29'
 */
student.success.baidu = '100';
student.success.alibaba = '29';
/**
 * 1. student对象没有students属性,沿着原型链向上查找
 * 2.	student.students = student.__proto__.student
 * 3. student.students++
 */
student.students++;
console.log(teacher, student);

注意: 对于原始值,student对象是在链条上找student属性,然后找到了就拿到这个值,进行操作后,在自己这个对象中创建这个属性,保存。所以说不会改变链条上的teacher这个对象中student这个属性的值,引用值就会改变。

2. 

访问对象的方法和属性时,优先访问自身的属性和方法,没有就去原型上找。

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

Car.prototype = {
  brand: 'Mazda',
  intro: function () {
    console.log('我是' + this.brand + '车');
  }
}

var car = new Car();

car.intro(); // '我是Benz车'

Car.prototype.intro(); //'我是Mazda车'
//------------------------------------------------------------------------------------------
function Person() {
  this.smoke = function () {
    this.weight--;
  }
}

Person.prototype = {
  weight: 130
}

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

注意:谁调用,this指向谁,第一个是car调用,所以this是car,打印car中的brand。第二个是原型调用,所以打印原型上的。

函数默认返回undefind,构造函数默认是this。返回值可以更改,构造函数只有返回引用值才会有效,原始值还是默认返回this。

三、对象继承

1. 创建对象

var obj1 = {}
console.log(obj1);

var obj2 = new Object(); // 一般不用
console.log(obj2);

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

2. Object.create构建对象

Object.create(proto)指定对象的原型,当参数为null时可以创建出没有原型的对象,
所以说不是所有对象都有原型。

function Obj(){}
Obj.prototype.num=1;
var obj1=Object.create(Obj.prototype);
var obj2=new Obj();
console.log(obj1);
console.log(obj2);



// 创建obj1空对象
// 不是所有的对象都继承于Object.prototype
var obj1 = Object.create(null);
console.log(obj1);
obj1.num = 1;
var obj2 = Object.create(obj1);
console.log(obj2);
console.log(obj2.num);

var obj = Object.create(null);

obj.num = 1;

var obj1 = {
  count: 2
}

obj.__proto__ = obj1;
// 给空对象添加__proto__属性无效
console.log(obj.count); // undefined

注意:proto是系统自带的属性,你可以重写,更改,但是不能自己造出来,就是var obj = Object.create(null);他没有proto这个属性,你造出来也没有继承的作用。

四、toSting方法

1. 原始值、undefind、null没有属性和方法,它们也没有原型。但是原始值可以通过包装类变成一个对象,然后使用这个方法。

var num = 1;
// 原始值没有属性和方法
num.toString();
// new Number(1) -> toString();
var num2 = new Number(num);
console.log(num2.toString());

2. 原型的原型上有一个自带的toSting方法

3. document.write()会调用打印对象的toString方法。

五、call、apply

1. 系统会隐式添加一个call

function test(){
    console.log('a');
}
test.call();

2. 改变this指向





function Car(brand, color) {
  this.brand = brand;
  this.color = color;
  this.run = function () {
    console.log('running');
  }
}

var newCar = {
  displacement: '3.0'
};
// Car.call(newCar, 'Benz', 'red');
Car.apply(newCar, ['Benz', 'red']);
console.log(newCar);
var car = new Car('Benz', 'red');
console.log(car);

call、apply区别就是传入的参数,call是参数,apply是数组,arguments

案例

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

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

function FullCompute() {
  Compute.apply(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(1, 2);
compute.minus(1, 2);
compute.mul(1, 2);
compute.div(1, 2);

六、作业

年龄为多少岁,姓名为xx买了一辆排量为XX的什么颜色的什么牌子的车  call 、apply。
 

function Car(opt) {
  this.displacement = opt.displacement;
  this.color = opt.color;
  this.brand = opt.brand;
}
function Person(opt) {
  this.name = opt.name;
  this.age = opt.age;
  Car.call(this, {
    displacement: opt.displacement,
    color: opt.color,
    brand: opt.brand
  });
  console.log('姓名为' + this.name + '年龄为' + this.age + '买了一辆排量为' + this.displacement + '的' + this.color + '色的' + this.brand + '牌的车');
}

var person = new Person({
  name: '张三',
  age: '24',
  color: 'red',
  displacement: '100',
  brand: 'Benz'
})

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值