js 面向对象3大特点与this

153 阅读1分钟

1.面向对象3大特点

先使用一个个的对象结构集中存储现实中事物的属性和功能。然后,再按需使用不同对象中的不同属性和功能。

优点: 简化大数据了的管理

  • 封装 :
  • 继承
  • 重载

1.1封装

  1. 封装就是创建一个对象,集中保存现实中一个事物的属性和功能。
  2. 将零散的数据封装进对象结构中,极其便于大量数据的管理维护。

封装对象的4种方式

1. 直接量

var 对象名={ //new Object()的简写 
属性名: 属性值, 
... : ... , 
方法名: function(){ ... } 
}

访问方式

  • 对象名.属性名
  • 对象名.方法名()
var obj = {
    name: "jason",
    info: function () {
        console.log(`I'm ${name}`)//这里会报错,函数里的变量不能直接访问对象的属性,
        //会走函数作用域链的逻辑, 依次往上找,到window结束,还是没有找到。
       //这里的obj = {} ,{}只是语法糖的简写,不包含函数作用域。
    }
}}

解决办法

  1. 直接通过 对象.xx 访问
console.log(`I'm ${obj.name}`) // 缺点:硬编码,后期调整不灵活。
  1. 通过this.xx 访问
console.log(`I'm ${this.name}`) // 这里指向的是调用的对象

2. new Object

var obj = new Object()

3. 构造函数

定义: 描述同一类型的所有对象统一结构的函数。实现代码重用。

function 类型名(形参1, 形参2, ...){
    //将来要加入到新对象中的规定的属性
    this.属性名=形参1;
    this. xxx = xxx; 
    this.方法名=function(){ ... this.属性名 ... }
}

执行的内容

  • 创建指定类型的一个新对象
  • 同时把实参值传给构造函数的形参变量。

例子

function User(name,age) {
    this.name = name;
    this.age = age;
}
var user = new User("张三",18)

image.png 整体流程

  1. function User(name,age) {}等价于 new Function 创建了User对象
  2. 创建User对象的prototype,同时把prototype的constructor指回User
  3. new 关键字会创建一个新的空子对象
  4. 把子对象实例的__proto__属性指向User.prototype
  5. 执行函数User("张三",18),所以会创建函数作用域,由于this指向最新的空对象,所有对应的实参会赋值给新的空对象。
  6. 返回新对象的地址 0x0002

方法重用问题

function User(name,age) {
    this.name = name;
    this.age = age;
    this.say:function(){
    
    }
} 

由于 function say 本质还是会在内存创建新的区域,所有每次都会重复实例化,要避免构造函数定义方法的情况。
优化方案是通过原型链继承。

4. es6 class

  1. 使用class包裹
  2. constructor传入初始参数
  3. info(){...} 简写 this.info = function info() {...}
//class方式创建
class User2 {
    constructor(name,age){
        this.name = name
        this.age = age
    }
    info(){
        console.log("name:",this.name)
        console.log("age:",this.age)
    }
}

var user2 = new User2("jason",18)
user2.info()

//等价于下面 构造函数方式
function User(name,age) {
    this.name = name
    this.age = age
    this.info = function info() {
        console.log("name:",this.name)
        console.log("age:",this.age)
    }
}

var user = new User("jason",18)
user.info()

1.2继承

所有子对象共用的属性值和方法,都要放在构造函数的原型对象中

原型对象

定义
替所有子对象集中保存共有属性值和方法的父对象.

访问
构造函数自带prototype ,通过User.prototype 访问

添加属性\

  • 构造函数.prototype.属性名=属性值
  • 构造函数.prototype.方法名=function(){… …}

原型链

访问成员的顺序:
依次从当前 -> 当前的__proto__ 找父对象 一直查找下去。

内置类型

9种类型

原始类型

  • String
  • Number
  • Boolean
  • Array
  • Date
  • RegExp
  • Math(不是类型,已经是一个{}对象)
  • Error

引用类型

  • Function
  • Object

组成

  • 构造函数: 负责创建该类型的子对象,可以使用new 创建

  • 原型对象: 负责为该类型所有子对象集中保存共有的属性值和方法定义。

      通过内置类型.prototype可以查看所有的api信息
    

1.3多态

重写父类的方法 override

只要觉得从父对象继承来的成员不要用,都在子对象中重写同名成员

  • 原型顶端 Object.prototype.toString = {...}
  • 一般输出 [Object xxxx]
function User(name,age) {
   this.name = name;
   this.age = age;
}
//向User的原型对象中添加一个好用的toString方法
User.prototype.toString = function () {
   return `{ name:${this.name}, age:${this.age} }`
}
var user = new User("张三",18)
console.log(user);
var arr = [1, 2, 3];
var now = new Date();
//不同的类型都重写了 toString方法
console.log(user.toString());//{ name:张三, age:18 }
console.log(arr.toString());//1,2,3
console.log(now.toString());//Sat Jul 16 2022 16:54:38 GMT+0800 (中国标准时间)

2.箭头函数

已知:

var obj = {
    name: "jason",
    users: ["张三", "李四", "王五"],
    info: function () { //对象函数this 指向调用者
        this.users.forEach( 
            function (o) { //回调函数 this指向window
                console.log(`${this.name} -- ${o}`)
            }
    }
}
obj.info();
 
// -- 张三
// -- 李四
// -- 王五

这里jason无法正常显示。因为this访问的是全局的window

改为箭头函数可以解决

var obj = {
    name: "jason",
    users: ["张三", "李四", "王五"],
    info: function () { //对象函数this 指向调用者
        this.users.forEach( 
            (o) => { //回调函数 this指向函数之外最近的作用域中的this 等价于 info: function () {}的指向
                console.log(`${this.name} -- ${o}`)
            }
    }
}
obj.info();
  • 箭头函数只让this,指向外部作用域的this
  • 而箭头函数内的局部变量,依然只能在箭头函数内使用。出了箭头函数不能用!
  • 箭头函数依然有作用域!只是改变了this指向,不影响局部变量

底层实现
使用 bind(this) , 由于bind是的对象是不能再修改this,所以后面的call和apply均无效

var obj = {
    name: "jason",
    users: ["张三", "李四", "王五"],
    info: function () {  
        this.users.forEach( 
            (o) => {  
                console.log(`${this.name} -- ${o}`)
            }
    }
}
//等价于
var obj = {
    name: "jason",
    users: ["张三", "李四", "王五"],
    info: function () {  
        this.users.forEach( 
           function(o){  
                console.log(`${this.name} -- ${o}`)
            }.bind(this)//这里就会去外部找this
    }
}
由于底层是bind ,所以不能再用call方法修改this

什么场景可以改箭头

可以改:
如果函数中就不包含this 或 刚好希望函数内的this与外部this保持一致

bind和call,apply区别

  • bind一次性修改this指向,方法不执行,返回一个新的函数待执行。
  • call接受多个参数,方法立马执行。
  • apply接受数组参数,方法立马执行。

es6对象的函数新写法

var obj = {
    name: "jason",
    users: ["张三", "李四", "王五"],
    info: function () {//传统写法
    }
    info2() {//新写法
    
    }
}

info2只是简写,和原来function效果一致

3.this 7种情况

this指向不看定义,只看调用

1. 对象调用方法 obj.fun()

this:为.前的obj对象

function User(name,age) {
    this.name = name; 
    this.age = age;
    this.fun() = function (){
        console.log(this.name)// 这里指向的是 下面的user
    }
}
var user = new User("张三",18) 

2. new构造函数()

this:new正在创建的新对象

function User(name,age) {
    this.name = name; //这里指向新创建对象
    this.age = age; //这里指向新创建对象
}
var user = new User("张三",18) 

3. 构造函数.prototype.fun=function(){...}

  • 因为将来原型对象中的方法,都是"子对象.fun()"方式调用。
  • 所以,this->将来调用这个fun函数的.前的某个子对象
function User(name,age) {
    this.name = name;
    this.age = age;
}
User.prototype.toString = function () {
    return `{ name:${this.name}, age:${this.age} }` //this指向下面实例化的user
}
var user = new User("张三",18) 

4. fun() 匿名函数自调和回调函数中的

  • 正常模式this:window
  • 严格模式(usestrict)下,this:undefined 比如:
(function () { … this … })();
//和
arr.forEach(
    function () { … this … }
);

5.方法事件

this:当前正在出发事件的.前的DOM元素对象

button.onclick=function(){}
//或
button.addEventListener(“click",function(){…})

这里不能改成箭头函数!一旦改为箭头函数,this指外层的window。功能就会出错。

6. Vue中this

this:当前vue对象

<button@click="fun">
export default {
    methods: {
        //vue中methods中的方法中的this默认都指当前vue组件对象
        fun(e) { e.target }
        //如果想获得当前出发事件的DOM元素对象,必须用$event关键字和e.target联合使用
    }
}

7. 箭头函数中

this :当前函数之外最近的作用域中的this\