资讯专栏INFORMATION COLUMN

复习Javascript专题(三):面向对象(对象的创建与继承,原型及原型链)

testHs / 579人阅读

摘要:在创建子类实例时,不能向超类型的构造函数中传递参数。构造函数继承子类传进的值是基本思想是在子类构造函数的内部调用超类或父类型构造函数。继承保证构造函数指针指向如果想同时继承多个,还可使用添加属性的方式类继承,

OOP:Object Oriented Programming 面向对象编程。
题外话:面向对象的范围实在太大,先把这些大的东西理解理解。
1.什么是对象?
根据高程和权威指南上的定义,对象是一组没有特定顺序的值,我们可以把对象看成是从字符串到值的映射。
2.怎样理解原型和原型链?

原型:

根据权威指南上的定义:每一个js对象(null除外)都和另一个对象相关联,
“另一个”对象就是我们熟知的原型,每一个对象都从原型上继承属性。原型也是对象。

通俗点讲,就是一个拥有prototype属性、且这个属性指向函数的原型对象的对象。
原型的好处就是:原型上的方法和属性会被所有实例所共享

原型链

当访问某个实例属性或方法时,会先自身对象中查找,查不到时再往当前对象原型上找;
若依然没找到,则会继续往原型对象的原型上找,一直到找到结果或者找到Object.prototype为止也没找到,
然后这时就会返回undefined,这么一个链式查找过程形成的结构就叫原型链。
    

每个对象都有一个__proto__属性,函数也是对象,所以函数也有;
每个函数都有一个prototype属性,而实例对象没有。
3.面向对象的三大特性是什么?
封装,继承,多态(指一个方法可以有多种调用方式:例如有参或无参)
4.创建对象有哪些方式? (1).对象字面量

let obj={};

(2).Object方式

let obj=new Object();

(3).Object.create

let obj=Object.create({}/null);

注意!!前面这三种方式的的构造函数都是Object,而Object已经是原型链的最顶端了,所以Object.prototype都为undefined。

可以用实例的__proto__.constructor查看构造函数是否指向Object构造函数。

(4).工厂模式
    function person(name,job){
        let o={};
        o.name=name;
        o.job=job;
        o.sayName=function(){
            console.log(this.name);
        }
        return o;
    }
    let p1=person("nagi","sleep");
    console.log(p1.constructor); // 指向Object
    p1 instanceof person;  // false;

优缺点:

这种模式虽然解决了量产对象的问题,但却无法获知当前对象是何类型 (例如类型:Array,Math等内置对象,或者BOM(window)/DOM的宿主对象,又或者自定义对象等)

注意点:函数首字母不用大写。

(5).构造函数模式
    function Person(name,job){
        this.name=name;
        this.job=job;
        this.sayName=function(){
            console.log(this.name);
        }
    }
    let p1=new Person("nagi","sleep");
    console.log(p1.constructor); // 指向Person
    p1 instanceof Person;   // true

与工厂模式区别:

a.没有显式创建对象;
b.直接将属性和方法赋给了this对象
c.不有return语句;

拓展:new操作符做了些什么?

a.创建一个新对象;
b.将构造函数的作用域赋给新对象(因此this就指向一这个新对象);
c.执行构造函数中的代码(为这个新对象添加属性);
d.返回新对象(默认返回当前对象,除非有显示返回某个对象)

优缺点:

首先是解决了工厂模式中不能判断类型的问题;
但缺点是每实例一次的同时还会把方法重新创建一遍,造成内存资源浪费;
其次,因构造函数与其它函数的唯一区别就是调用方式不一样,所以当被当作普通函数调用时,其内部的this会指向全局,引发作用域问题。
(6).原型模式
    function Person(){};
    // 写法一:
    Person.prototype.name="nagi";
    Person.prototype.job="sleep";
    Person.prototype.sayName=function(){
        console.log(this.name);
    };
    // 写法二:注意,这种直接更改原型指向的写法,会改变constructor指向,指向Object构造函数
    /* Person.prototype={
    //  constructor:Person,
        name:"nagi",
        job:"sleep",
        sayName:function (){
            console.log(this.name)
        }
    }*/
    let p1=new Person();

优缺点:

优点:解决了上述构造函数的缺点,原型对象上的属性和方法为所有实例所共享。
缺点:
    a.缺点也是所有实例共享方法和属性,因此其中一个实例更改了引用类型的属性值时,其他的实例也会被迫改变。(属性)
    b.默认情况下所有实例都取得相同的属性值。
    
(7).组合模式(结合构造函数和原型模式)
    function Person(name,job){
        this.name=name;
        this.job=job;
    }            
    Person.prototype.sayName=function(){
        console.log(this.name);
    }
    let p1=new Person("nagi","sleep");
4.对象继承方式有哪些? (1).原型链继承
    function Parent(){
        this.name="nagi";
        this.colors=["red","blue","green"];
    }
    Parent.prototype.sayName=function(){
        console.log(this.name);
    }
    function Child(){
        this.job="sleep";
    };
    Child.prototype=new Parent(); 
    // 要注意:这种重写原型链的写法是会切断构造函数与最初原型之间的联系的,
    // 意味着此时Child.prototype.constructor指向Parent
    var child=new Child();        
这种方式的基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。

问题点:

a.上述例子中,通过原型继承方式继承相当于专门创建了一个Child.prototype.colors的属性,
 因为引用类型的原型属性会被所有实例共享,也就意味着Child的所有实例都会共享colors这一属性,
 当其中一实例修改它的值时,那么其他的实例的值也会跟着被改变。
 
b.在创建子类实例时,不能向超类型的构造函数中传递参数。鉴于此,实际很少多带带用原型链继承。
超类型:比如Child类继承了Parent类的属性,那么Parent就是Child的超类(也叫父类)。
(2).构造函数继承(call/apply)
    function Parent(name){
        console.log(`子类传进的name值是:${name}`)
        this.name="nagi";
        this.colors=["red","blue","green"];
    }
    Parent.prototype.sayName=function(){
        console.log(this.name);
    }
    function Child(){
        Parent.call(this,"Bob")
        this.job="sleep";
    };
    var child1=new Child();
    var child2=new Child();
基本思想是在子类构造函数的内部调用超类(或父类)型构造函数。

优缺点:

优势:解决了原型链的两个问题;
缺点:
    a. 方法都在构造函数定义的话,那函数复用就无从谈起了。
    b. 父类在原型中定义的方法,对于子类型来说是不可见的。鉴于此,构造函数也很少用。[捂脸]
(3).组合继承(即原型链+构造函数)
    function Parent(name){
        this.name=name;
        this.job="sleep";
        this.colors=["red","blue","green"];
    }
    Parent.prototype.sayName=function(){
        console.log(this.name);
    }
    function Child(name){
        Parent.call(this,name);
        this.job="eat";
    }
    Child.prototype=new Parent();
    Child.prototype.constructor=Child; 
    let child1=new Child("nagi");
    let child2=new Child("Bob");
其实现思路是用原型链实现对原型属性和方法的继承,而借助构造函数实现对实例属性的继承。

优点:在前两者基础上,补足了构造函数和原型链的缺点,是比较常用的方式。
(4). Object.create继承
    function Parent(name){
        this.name=name;
        this.job="sleep";
        this.colors=["red","blue","green"];
    }
    Parent.prototype.sayName=function(){
        console.log(this.name);
    }
    function Child(){
        Parent.call(this); // 保证构造函数指针指向Child
    }
    Child.prototype=Object.create(Parent.prototype,{name:{value:"nagi"},job:{value:"eat"}})
    // 如果想同时继承多个,还可使用Object.assign()添加属性
    // Object.assign(A.prototype, B.prototype);
    let child=new Child();
(5)ES6的extends方式
类继承,class A extends B

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99321.html

相关文章

  • JS专题继承

    摘要:构造函数所以,就有了畸形的继承方式原型链继承三原型链继承改变构造函数的原型对象继承了属性以上例子中,暴露出原型链继承的两个问题包含引用类型数据的原型属性,会被所有实例共享,基本数据类型则不会。 前言 众所周知,JavaScript 中,没有 JAVA 等主流语言类的概念,更没有父子类继承的概念,而是通过原型对象和原型链的方式实现继承。 于是,我们这一篇讲一讲 JS 中的继承(委托)。 ...

    rollback 评论0 收藏0
  • 面向对象小九九

    摘要:由构造函数返回的对象就是表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤创建的对象。运算符返回一个布尔值,表示对象是否为某个构造函数的实例。 面向对象 本人能力有限,有误请斧正 本文旨在复习面向对象(不包含es6) 本文学习思维 创建对象的方式,获取对象属性 构造函数,构造函数的new 做了什么 原型与原型对象 原型链 继承(借用构造继承、原型继承、组合继承、寄生组合继承)...

    时飞 评论0 收藏0
  • 【重温基础】15.JS对象介绍

    摘要:构造函数通常首字母大写,用于区分普通函数。这种关系常被称为原型链,它解释了为何一个对象会拥有定义在其他对象中的属性和方法。中所有的对象,都有一个属性,指向实例对象的构造函数原型由于是个非标准属性,因此只有和两个浏览器支持,标准方法是。 从这篇文章开始,复习 MDN 中级教程 的内容了,在初级教程中,我和大家分享了一些比较简单基础的知识点,并放在我的 【Cute-JavaScript】系...

    booster 评论0 收藏0
  • 做个JS面向对象笔记

    摘要:组合构造原型模式将自身属性于构造函数中定义,公用的方法绑定至原型对象上原型对象的解释每一个函数创建时本身内部会有一个固有的原型对象,可以通过函数名去访问,而其原型对象又有一个属性指针指向该函数。 每次遇到JS面对对象这个概念,关于继承及原型,脑海里大概有个知识框架,但是很不系统化,复习下,将其系统化,内容涉及到对象的创建,原型链,以及继承。 创建对象 两种常用方式,其余的比较少见工厂模...

    GitCafe 评论0 收藏0
  • JS 原型原型学习

    摘要:所以继承了对象的所有方法,当你用时,会先查一下它的构造函数的原型对象有没有有方法,没查到的话继续查一下的原型对象有没有这个方法。 普通函数与构造函数的区别 在命名规则上,构造函数一般是首字母大写,普通函数遵照小驼峰式命名法。 在函数调用的时候: function fn() { } 构造函数:1. new fn( ) 2 .构造函数内部会...

    PiscesYE 评论0 收藏0

发表评论

0条评论

testHs

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<