1.面向对象3大特点
先使用一个个的对象结构集中存储现实中事物的属性和功能。然后,再按需使用不同对象中的不同属性和功能。
优点: 简化大数据了的管理
- 封装 :
- 继承
- 重载
1.1封装
- 封装就是创建一个对象,集中保存现实中一个事物的属性和功能。
- 将零散的数据封装进对象结构中,极其便于大量数据的管理维护。
封装对象的4种方式
1. 直接量
var 对象名={ //new Object()的简写
属性名: 属性值,
... : ... ,
方法名: function(){ ... }
}
访问方式
- 对象名.属性名
- 对象名.方法名()
var obj = {
name: "jason",
info: function () {
console.log(`I'm ${name}`)//这里会报错,函数里的变量不能直接访问对象的属性,
//会走函数作用域链的逻辑, 依次往上找,到window结束,还是没有找到。
//这里的obj = {} ,{}只是语法糖的简写,不包含函数作用域。
}
}}
解决办法
- 直接通过 对象.xx 访问
console.log(`I'm ${obj.name}`) // 缺点:硬编码,后期调整不灵活。
- 通过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)
整体流程
- function User(name,age) {}等价于 new Function 创建了User对象
- 创建User对象的prototype,同时把prototype的constructor指回User
- new 关键字会创建一个新的空子对象
- 把子对象实例的__proto__属性指向User.prototype
- 执行函数User("张三",18),所以会创建函数作用域,由于this指向最新的空对象,所有对应的实参会赋值给新的空对象。
- 返回新对象的地址 0x0002
方法重用问题
function User(name,age) {
this.name = name;
this.age = age;
this.say:function(){
}
}
由于 function say 本质还是会在内存创建新的区域,所有每次都会重复实例化,要避免构造函数定义方法的情况。
优化方案是通过原型链继承。
4. es6 class
- 使用class包裹
- constructor传入初始参数
- 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\