面向对象更贴近我们的实际生活, 可以使用面向对象描述现实世界事物.
面向对象的思维特点:

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

    1.对象

    在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
    对象是由属性和方法组成的
  • 属性:事物的特征,在对象中用属性来表示
  • 方法:事物的行为,在对象中用方法来表示

    2.类

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

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

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

2.1创建类

  1. class name {
  2. // class body
  3. }
  1. var XX = new name();

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

2.2构造函数

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

  1. class Star{
  2. constructor(name,age){
  3. this.name=name;
  4. this.age=age;
  5. }
  6. }
  7. var hg=new Star('胡歌',18)
  8. var xs=new Star('许嵩',20)
  9. console.log(hg)
  10. console.log(xs)

通过 class 关键字创建类,类名我们还是习惯性定义首字母大写
类里面有个 constructor函数,可以接收传递过来的参数,同时返回实例对象
constructor函数只要 new 生成实例,就会自动调用这个函数,如果我们不写这个函数,类也会自动生成这个函数
最后注意语法规范
创建类➡类名后面不要加小括号
生成实例➡类名后面加小括号
构造函数不需要加 function 关键字

2.3类中添加方法

  1. class Person{
  2. constructor(name,age){
  3. this.name=name;
  4. this.age=age;
  5. }
  6. say(){
  7. console.log(this.name+'你好')
  8. }
  9. }
  10. var person=new Person('胡歌',18)
  11. person.say()
  • 类的共有属性放到constructor 里面
  • 类里面的函数都不需要写 function 关键字

2.4类的继承

  1. // 父类
  2. class Father {
  3. }
  4. // 子类继承父类
  5. class Son extends Father {
  6. }
  1. class Father{
  2. constructor(x,y){
  3. this.x=x;
  4. this.y=y;
  5. }
  6. sum(){
  7. console.log(this.x+this.y)
  8. }
  9. }
  10. class Son extends Father{
  11. constructor(x,y){
  12. super(x,y)
  13. this.x=x
  14. this.y=y
  15. }
  16. sub(){
  17. console.log(this.x-this.y)
  18. }
  19. }
  20. var son=new Son(5,3)
  21. son.sum()
  22. son.sub()

2.5super关键字

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

2.5.1调用父类的构造函数

  1. class Person{
  2. constructor(name){
  3. this.name=name
  4. }
  5. }
  6. class Student extends Person{
  7. constructor(name,age){
  8. super(name)
  9. this.age=age
  10. }
  11. }

2.5.2调用父类的普通函数

  1. class Father{
  2. say(){
  3. return '我是爸爸'
  4. }
  5. }
  6. class Son extends Father{
  7. say(){
  8. return super.say()+'儿子'
  9. }
  10. }
  11. var son = new Son()
  12. console.log(son.say())
  • 多个方法之间不需要添加逗号分隔
  • 继承中属性和方法的查找原则:就近原则,先看子类,再看父类。

    3.构造函数和原型

    在典型的 OOP 的语言中(如 Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但在 ES6之前, JS 中并没用引入类的概念。

ES6, 全称 ECMAScript 6.0 ,2015.06 发版。但是目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能。
在 ES6之前 ,对象不是基于类创建的,而是用一种称为构建函数的特殊函数来定义对象和它们的特征。

创建对象有三种方式

  • 对象字面量
  • new Object()
  • 自定义构造函数
    1. var obj1=new Object();
    2. var obj2={}
    ```javascript function Star(name,age){ this.name=name this.age=age this.sing=function(){
    1. console.log('唱歌')
    } }

var hg = new Star(‘胡歌’,18)

  1. 注意:
  2. 1. 构造函数用于创建某一类对象,其首字母要大写
  3. 1. 构造函数要和new一起使用才有意义
  4. <a name="LeFdz"></a>
  5. ## 3.1静态成员和实例成员
  6. - 静态成员: 在构造函数本身上添加的成员为静态成员,只能由构造函数本身来访问
  7. - 实例成员: 在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
  8. ```javascript
  9. function Star(name,age){
  10. this.name=name
  11. this.age=age
  12. this.sing=function(){
  13. console.log(name+'唱歌')
  14. }
  15. }
  16. var hg = new Star('胡歌',18)
  17. hg.sing()
  18. console.log(Star.age) // undefined
  19. Star.sex='男'//静态成员就是在构造函数本身上添加的成员 sex 就是静态成员
  20. console.log(Star.sex)
  21. console.log(hg.sex) //// undefined 不能通过对象来访问

3.2构造函数的问题

构造函数方法很好用,但是存在浪费内存的问题。
我们希望所有的对象使用同一个函数,这样就比较节省内存

3.3构造函数原型 prototype

构造函数通过原型分配的函数是所有对象所共享的,这样就解决了内存浪费问题
JavaScript 规定,每一个构造函数都有一个prototype属性,指向另一个对象,注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
我们可以把那些不变的方法,直接定义在prototype 对象上,这样所有对象的实例就可以共享这些方法

  1. function Star(name,age){
  2. this.name=name
  3. this.age=age
  4. // this.sing=function(){
  5. // console.log(name+'唱歌')
  6. // }
  7. }
  8. //公共的方法我们放到原型对象身上
  9. Star.prototype.sing=function(){
  10. console.log(this.name+'唱歌')
  11. }
  12. // 一般情况下,我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上
  13. var hg=new Star('胡歌',18)
  14. var xs=new Star('许嵩',18)
  15. console.log(hg.sing === xs.sing) //true
  16. hg.sing()
  17. xs.sing()

3.4对象原型 proto

对象都会有一个属性 proto 指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype 原型对象的属性和方法,就是因为对象有proto原型的存在。
proto对象原型和原型对象 prototype 是等价的
proto对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

  1. console.log(xs.__proto__===Star.prototype) //true

3.5constructor 构造函数

constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数
一般情况下,对象的方法都在构造函数(prototype)的原型对象中设置

  1. function Star(name,age){
  2. this.name=name
  3. this.age=age
  4. // this.sing=function(){
  5. // console.log(name+'唱歌')
  6. // }
  7. }
  8. // Star.prototype.sing=function(){
  9. // console.log(this.name+'唱歌')
  10. // }
  11. Star.prototype={
  12. // // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
  13. constructor:Star,
  14. sing:function(){
  15. console.log(this.name+'唱歌')
  16. },
  17. movie:function(){
  18. console.log(this.name+'演戏')
  19. }
  20. }
  21. var hg=new Star('胡歌',18)
  22. hg.sing()
  23. hg.movie()

3.6原型链查找规则

  1. function Star(name,age){
  2. this.name=name
  3. this.age=age
  4. // this.sing=function(){
  5. // console.log(name+'唱歌')
  6. // }
  7. }
  8. // Star.prototype.sing=function(){
  9. // console.log(this.name+'唱歌')
  10. // }
  11. Star.prototype={
  12. // // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
  13. constructor:Star,
  14. sing:function(){
  15. console.log(this.name+'唱歌')
  16. },
  17. movie:function(){
  18. console.log(this.name+'演戏')
  19. }
  20. }
  21. var hg=new Star('胡歌',18)
  22. hg.sing()
  23. hg.movie()
  24. // 1. 只要是对象就有__proto__ 原型, 指向原型对象
  25. console.log(Star.prototype)
  26. // 2.我们Star原型对象里面的__proto__原型指向的是 Object.prototype
  27. console.log(Star.prototype.__proto__)
  28. console.log(Star.prototype.__proto__===Object.prototype)
  29. // 3. 我们Object.prototype原型对象里面的__proto__原型 指向为 null
  30. console.log(Object.prototype.__proto__)

4.继承

S6 之前并没有给我们提供extends继承

  • 我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承

    4.1call()

    调用这个函数,并且修改函数运行时的 this 指向

    1. fun.call(thisArg,arg1,arg2,......)
  • thisArg:当前调用函数 this 的指向对象

  • arg1,arg2: 传递的其他参数 ```javascript function fn(x,y){ console.log(‘helloworld’) console.log(this) console.log(x+y) } var o={ name:’cheng’ }

// fn(1,2) //call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象 fn.call(o,1,2)

  1. <a name="bdaSS"></a>
  2. ## 4.2借用构造函数继承父类型属性
  3. 核心原理: 通过 call() 把父类型的 this 指向子类型的 this,这样就可以实现子类型继承父类型的属性
  4. ```javascript
  5. //父构造函数
  6. function Father(name,age){
  7. this.name=name
  8. this.age=age
  9. }
  10. //子构造函数
  11. function Son(name,age,score){
  12. //this 指向子构造函数的对象实例
  13. Father.call(this,name,age)
  14. this.score=score
  15. }
  16. var son=new Son('胡歌',18,100)
  17. console.log(son)

4.3借用原型对象继承父类型方法

一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法

  1. //父构造函数
  2. function Father(name,age){
  3. this.name=name
  4. this.age=age
  5. }
  6. Father.prototype.money=function(){
  7. console.log(100000)
  8. }
  9. //子构造函数
  10. function Son(name,age,score){
  11. //this 指向子构造函数的对象实例
  12. Father.call(this,name,age)
  13. this.score=score
  14. }
  15. // var son=new Son('胡歌',18,100)
  16. // console.log(son)
  17. //Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
  18. Son.prototype=new Father();
  19. //如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
  20. Son.prototype.constructor=Son;
  21. //这个是子构造函数专门的方法
  22. Son.prototype.exam=function(){
  23. console.log('考试')
  24. }

4.4 类的本质

class 本质还是 function
类的所有方法都定义在类的 prototype属性上
类创建的实例,里面也有proto指向类的prototype原型对象
所以 ES6 的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
所以 ES6 的类其实就是语法糖
语法糖:语法糖就是一种便捷写法,简单理解
[

](https://blog.csdn.net/Augenstern_QXL/article/details/115219073)

5.ES5新增方法

ES5 给我们新增了一些方法,可以很方便的操作数组或者字符串

  • 数组方法
  • 字符串方法
  • 对象方法

    5.1数组方法

  • 迭代(遍历)方法:foreach() ,map(),filter(),some() ,every() ;

    5.1.1forEach()

    1. array.forEach(function(currentValue,index,arr))
    1. var arr=[1,2,3]
    2. var sum=0
    3. //forEach 迭代(遍历) 数组
    4. arr.forEach(function(value,index,array){
    5. console.log('每个数组元素' + value);
    6. console.log('每个数组元素的索引号' + index);
    7. console.log('数组本身' + array);
    8. sum+=value
    9. })
    10. console.log(sum)

    5.1.2filter()筛选数组

    1. array.filter(function(currentValue,index,arr))
    1. var arr=[1,2,3,4,5,6]
    2. // filter 筛选数组
    3. var newArr=arr.filter(function(value,index){
    4. return value % 2===0
    5. })
    6. console.log(newArr)

    5.1.3some()

  • some()方法用于检测数组中的元素是否满足指定条件(查找数组中是否有满足条件的元素)

  • 注意它返回的是布尔值,如果查找到这个元素,就返回true,如果查找不到就返回false
  • 如果找到第一个满足条件的元素,则终止循环,不再继续查找

    1. var arr=['red','blue','green']
    2. //some 查找数组中是否有满足条件的元素
    3. var flag=arr.some(function(value){
    4. return value === 'green'
    5. })
    6. console.log(flag)

    5.2字符串方法

  • trim()方法会从一个字符串的两端删除空白字符

  • trim()方法并不影响原字符串本身,它返回的是一个新的字符串
    1. var str = ' hello world '
    2. console.log(str)
    3. var str1 = str.trim()
    4. console.log(str1)

    5.3对象方法

    5.3.1Object.keys()

  1. Object.keys()用于获取对象自身所有的属性
  2. 效果类似for…in
  3. 返回一个由属性名组成的数组 ```javascript var obj={ id:1, name:’小米’, price:1999, num:0

} var arr=Object.keys(obj) console.log(arr) arr.forEach(function(value,index){ console.log(value) console.log(index) })

  1. <a name="XeWBC"></a>
  2. ### 5.3.2Object.defineProperty()
  3. Object.defineProperty()定义对象中新属性或修改原有的属性(了解)
  4. ```javascript
  5. Object.defineProperty(obj,prop,descriptor)
  • obj : 目标对象
  • prop : 需定义或修改的属性的名字
  • descriptor : 目标属性所拥有的特性 ```javascript var obj={ id:1, name:’小米’, price:1999, num:0

} console.log(obj) //Object.defineProperty() 定义新属性或修改原有的属性 Object.defineProperty(obj,’num’,{ value:1000, enumerable: true }) console.log(obj) Object.defineProperty(obj,’price’,{ value:9.9,

}) console.log(obj) Object.defineProperty(obj, ‘id’, { //如果值为false 不允许修改这个属性值 默认值也是false writable: false, }); console.log(obj)

  1. ```javascript
  2. Object.defineProperty(obj,'address',{
  3. value:'china',
  4. // 如果只为false 不允许修改这个属性值 默认值也是false
  5. writable:true,
  6. // enumerable 如果值为false 则不允许遍历, 默认的值是 false
  7. enumerable:false,
  8. // configurable 如果为false 则不允许删除这个属性
  9. //不允许在修改第三个参数里面的特性 默认为false
  10. configurable:false
  11. })
  12. console.log(obj)

第三个参数 descriptor 说明:以对象形式{ }书写
value:设置属性的值,默认为undefined
writeable: 值是否可以重写 true | false 默认为false
enumerable: 目标属性是否可以被枚举 true | false 默认为false
configurable: 目标属性是否可以被删除或是否可以再次修改特性 true | false 默认为false

6.函数进阶

6.1函数的定义方式

  1. // 1. 自定义函数(命名函数)
  2. function fn(){}
  3. // 2. 函数表达式 (匿名函数)
  4. var fun=function(){}
  5. //利用 new Function('参数1','参数2', '函数体');
  6. //Function 里面参数都必须是字符串格式,执行效率低,较少写
  7. var f=new Function('a','b','console.log(a+b)')
  8. f(1,2)
  9. console.dir(f)
  10. console.log(f instanceof Object) //true

6.2函数的调用方式

  1. //普通函数
  2. function fn(){
  3. console.log('普通函数')
  4. }
  5. fn()
  6. //对象的方法
  7. var o={
  8. say:function(){
  9. console.log('对象的方法')
  10. }
  11. }
  12. o.say()
  13. //构造函数
  14. function Star(){};
  15. new Star()

6.3改变函数内部this指向

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

6.3.1call() 方法

  1. var o={
  2. name:'cheng'
  3. }
  4. function fn(a,b){
  5. console.log(this)
  6. console.log(a+b)
  7. }
  8. fn.call(o,1,2)
  1. function Father(name, age, sex) {
  2. this.name = name;
  3. this.age = age;
  4. this.sex = sex;
  5. }
  6. function Son(name, age, sex,score) {
  7. Father.call(this,name,age,sex)
  8. this.score=score
  9. }
  10. var xs= new Son('许嵩', 18, '男',100);
  11. console.log(xs);

6.3.2apply()方法

apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值

  • fun.apply(thisArg,[argsArray])
  • thisArg: 在 fun 函数运行时指定的 this 值
  • argsArray : 传递的值,必须包含在数组里面
  • 返回值就是函数的返回值,因为它就是调用函数

    1. var max = Math.max.apply(null, arr);
    1. var arr=[1,2,3,4,5,6]
    2. var max=Math.max.apply(Math,arr)
    3. console.log(max) //6(max)

    6.3.3bind()方法

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

  • 返回由指定的 this值和初始化参数改造的 原函数拷贝
  • 因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind ```javascript var o = { name: ‘cheng’ };

function fn(a, b) { console.log(this); console.log(a + b);

}; //当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind var f=fn.bind(o, 1, 2); f()

var o={ name:’cheng’ } function fn(a,b){ console.log(this) console.log(a+b) } //自动调用函数 fn.call(o,1,2)

```

6.3.4总结

相同点:

  • 都可以改变函数内部的 this指向

区别点:

  • call和apply会调用函数,并且改变函数内部的this指向
  • call和apply传递的参数不一样,call 传递参数,apply 必须数组形式
  • bind不会调用函数,可以改变函数内部this指向

主要应用场景

  1. call经常做继承
  2. apply经常跟数组有关系,比如借助于数学对线实现数组最大值与最小值
  3. bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向