JS高级 ES6的类和对象、ES6之前的构造函数

两大编程思想

面向过程(Process-oriented Programming,POP):

根据解决问题的步骤,用函数一步步地实现这些步骤,再依次调用函数。

 

面向对象编程(Object-oriented Programming,OOP):

将问题分解成一个个功能对象,有对象之间合作来解决问题;

具有 封装性、继承性、多态性 的特性,更加灵活,易复用,易维护。

 

面向对象的思维特点:

  1. 抽取对象共有的属性和行为封装成一个类(模板);
  2. 对这个类进行实例化,创建类的具体对象;
  3. 使用对象的属性和方法,实现功能。

类是对象的模板,对象是类的实例。


 

一、ES6 中的类和对象

对象及其属性、方法的定义 见前文 JS(五)。

ES6 全称 ECMAScript 6.0,在 JS 中引入类的概念。

 

创建类

第一步,创建类 class:

class 类名 { 
      constructor(形参1, ...) { 
            //定义共有属性
            this.uname = 形参1;
      } 
      //定义共有方法
      sing() { ...
      }
}

第二步,类的实例化,创建对象:

var 对象名 = new 类名(实参1, ...);

 

其中使用 构造函数 constructor() 方法用于传递参数,返回到对象实例;

通过 new 生成对象实例时,会自动调用 constructor (不用function)。

 

注意点

ES6 中没有变量提升,所以必须要先定义类,才能通过类实例化对象;(链式?)

类里面共有的属性和方法一定要加 this.属性/方法;

this 指向问题:在一类class 中,constructor 里面的 this 指向的是实例对象,方法里面的 this 指向的是这个方法的调用者。

 

 

类的继承 

子类继承父类的属性和方法:

class Father {
    constructor() {
    }
}

//创建继承父类的子类
class Son extends Father {
    constructor() {
        //调用父类的构造函数
        super(..,..);
    }
}

子类继承了父类后,如果子类和父类有相同的属性或方法,子类会执行自己本身的(就近原则);子类中没有就去调用父类中的。

子类可以扩展自己的方法。

 

super 关键字

在子类中使用,可以调用父类的构造函数,把实参数据传给父类: super (形参1, 形参2,...);

也可以调用父类中的普通函数: super.方法();

如果在子类中要使用 super,也要用 this 设置自己的参数,就要把 super 写在 this 前面。

 

 

 

 

 

二、构造函数和原型

 

创建自定义对象的三种方式:

  1. 对象字面量
  2. new Object()
  3. 自定义构造函数

 

概述

在 ES6 之前,对象不是基于类创建的,是用构造函数创建的。

构造函数主要用来初始化对象,即为对象成员变量赋初值,常与 new 搭配使用;

 

new 执行是完成的任务:

  1. 在内存中创建一个空对象;                                              (会浪费内存)
  2. 让 this 指向这个空对象;
  3. 执行构造函数中的代码,给该空对象添加属性和方法;
  4. 直接返回这个新对象(构造函数里面就不需要return)。
//构造函数
function Star(uname, age,..) {
            this.name = uname;
            this.age = age;
            this.sing = function() {
                ...
            }
        }

//创建对象实例
var ldh = new Star('刘德华', 50);

 

构造函数中的属性和方法称为成员;

分为两类,通过两种方式添加的成员:

静态成员 —— 在构造函数本身上添加的成员,只能由构造对象本身访问;

动态(实例)成员 —— 在构造函数内部创建的对象成员(this.),只能由实例化的对象访问;

 

 

 

原型

构造函数原型 prototype

每一个构造函数都有一个 prototype 属性(也是一个对象);

构造函数可以通过原型 prototype 定义一些方法(函数),被它所有的对象实例所共享。          (共享方法,避免浪费内存)

 

 

对象原型 __proto__

每个对象都会有一个 __proto__ 属性,指向构造函数的  prototype 原型对象;(这就是对象能够共享方法的原因)

实例身上的对象原型 __proto__ 与 构造函数身上的原型 prototype 是等价的;

__proto__ 是属性非标准,不能直接使用,它只是为对象查找机制提供一条路线。

(构造函数的原型对象 prototype 也有 __proto__ 属性)

 

 

构造函数 constructor

构造函数原型对象(prototype)和对象原型(_proto_)里面都有一个 constructor 属性,称为构造函数;

主要用于记录对象引用于哪个构造函数,让原型对象重新指向最初的构造函数本身;

 

原型对象 prototype 的函数里面的 this 指向对象实例(调用者);

在给构造函数原型对象 prototype 添加共享方法时,以对象形式赋值的操作会覆盖掉原来默认存在的 constructor 属性,所以要手动添加 constructor 构造函数:

Star.prototype={
    //手动添加 constructor
    constructor:Star,
    sing: function(){
        ...
    },
    ...
}

 

 

内在关系

构造函数(function)、原型对象 prototype、对象实例之间的关系:

 

原型链

 

JS 的成员查找机制(按原型链)

  1. 访问一个对象的属性或方法时,先查找这个对象自身有没有;
  2. 如果自身没有,就查找对象的原型,即 _proto_ 指向的 prototype 原型对象;
  3. 如果原型中也没有,就查找原型对象的原型,即 Object 原型对象;
  4. 依次向上直到 null 为止。

 

 

扩展内置对象

通过在原型对象中自定义方法,对内置对象(数组Array、字符串String...)进行方法的扩展。

//给数组扩展一个求和的方法
Array.prototype.sum = function() {
    var sum = 0;
    for (var i = 0; i < this.length; i++) {
        sum += this[i];
    }
    return sum;
}

 

 

继承

ES6 是通过 extends 实现继承,而 ES6 之前是通过 构造函数+原型对象 模拟实现继承,称为组合继承。

 

call() 方法,可以调用函数,改变 this 的指向

                                   方法名fn.call ( thisArg, arg1, arg2,... )

其中:thisArg 表示让当前函数fn的 this 指向谁(谁成为调用者);

           arg1、2...表示穿传入的实参。

 

继承属性和方法

function Father(形参) {
    ...
}

function Son(形参) {
    //利用 call() 将 father 的属性继承过来
    Father.call(this, 形参...);
}
    
//利用 new 新建一个实例来继承 father 的方法
Son.prototype = new Father();

//更改了 Son 的原型对象后,还要手动设置好 constructor 属性(指回本身的构造函数)
Son.prototype.constructor = Son;

 

不能用  Son.prototype = Father.prototype;  直接赋值来实现继承;

—— 因为对象属于复杂数据类型,赋值操作是将地址赋值过去,若继续修改Son.prototype,Father.prototype 也一起被改变。

 

 

ES5 新增方法

数组方法

迭代(遍历)方法:

 

                                             arr.forEach ( function( value, index, array ) {...})

函数里面的参数:

value —— 逐个传递数组中的元素;

index —— 逐个传递数组中元素的索引;

array —— 传递整个数组(可不写)。

会自动循环执行,遍历整个数组。

 

                                              arr.filter ( function( currentValue, index, array ) {...})

currentValue —— 传递数组当前元素的值;

用于筛选数组,选出符合条件的数组元素,然后返回(return)这些元素组成的一个新数组。

 

                                              arr.some ( function( currentValue, index, array ) {...})

用于查找数组中是否有符合条件的数组元素,返回 ture 或者 false;

循环查找时,如果找到了第一个符合的元素,就停止循环,返回结果。

 

 

字符串方法

                                             str.trim()

删除字符串两端的空白字符。

 

 

对象方法

                                             Object.keys(obj)

获取对象自身所有的属性,效果类似于 for ( k in obj );

返回的是一个数组。

 

                                           Object.defineProperty(obj, prop, descriptor)

直接在对象 obj 上定义一个新属性 prop,或者修改对象的现有属性,并返回此对象。

都是必需参数:

obj —— 目标对象;

prop —— 要定义或修改的属性名;

descriptor —— 要执行的定义或修改属性操作,以及相关设置,都以对象{ } 形式书写:

Object.defineProperty(obj, 'name', {
    value: 'ldh', //定义新增属性的值,或者修改已有属性的值

    writable: false, //默认false,不允许修改此对象属性(name)

    enumerable: false, //默认false,不允许遍历此对象属性

    configurable: false //默认false,不允许删除此对象属性,并且不允许再次修改此对象属性的configurable
})

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值