JavaScript面向对象---封装和继承

函数中运行时发生了什么

函数运行时,会自动绑定两个变量 arguments 和 this

arguments:一个实参的类数组对象
function Aoo(a, b){ 
    console.log(arguments);
}
// 这里的a,b是形参

Aoo(1, 2, 3, 4) // 1,2,3,4
//这里的arguments就是1,2,3,4 这个就是实参
this: 函数运行时的上下文

谁调用这个方法,this就指向谁

function Aoo(){
    console.log(this);
}
let obj = {
    fn: Aoo,
    obj2: {
        fn: Aoo
    }
}
Aoo(); // window 在浏览器环境下
obj.fn(); // obj
obj.obj2.fn(); // obj2
改变this指向的方法

function.call(obj,arg1,arg2,....)
function.apply(obj,[arg1,arg2,....])

function Aoo(){
    console.log(this.name)
}
window.name = 'window'
Aoo();// window

let obj = {
    name: 'objName'
}
Aoo.call(obj) // objName
Aoo.apply(obj) // objName

// 如果后面带参数的话
function Boo(arg1,arg2){
       this.a = arg1;
       this.b = arg2;
       console.log(this);
}
Boo('1', '2');//window.a === '1' windwo.b === '2'
let obj2 = {
    name: 'obj2'
}
Boo.call(obj2, '1', '2') //{name: "obj2", a: "1", b: "2"}
Boo.apply(obj2, ['1', '2']) //{name: "obj2", a: "1", b: "2"}

new 一个对象时发生了什么

首先,我们需要知道JS的原型链

function Person(name){
    this.name = name;
}
// 我们将Person这个函数的公共方法写在prototype上,后面通过Person函数new出来的实例都可以使用这些方法
Person.prototype.introduct = function(){
    console.log(`Hello, my name is ${this.name}`)
}
let p = new Person('jack');
let p2 = new Person('rose');
p.introduct();//Hello, my name is jack
p2.introduct();//Hello, my name is rose
// 为什么可以实现呢
// 因为p.__proto__ === Person.prototype,当p实例上找不到introduct这个方法时,就会顺着__proto__去寻找原型对象上是否存在这个方法

了解原型链后,探究一下new一个对象时发生了什么

function Person(name){
    this.name = name;
}
let p = new Person('rose')// {name: "rose", __proto__: Object}
//1.创建一个空对象
    let obj = {};
//2.将这个空对象的__proto__指向构造函数的prototype
    obj.__proto__ = Person.prototype;
//3.将构造函数的this指向这个空对象
//4.运行构造函数
    Person.call(obj, name)
//5.返回这个对象
    return obj;
// 经过这5步,我们就可以产生一个由构造函数new出来的实例

如何实现继承

function Person(name, age){
    this.name = name;
    this.age = age;
}
Person.prototype.introduct = function(){
    console.log(`my name is ${this.name}, my age is ${this.age}`);
}

function Student(hobby){
    this.hobby = hobby;
}
Student.prototype.showHobby = function(){
    console.log(`my hobby is ${this.hobby}`);
}
// 如果Student是Person的一个子类,我们需要如何实现继承
实现继承,我们就应该实现student的实例可以使用Person函数的属性和方法
let s = new Student('Tom', 22, 'javascript');
// 如果只是这样写,是无法在student对象加上name,age属性的
// 因此,我们可以改写Student方法
function Student(name, age, hobby){
    //我们再执行student构造函数的具体方法前先执行Person的构造方法
    Person.call(this, name, age);
    this.hobby = hobby;
}
// 结合new的原理,我们可以知道
/* 
    1. 先生成一个空对象 let obj = {}
    2. obj.__proto__ =  Student.prototype 
    3. 绑定obj到this上
    4. obj执行Person的构造函数
    5. obj执行Student的构造函数
    6. 返回obj
    s: {name: 'Tom', age: 22, hobby: 'javascript'}
    注: 到这里,我们student实例s上有了Person的属性,但是没有protoype上的方法
*/

回头来看

s实例之所以不可以使用Person上的方法,是因为Student函数没有继承.
Student.prototype是一个object,这个实例应该继承Person原型上的方法
所以,Student.prototype.__proto__ = Person.prototype

function Person(name, age){
    this.name = name;
    this.age = age;
}
Person.prototype.introduct = function(){
    console.log(`my name is ${this.name}, my age is ${this.age}`);
}

function Student(name,age,hobby){
    Person.call(this,name,age)
    this.hobby = hobby;
}
Student.prototype.__proto__ = Person.prototype;
Student.prototype.showHobby = function(){
    console.log(`my hobby is ${this.hobby}`);
}

let ss = new Student('yvan', 22, 'node.js');
console.log(ss); 

JavaScript面向对象---封装和继承_第1张图片

ss.introduct();// my name is yvan, my age is 22
ss.showHobby();// my hobby is node.js

你可能感兴趣的:(javascript)