构造函数、js原型、原型链、继承

构造函数

构造函数分为 实例成员 和 静态成员

实例成员: 实例成员就是在构造函数内部,通过this添加的成员。实例成员只能通过实例化的对象来访问。
静态成员: 在构造函数本身上添加的成员,只能通过构造函数来访问

    function Star(name,age) {
        //实例成员
        this.name = name;
        this.age = age;
    }
    //静态成员
    Star.sex = '女';

    let stars = new Star('小红',18);
    console.log(stars);      // Star {name: "小红", age: 18}
    console.log(stars.sex);  // undefined     实例无法访问sex属性

    console.log(Star.name); //Star     通过构造函数无法直接访问实例成员
    console.log(Star.sex);  //女       通过构造函数可直接访问静态成员
通过构造函数创建对象

通过构造函数创建一个对象

 function Father(name) {
     this.name = name;
 }
 let son = new Father('Lisa');
 console.log(son); //Father {name: "Lisa"}

new的过程

(1) 创建一个空对象 son {}
(2) 为 son 准备原型链连接 son.__proto__ = Father.prototype
(3) 重新绑定this,使构造函数的this指向新对象 Father.call(this)
(4) 为新对象属性赋值 son.name
(5) 返回this,此时的新对象就拥有了构造函数的方法和属性了
在构造函数上直接定义方法(不共享)
    function Star() {
        this.sing = function () {
            console.log('我爱唱歌');
        }
    }
    let stu1 = new Star();
    let stu2 = new Star();
    stu1.sing();//我爱唱歌
    stu2.sing();//我爱唱歌
    console.log(stu1.sing === stu2.sing);//false

在构造函数上通过this来添加方法的方式来生成实例,每次生成实例,都是新开辟一个内存空间存方法。

通过原型添加方法(共享)
    function Star(name) {
        this.name = name;
    }
    Star.prototype.sing = function () {
        console.log('我爱唱歌', this.name);
    };
    let stu1 = new Star('小红');
    let stu2 = new Star('小蓝');
    stu1.sing();//我爱唱歌 小红
    stu2.sing();//我爱唱歌 小蓝
    console.log(stu1.sing === stu2.sing);//true

构造函数通过原型添加的函数,是所有对象共享的。

定义构造函数

公共属性定义到构造函数里面,公共方法我们放到原型对象身上。

原型、原型链

 function Star(name) {
        this.name = name;
    }
console.log(Star.prototype)//{constructor: ƒ Star(name)}
console.log(Star.prototype.constructor === Star);//true

Star.prototype 就是原型。原型的作用,就是共享方法。

原型与原型层层相链接的过程即为原型链。对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在

function Star(name,age) {
    this.name = name;
    this.age = age;
}
Star.prototype.dance = function(){
    console.log('我在跳舞',this.name);
};
let obj = new Star('张萌',18);
console.log(obj.__proto__);  //{dance: ƒ, constructor: ƒ}
console.log(obj.__proto__ === Star.prototype);//true
console.log(obj.__proto__.constructor);  // Star
console.log(obj.__proto__.constructor === Star); //true
原型链图
prototype
实例化
__prote__
constuctor
构造函数Function
Funtion的原型对象
实例对象Object
原型查找顺序

(1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法。

(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。

(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。

(4)如果再没有,则会报错。

    function Star(name) {
        this.name = name;

        (1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法
        this.dance = function () {
            console.log(this.name + '1');
        }
    }

    (2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。
    Star.prototype.dance = function () {
        console.log(this.name + '2');
    };

    (3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。
    Object.prototype.dance = function () {
        console.log(this.name + '3');
    };
    (4)如果再没有,则会报错。
    let obj = new Star('小红');
    obj.dance();

继承

ES5

利用call改变this指向,只可以继承属性,实例不可以使用父类的方法。

    function Father(name) {
        this.name = name;
    }
    Father.prototype.dance = function () {
      console.log('I am dancing');
    };
    function Son(name, age) {
        Father.call(this, name);
        this.age = age;
    }
    let son = new Son('小红', 100);
    console.log(Father.prototype) //{dance: ƒ, constructor: ƒ}
    // 利用call改变this指向,只可以继承属性,实例不可以使用父类的方法。
    console.log(son.__proto__) //{constructor: ƒ}
    son.dance();   //报错  son.dance is not a function

Son.prototype = Father.prototype改变原型指向,我们给子类增加原型方法,同样会影响到父类

    function Father(name) {
        this.name = name;
    }
    Father.prototype.dance = function () {
        console.log('I am dancing');
    };
    function Son(name, age) {
        Father.call(this, name);
        this.age = age;
    }
    console.log(Son.prototype)//{constructor: ƒ}
    console.log(Father.prototype)//{dance: ƒ, constructor: ƒ}
    Son.prototype = Father.prototype;
    console.log(Son.prototype)//{dance: ƒ, constructor: ƒ}
    //为子类添加方法
    Son.prototype.sing = function () {
        console.log('I am singing');
    };
    let son = new Son('小红', 100);
    //此时父类也被影响了
    console.log(Father.prototype === Son.prototype) // true
    console.log(Father.prototype) //{dance: ƒ, sing: ƒ, constructor: ƒ}

子类的原型指向父类的实例,共享父类的方法了。为子类添加原型方法的时候,就不会影响父类。

    function Father(name) {
        this.name = name;
    }
    Father.prototype.dance = function () {
        console.log('I am dancing');
    };
    function Son(name, age) {
        Father.call(this, name);
        this.age = age;
    }
    Son.prototype = new Father();
    console.log(new Father().__proto__)//{dance: ƒ, constructor: ƒ}
    console.log(Son.prototype.__proto__)//{dance: ƒ, constructor: ƒ}
    console.log(Son.prototype.__proto__ === Father.prototype)//true
    Son.prototype.sing = function () {
        console.log('I am singing');
    };
    let son = new Son('小红', 100);
    console.log(son.__proto__.__proto__) //{dance: ƒ, constructor: ƒ}
    console.log(Father.prototype) //{dance: ƒ, constructor: ƒ}

如有疑惑,请查看原型查找顺序

prototype
实例化
prototype
__proto__
Son构造函数
Son的原型对象
Father实例对象
Father构造函数
Father原型对象

类的本质还是一个函数,类就是构造函数的另一种写法。

function Star(){}
console.log(typeof Star); //function

class Star {}
console.log(typeof Star); //function

类的所有方法都定义在类的prototype属性上面

    class Father{
        constructor(name){
            this.name = name;
        }
        sing(){
            return this.name;
        }
    }
    let red = new Father('小红');
    let green = new Father('小绿');
    console.log(red.sing === green.sing); //true
    class Father{
        constructor(name){
            this.name = name;
        }
        sing(){
            return this.name;
        }
    }
    //在原型上追加方法
    Object.assign(Father.prototype,{
        dance(){
            return '我爱跳舞';
        }
    });
    let red = new Father('小红');
    let green = new Father('小绿');
    console.log(red.dance());//我爱跳舞
    console.log(red.dance === green.dance); //true

一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

ES6
    class Father {
        constructor(name){
            this.name = name;
        }
        dance(){
            return '我在跳舞';
        }
    }
    class Son extends Father{
        constructor(name,score){
            super(name);
            this.score = score;
        }
        sing(){
            return this.name +','+this.dance();
        }
    }
    console.log(Son.prototype)//Father {constructor: ƒ, sing: ƒ}
    console.log(Son.prototype.__proto__)//{constructor: ƒ, dance: ƒ}
    let obj = new Son('小红',100);//'小红,我在跳舞'

构造函数特点:

1.构造函数有原型对象prototype。

2.构造函数原型对象prototype里面有constructor,指向构造函数本身。

3.构造函数可以通过原型对象添加方法。

4.构造函数创建的实例对象有__proto__原型,指向构造函数的原型对象。

类:

1.class本质还是function

2.类的所有方法都定义在类的prototype属性上

3.类创建的实例,里面也有__proto__指向类的prototype原型对象

4.新的class写法,只是让对象原型的写法更加清晰,更像面向对象编程的语法而已。

5.ES6的类其实就是语法糖。

prototype
__proto__
__proto__
Object
Object.prototype
null
Function.prototype
prototype
__proto__
Function
Function.prototype
Object.prototype
new
prototype
__proto__
constructor
Father函数
son
Father.prototype
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值