js对象继承的几种方式

17 篇文章 0 订阅

 

1.对象冒充

构造函数使用this关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可以使parent这个函数成为children的方法,然后调用它。children就会收到parent的构造函数中定义的属性和方法

var Parent = function (name) {

    this.name = name;

    this.sayHi = function () {

        console.log("hi!"+this.name+".");

    }

}



var Children = function (name) {

    this.method = Parent;//method类似于property,只是这个method指向的必须是方法

    this.method(name);

    delete this.method;

    this.getName = function () {

        console.log(this.name);

    }

}

var p = new Parent("john");

var c = new Children("joe");

p.sayHi();

c.sayHi();

c.getName();

在上面的代码中,在children函数里面调用了parent,将parent赋给了this.method,也就是说此时的this.method指向了parent,下一行代码就执行了this.method,相当于将name传给了parent然后执行了一次,此时children就拥有了parent的属性和方法了。

 

而为什么不直接执行parent呢?而是在里面执行呢?因为在函数内this是指向window(因为函数执行时,实际是window调用了它,也就是window.函数名();那么,里面的this指向当前调用该函数的对象,就是window。)。当把parent赋值给children的method的时候,this就指向了children的实例了。

 

 

2.原型链继承

 

var Parent = function () {

    this.name = "john";

    this.sayHi = function () {

        console.log("hi!"+this.name+".");

    }

};

var Children = function () {

    

};

Children.prototype = new Parent();

var p = new Parent();

var c = new Children();

p.sayHi();

c.sayHi();

在JavaScript中,某个对象中的prototype中所有的属性和方法都会被赋予它对应的实例。

调用 Parent 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。

 

 

 

3.使用call或者apply

这两个函数都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。因为this总是指向调用某个方法的对象,但是使用call和apply的时候,就会改变this的指向。

  window.color = 'red';

        document.color = 'yellow';



        var s1 = {color: 'blue' };

        function changeColor(){

            console.log(this.color);

        }



        changeColor.call();         //red (默认传递参数)

        changeColor.call(window);   //red

        changeColor.call(document); //yellow

        changeColor.call(this);     //red

        changeColor.call(s1);       //blue





var Pet = {

        words : '...',

        speak : function (say) {

            console.log(say + ''+ this.words)

        }

    }

    Pet.speak('Speak'); // 结果:Speak...



    var Dog = {

        words:'Wang'

    }



    //将this的指向改变成了Dog

    Pet.speak.call(Dog, 'Speak'); //结果: SpeakWang

apply的用法:  

 window.number = 'one';

        document.number = 'two';



        var s1 = {number: 'three' };

        function changeColor(){

            console.log(this.number);

        }



        changeColor.apply();         //one (默认传参)

        changeColor.apply(window);   //one

        changeColor.apply(document); //two

        changeColor.apply(this);     //one

        changeColor.apply(s1);       //three

不同点:

 

  • apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。

  • call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

 

4.混合方式

对象冒充方法的主要问题是必须使用构造函数方式。但是使用原型链,就无法使用带有参数的构造函数了。那么如何选择最好的继承方式呢,那就是两者都用。在JavaScript中创建类的最好方式就是用构造函数定义属性,用原型定义方法。

var Parent = function (name) {

    this.name = name;

};

Parent.prototype.sayHi = function () {

    console.log("hi!"+this.name+".");

};

var Children = function (name,age) {

    Parent.call(this,name);//实现继承的关键

   this.age = age;

};

Children.prototype = new Parent();//实现继承的关键

Children.prototype.getAge= function () {

    console.log(this.age);

};

var p = new Parent("john");

var c = new Children("joe",22);

p.sayHi();

c.sayHi();

c.getAge();

 

在上面的代码中,父类和子类中都是在函数体内些属性,将方法些在了prototype属性中,也就是用构造函数定义属性,用原型定义方法。

此外,子类CHildren在构造函数中使用call来继承父类Parent的属性,在原型中继承父类的原型

 

 

5.使用Object.create()方法

var Parent = function (name) {

    this.name = name;

};

Parent.prototype.sayHi = function () {

    console.log("hi!"+this.name+".");

};

var Children = function (name,age) {

    Parent.call(this,name);//实现继承的关键

   this.age = age;

};

Children.prototype = Object.create(Parent.prototype);//实现继承的关键

Children.prototype.constructor = Children;

Children.prototype.getAge= function () {

    console.log(this.age);

};

var p = new Parent("john");

var c = new Children("joe",22);

p.sayHi();

c.sayHi();

c.getAge();

@ 当执行 Children.prototype = Object.create(Parent.prototype) 这个语句后,Children 的 constructor 就被改变为 Parent ,因此需要将 Children.prototype.constructor 重 新指定为 Children 自身。

 

 

6.extends关键字实现

class Parent{

    constructor(name,age){

        this.name = name;

        this.age = age;

    }

    sayHi(){

        console.log("hi "+this.name);

    }

}

class Children extends Parent{



    constructor(name,age,job){

        super(name,age);

        this.job = job;

    }

    getJob(){

        console.log(this.job);

    }

}

let p =  new Parent("john",23);

let c =  new Children("joe",22,"teacher");



p.sayHi();

c.sayHi();

c.getJob();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值