JS 面向对象


ES5 创建对象的方式

// 构造函数创建对象
function User(name, age) {
    this.name = name;
    this.age = age;
    this.say = function() {
        return "name: " + this.name + "age: " + this.age;
    }
}

function say(name, age) {
    console.log(name, age);
}
// 对象字面量创建对象
let vivi = {name: "vivi", age: 19, say: (name, age) => {say(name, age)}}


// Object 的构造器创建对象
let lulu = new Object();

构造函数和原型

# 构造函数和原型:
- 构造函数存在的问题:
- 构造函数虽然好用、但是每创建一个对象、方法也会被创建一份、浪费内存空间
- 因为每个实例上的方法都是一样的。我们希望每一个实例共享同一个方法
- 这就引出了构造函数的原型对象

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

# js 规定、每一个构造函数都有一个 prototype 属性、指向另一个对象(字面量创建的新对象)
# 这个对象的所有属性和方法都会被构造函数所拥有
# 我们可以把那些不变的方法、直接定义在 proptype 对象上、这样所有的实例就都可以共享这些方法


// 构造函数创建对象
function User(name, age) {
    this.name = name;
    this.age = age;
    // 使用这种方式每一个实例都会在内存中开辟该方法的空间
    /* this.say = function() {
        return "name: " + this.name + "age: " + this.age;
    } */
}

// 类的 prototype:{} 是属于类的属性值, 是一个通过字面量方式创建的一个新对象
// 这个属性和对象是由编译器自动添加的、用来存放该类所有实例的共享属性/方法
// class User {prototype: {constructer: f(), say: f()}}
// 我们给这个自动添加的 prototype 起了个名词叫:原型对象
// 将对象的方法放在类的原型对象上
User.prototype.say = function() {
    return "name: " + this.name + "age: " + this.age;
}

let user = new User("vivi", 19);
// 类原型属性上的所有方法被所有实例所共享
console.log(user.say());

# 我们之所以可以通过实例直接访问到类的原型对象上的方法、是因为每一个实例对象编译器都会添加一个属性
# 这个属性是 __proto__ 、指向的是类的原型对象 prototype: {}

# 因此、在 js 的面向对象中、为了实现方法的复用、编译器会给每一个类添加一个 propotype: {} (原型对象)
# 为每一个类的实例添加一个 __proto__ : Object 属性、实例的__proto__ 指向了类的 prototype: {}
# 实现了方法的复用、模拟出了Java方法区的效果

# 方法的查找规则;
- 首先看实例对象上有没有这个方法、如果有直接调用实例上的方法
- 如果没有、就去__proto__属性上查找 __proto__ 指向的是类的 prototype: {} (原型对象)

# constructor() 构造函数
- 在类的 prototype: {} 里面编译器会自动添加一个函数 constructor() 即 prototype: {constructor: f()}
- 这个编译器在类的 prototype:{} (原型对象)添加的 contructor 方法、我们称之为构造函数

# 构造函数和原型对象的关系:
- 原型对象是构造函数的一个属性 prototype: {}
- 构造函数被原型对象的 constructor: 属性所引用
- 即 prototype: {constructor: User(name, age)}
- 原型对象 prototype: {} 中的 this 指向的是实例对象、在运行时确定

# 原型链
- js 中所有类默认继承自 Object
- 类的 prototype: {} 也是一个对象!!、既然是对象、那么必然有一个__proto__属性、而这个属性
- 又指向了该类父类的 prototype: {} js 中所有类的 prototype: {} 对象中的 __proto__指向了 Object 的 prototype
- 而 Object 的 prototype: {} 对象中的 __proto__ 指向 null ! !

原型对象的应用

# 通过类的原型对象:prototype: {} 扩展内置对象的方法、比如 Array String Date 对象


// 扩展内置对象的方法
Array.prototype.sum = function() {
    let result = 0;
    for (let i = 0; i < this.length; i++) {
        result += this[i];
    }
    return result;
}

let arr = [1, 2, 3];

console.log(arr.sum()); // 6


ES5的继承(模拟继承)

# call()
- call() 方法可以修改函数运行时的 this 指向




// call() 为 Function.prototype 上的方法
function hello(a, b) {
    console.log(a, b);
    console.log("hello world");
    console.log(this); // 默认为 window
}

// call() 可以调用函数
hello.call(null, 1, 2); // 1, 2  hello world


// call() 修改 this 的指向
let user = {name: "vivi"};
hello.call(user, 1, 2);
// hello 函数中的 this --> {name: vivi}



function Fu(name, age) {
    this.name = name;
    this.age = age;
}

Fu.prototype.say = function() {
    return "name: " + this.name + " age: " + this.age;
}

function Zi(name, age) {
    // 借助父构造函数继承**属性**
    Fu.call(this, name, age);
}

// 通过原型对象继承**方法**
// Zi.prototype = Fu.prototype; error
Zi.prototype = new Fu();
Zi.prototype.constructor = Zi;
// 添加子构造函数特有的方法
Zi.prototype.sleep = function() {
    console.log(this.name + "在睡觉");
}
let user = new Zi('vivi', 19);
console.dir(user);
console.log(user.say());
user.sleep();


ES5 中新增的方法

# 数组方法:
- foreach()
- map()
- filter()
- some()
- every()

let arr = [1, 2, 3];

arr.forEach((value, index, arr) => {
    console.log(value, index, arr);
});

console.log(arr.filter((value, index) => index % 2 === 0 && value % 2 === 0));

console.log(arr.some((value) => value >= 3)); // true

# 字符串方法
- trim()

# 对象方法
- Object.keys()
- Object.defineProperty()

let user = {name: "vivi", age: 19}

console.log(Object.keys(user)); // [ 'name', 'age' ]

// 定义新属性或修改原有属性
Object.defineProperty(user, 'age',{value: 20});

Object.defineProperty(user, 'name', {
    // 设置该属性的值不可以修改
    writable: false,
})
console.log(user); // { name: 'vivi', age: 20 }

this 的指向问题
# 改变函数内部 this 指向的方法
- call()
- bind()
- apply()


function hello(a, b) {
    console.log(a, b);
    console.log(this);
}

let user = {name: 'vivi', age: 19}

// 与 call() 不同的是 第二个参数是一个数组
// 第二个参数是一个伪数组
hello.apply(user, [1, 2]);

// bind() 方法不会调用函数
// call() apply() 会调用函数
// bind() 方法返回一个this改变之后的函数
let world = hello.bind(user);
console.log("====================");
world(3, 4);

严格模式

# 严格模式可以分为
- 为脚本开启严格模式
- 为函数开启严格模式

# 为脚本开启严格模式
- 文件的开头 加上 "use strict"

# 严格模式中的变化
- 变量规定:在正常模式中、如果一个变量没有声明就赋值、默认是全局变量、严格模式禁止这种用法、变量必须先用
- var/let/const 声明、才能使用。
- 严禁删除已声明的变量 delete x; // error
- 严格模式全局作用域中函数的 this 不再指向 window 而是指向 undefined;
- 严格模式下函数中的形参不能重名
- 严格模式不允许在非函数的代码块中声明函数 比如 if for


"use strict"; // 脚本开启严格模式

function hello() {
    "use strict"; // 函数开启严格模式
}


闭包

# 定义:闭包是指有权访问另一个函数中作用域变量的函数
# 简单理解就是一个函数访问另一个函数作用域的变量

# 闭包的作用、延伸了变量的作用范围



// 闭包:一个函数访问另一个函数作用域的变量
// 在 world 函数中访问了 hello函数中的变量 name、形成了闭包
// hello 函数即为闭包函数
function hello() {
    let name = "vivi";
    function world() {
        console.log(name);
    }
    world();
}

hello();


闭包的应用


function hello() {
    let name = "vivi";
    function world() {
        console.log(name);
    }
    return world;
}

// 闭包的应用
// 在hello 函数的外部作用域访问hello函数的变量
hello()();

# 浅拷贝和深拷贝
- 浅拷贝只是拷贝一层、更深层次对象级别只拷贝引用
- 深拷贝拷贝多层、每一级别的数据都会拷贝

// 浅拷贝
let user = {name: "vivi", age: 19}

let vivi = {}

for (key in user) {
    vivi[key] = user[key];
}

console.log(vivi);

// 浅拷贝
Object.assign(vivi, user);

ES6 一些新特性

# 新的变量类型
- let
- const

# 解构赋值

# 箭头函数

# 模板字符串

# 扩展运算符 [...arr]

# set 数据结构
let set = new Set([1, 2, 3, 4]);

# async/await
- async 关键字用于函数上、函数的返回值是 Promise 实例对象
- await 关键字用于 async 函数当中(await 可以得到异步的结果)

async function queryData(id) {
    let response = await axios("/data");
    return response;
}

queryData.then(resp => {console.log(resp);})

ES6模块化

# ES6 模块化规范的定义
- 每一个 js 文件都是一个独立的模块
- 导入模块成员使用 import 关键字
- 导出模块成员使用 export 关键字

# 默认导出和默认导入
- 默认导出 export default {} 在每一个模块中、只允许使用一次
- 默认导入 import "" from ".js"

# 按需导出与按需导入
- 按需导出 export let name = "vivi";
- 按需导入 import {name} from ".js";

# 直接导入并执行模块代码
- import ".js";


// 默认导出 app.js
let username = "vivi";
let password = "123";
function login() {

}
export default {
    username, age, login
}

// 默认导入 index.js
import app from 'app.js';

console.log(app); // {username: vivi, password: 123, login: f()}


// 按需导出 app.js
export let name = "vivi";

export let age = 19;

export function say() {
    return name + " ==> " +age;
}


// 按需导入 index.js
import {name, age, say} from 'app.js';


// 直接导入并执行模块代码
// app.js
(function() {
    console.log("hello world");
})();

// 直接导入 index.js
import "app.js";


ES6 面向对象

# 类比 Java 面向对象

class Hello {
	
}

未完、待续…

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值