js 进阶相关知识(1)

188 阅读12分钟

记录自己学习的知识和相关资料,方便以后查阅学习,侵权可删!

js进阶相关知识(1)

1. 面向对象编程介绍

1.1 两大编程思想

面向过程

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以了。

面向过程,就是按照分析好的步骤解决问题。

面向对象

面向对象是把事物分解成一个一个对象,然后由对象之间分工与合作。

面向对象是以对象功能来划分问题,而不是步骤。

在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工。

面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更适合多人合作的大型软件项目。

面向对象的特性:

① 封装性

② 继承性

③ 多态性

面向过程和面向对象的对比

面向过程(推荐:简单项目,步骤简单)

● 优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程。

● 缺点:没有面向对象易维护、易复用、易扩展

面向对象(推荐:大程序,多人合作,维护、复用方便)

● 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护。

● 缺点:性能比面向过程低

2. ES6 中的类和对象

面向对象的思维特点:

  1. 抽取(抽象)对象共用的属性和行为组织(封装)成一个(模板)
  2. 对类进行实例化,获取类的对象

2.1 对象

对象是一个具体的事物

在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象。(例如:字符串、数值、数组、函数等。)

对象由属性方法组成:

● 属性:事物的特征,在对象中用属性来表示(常用名词)

● 方法:事物的行为,在对象中用方法来表示(常用动词)

2.2 类 class

ES6 中新增了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。

抽象了对象的公共部分,它泛指某一大类(class)

对象特指某一个,通过类实例化一个具体的对象

2.3 创建类

语法:

class name {

// class body

}

创建实例:

var xx = new name();

注意:类必须使用 new 实例化对象

2.4 类 constructor 构造函数

constructor()方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过 new 命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给我们创建一个constructor()

注意点:

① 通过 class 关键字创建类,类名习惯性定义首字母大写

② 类里面有个 constructor 函数,可以接受传递过来的参数,同时返回实例对象

③ constructor 函数,只要 new 生成实例时,就会自动调用这个函数,如果我们不写这个函数,类也会自动生成这个函数

④ 生成实例 new 不能省略

⑤ 最后注意语法规范,创建类,类名后面不要加小括号;生成实例时,类名后面加小括号,构造函数不需要加 function

2.5 类添加方法

① 类里面所有的函数不需要写 function

② 多个函数、方法之间不需要添加逗号分隔

3. 类的继承

3.1 继承

程序中的继承:子类可以继承父类的一些属性和方法。

extends 语法:

class Father{ // 父类

}

class Son extends Father{ // 子类继承父类

}

3.2 super 关键字

super关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。

继承中的属性和方法查找原则:就近原则

  1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的方法
  2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)

子类可以继承父类的方法,也可以自己扩展相应的方法

注意:子类在构造函数中使用 super,必须放在 this 前面(必须先调用父类的构造函数,再使用子类构造方法)

ES6 中的类和对象

三个注意点:

  1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象

  2. 类里面的共有的属性和方法一定要加 this 才可以使用

  3. 类里面 this 的指向问题(重点):

    ① constructor 里面的 this 指向的是 创建的实例对象

    ② 方法中的 this 谁调用就指向谁(改变某些特定的 this 指向,可以在定义一个全局变量 that,灵 that = this,来改变 this 的指向问题)

构造函数和原型

创建对象可以通过以下三种方式:

  1. 利用 new Object() 创建对象

    var obj1 = new Object();

  2. 利用 对象字面量创建对象

    var obj2 = {};

  3. 利用构造函数创建对象

    <script>
    function Star(uname, age){
        this.name = name;
        this.age = age;
        this.sing = function(){
            console.log('我会开汽车!');
        }
    }
    
    var zs = new Star('张三', 20)
    var ls = new Star('李四', 21)
    console.log(zs)
    zs.sing();
    ls.sing();
    </script>
    

构造函数

构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,总与 new 一起使用。可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

在 JS 中,使用构造函数时要注意以下两点:

1 构造函数用于创建某一类对象,其首字母要大写

2 构造函数要和 new 一起使用才有意义

new 在执行时会做事件事情:

① 在内存中创建一个新的空对象

② 让 this 指向这个新的对象

③ 执行构造函数里面的代码,给这个新对象添加属性和方法

④ 返回这个新对象(所以构造函数里面不需要 return )

● 静态对象:在构造函数本身上添加的成员称为静态成员, 只能由构造函数本身来访问,不可以通过构造函数来访问实例成员

● 实例成员:在构造函数内部创建的对象成员称为实例成员, 只能由实例化的对象来访问,不可以通过对象来访问

构造函数方法很好用,但是存在浪费内存的问题

构造函数原型 prototype

构造函数通过原型分配的函数是所有对象共享的函数

JavaScript 规定,**每一个构造函数都有一个 prototype 属性,**指向另一个对象。注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。

把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

原型相关问题:

1 原型是什么?

一个对象,也称 prototype 为原型对象

2 原型的作用是什么?

共享方法

对象原型______proto______(这里前后分别是2个下划线)

对象都有一个属性______proto______ 指向构造函数的 prototype 原型对象,对象可以使用构造函数 prototype 原型对象的属性和方法,是因为对象有______proto______原型的存在

●______proto______对象原型和原型对象 prototype 是等价的

●______proto______对象原型的意义是为对象的查找机制提供一个方向,或者是一条路线,但是它是非标准属性,实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

constructor 构造函数

对象原型______proto______构造函数(prototype)原型对象里面都有一个属性 constructor 属性,constructor 称为构造函数,因为它指回构造函数本身。

constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。

如果修改了原来的原型对象,给原型对象赋值的是一个对象,则必须**手动的利用 constructor **指回原来的构造函数

原型链(面试常考!)

例子:

Star构造函数

zs 对象实例

1 zs.______proto______指向Star.prototype

2 Star.prototype.______proto______指向 Object.prototype

3 Object.prototype.______proto______指向 null( 原型链结束!)

JavaScript 的成员查找机制(规则)

按照原型链进行查找

有相同的对象成员时采用就近原则

① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性

② 如果没有就查找它的原型(也就是______proto______ 指向的prrototype 原型对象

③ 如果还没有就查找原型对象的原型(Object 的原型对象

④ 以此类推一直找到Object为止(null)

⑤ ______proto______对象原型的意义就在于为对象成员查找机制提供一个方向或者是一条路线

原型对象 this 指向

1 在构造函数中,里面 this 指向的是对象实例

2 原型对象函数里面的 this,指向的是实例对象

扩展内置对象

可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。

注意:数组和字符串内置对象不能给原型对象覆盖操作 Array.prototype = { } ,只能是 Array.prototype.xxx = function(){ } 的方式。

继承

ES6 之前并没有提供 extends 继承。通过构造函数 + 原型对象模拟实现继承,被称为组合继承。

3.1 call()

作用:

1 可以调用函数

2 改变函数的 this 指向

fun.call(thisArg, arg1, arg2,...)

● thisArg:当前调用函数 this 的指向对象

● arg1 , arg2:传递的其他参数

3.2 借用构造函数继承父类型属性

核心原理:通过 call() 把父类型的 this 指向子类型的 this ,这样就可以实现子类型继承父类型的属性。

Father.call(this) // 把这句话放在子类型中,this指向子类型,相当于继承了父类型属性

利用原型对象继承方法

注意:不能采用父类的原型对象赋值给子类的原型对象的方法,这样会导致子类的原型对象指向父类的原型对象,两者的地址相同,导致子类原型对象特有的方法也出现在父类的原型对象中,导致出错

应该采用,实例化一个父类的对象,达到利用原型对象继承方法的效果:Son.prototype = new Father()

4. 类的本质

1 class 本质还是 function

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

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

4 ES6 的类的绝大部分功能,ES5 都能做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法

5 ES6 的类就是语法糖(ES6 是构造函数的语法糖)

6 语法糖:语法糖就是一种便捷的写法,简单理解,有两种方法可以实现同样的功能,但是一种写法更加清晰、方便,那么这个方法就是语法糖

函数的定义和调用

1.1 函数的定义方式

1 函数声明方式 function 关键字(命名函数)

function fn( ){ };

2 函数表达式(匿名函数)

var fun = function ( ) { }

3 new Function( )

var f = new Function( 'a', 'b', 'console.log(a + b)')

f( 1, 2);

● Function 里面的参数都必须是字符串格式

● 第三种方式执行效率低,也不方便数学,较少使用

● 所有函数都是 Function 的实例(对象)

● 函数也属于对象

1.2 函数的调用方式

1 普通函数

function fn( ){

console.log(' 真的很优秀啊!!!')

}

fn( ); fn.call( )l; //调用函数的方式

2 对象的方法

var o = {

sayHi: function( ){

console.log('真的太棒了!!!')

}

}

o.sayHi( );

3 构造函数

function Star( ){ };

new Star( );

4 绑定事件函数

btn.onclick = function( ){ }; // 点击了按钮就可以调用这个函数

5 定时器函数

setInterval(function( ) { },1000) // 这个函数是定时器自动1秒针调用一次

6 立即执行函数

(function( ){

console.log('真的非常优秀啊!!!')

})( ) // 立即执行函数是自动调用

函数内 this 的指向

这些 this 的指向,是当我们调用函数的时候确定的。

函数调用方式的不同决定了 this 的指向不同,一般指向我们的调用者。

1 普通函数 this 指向 window

2 对象的方法 this 指向 对象

3 构造函数 this 指向 实例对象(原型对象里面的 this 也是指向 实例对象)

4 绑定事件函数 this 指向 函数的调用者

5 定时器函数 this 指向 window

6 立即执行函数 this 指向 window

改变函数内部 this 指向

JavaScript 提供了一些函数方法来处理函数内部 this 的指向问题,常用的有 bind( )、call( )、apply( ) 三种方法

1. call 方法

call( ) 方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。

fun.call(thisArg, arg1, arg2, ... )

① 调用函数

② 改变函数内的 this 指向

call 的主要作用可以实现继承

2. apply 方法

apply( ) 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。

fun.apply( thisArg, [argsArray] )

● thisArg:在 fun 函数运行时指定的 this 值

● argsArray:传递的值,必须包含在数组里面

● 返回值就是函数的返回值,因为它就是调用函数

① 调用函数

② 改变函数内的 this 指向

③ 它的参数必须是数组( 伪数组)

④ apply 的主要应用 比如 apply 与数学内置对象求数组的最大值/最小值

3. bind 方法

bind( ) 方法不会调用函数。但是能改变函数内部 this 指向。

fun.bind( thisArg, arg1, arg2, ...)

● thisArg: 在 fun 函数运行时指定的 this 值

● arg1, arg2:传递的其他参数

● 返回由指定的 this 值和初始化参数改造的原函数拷贝

不调用函数

② 改变函数内的 this 指向

③ 返回的是原函数改变 this 之后产生的新函数