IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【JavaScript】原型链 & 继承 -> 正文阅读

[JavaScript知识库]【JavaScript】原型链 & 继承

原型链

构造函数的属性是各个实例自己的属性,原型(对象)的属性是所有实例共享的属性

在这里插入图片描述

  • 构造函数的原型 (prototype),就是它的实例的原型对象 (__proto__)
  • Object.protptype 是最顶层的原型(对象),其原型对象为 null
  • 只有 Object.protptype 没有原型对象(为 null);除此之外的对象,都能通过 .__proto__ 找到原型对象
  • 一般构造函数的原型,是 Object 的实例;构造函数的原型的原型对象,是 Object.prototype

构造函数

  • 引用类型:有内置的构造函数:Object()Array()Function()RegExp()Date()
  • 基本类型:① 有内置的包装类:Number()String()Boolean();② nullundefined 无包装类

原型链查找逻辑

访问实例的属性时,先查看该实例的属性;若没有,则查看其原型对象的属性;若还是没有,则查看其原型对象的原型对象的属性;以此类推… 直至找到 Object.prototype

  • 所以,所有对象都能使用 Object.prototype 的属性 ,eg:toString()
  • 如果我们给 Object.prototype 添加属性,则所有的实例对象都能使用该属性
  • 如果我们给实例重写了一些的同名属性,会覆盖其原型对象的属性,eg:Number.toString()

判断对象的属性

① 对象可以通过打点,判断属性是否存在于原型链中

如果属性存在,则返回属性值;如果不存在,则返回 undefined;如果属性值为 undefined,也返回 undefined

var obj = {
    a: 1
}

console.log(obj.a) // 1
console.log(obj.b) // undefined

obj.__proto__.b = 2

console.log(obj.b) // 2
② 可以通过 in 运算符,判断属性是否存在于原型链中
  • 如果属性存在,则返回 true;否则返回 false
  • 注意属性是 string 类型的,要用引号括住
var obj = {
    a: 1
}

console.log("a" in obj); // true
console.log("b" in obj); // false

obj.__proto__ = {
    b: 20
}

console.log("b" in obj); // true
  • 我们还可以通过 in 操作符,遍历原型链上的可枚举属性
  • 可枚举属性是指原型链上,自己添加的属性。系统默认的属性(eg:constructor)是不可枚举的
for (var k in obj) {
    console.log(k)
}
我们可以通过 hasOwnProperty(),判断属性是否在实例自己身上
  • hasOwnProperty() 定义在 Object.prototype 对象上面,所以任意对象都可调用该方法
  • 如果实例存在指定属性,则返回 true;否则返回 false(不考虑原型链)
var obj = {
    a: 1
}
obj.__proto__.b = 4

console.log(obj.hasOwnProperty("a")); // true
console.log(obj.hasOwnProperty("b")); // false

配合 for in 使用,就可以遍历实例自己的属性啦

for (var k in obj) {
    obj.hasOwnProperty(k) && console.log(k);
}

Object.defineProperty()

我们可以通过 Object.defineProperty() 方法,定义属性 / 修改属性的配置(eg:是否可枚举)

该方法接收 3 个参数:属性所在的对象属性名描述符对象

描述符对象 有以下配置项:
  1. configurable:是否可以重新配置;默认为 true
  2. enumerable:是否可以通过 for in 枚举;默认为 false
  3. writable:属性值是否可修改;默认为 false
  4. value:默认属性值;默认为 undefined
var obj = {} // 创建空对象

Object.defineProperty(obj, 'name', {
    // 修改配置项
    configurable: true,
    enumerable: true,
    writable: true,
    value: 'superman'
})

console.log(obj) // {name: "superman"}
除了以上配置项外,描述符对象还有两个方法:
  1. get:获取属性值时,会被调用
  2. set:修改属性值时,会被调用

Object.defineProperties()

  • 可通过该方法,同时对多个属性进行定义 / 修改其配置
var book = {}

Object.defineProperties(book, {
    _year: { // 我们约定,带下划线的属性,为私有属性,不可直接访问
        writable: true,
        value: 2004
    },
    edition: {
        writable: true,
        value: 1
    },
    year: {
        get: function () {
            return this._year;
        },
        set: function (newValue) {
            if (newValue > 2004) {
                this._year = newValue;
                this.edition += newValue - 2004;
            }
        }
    }
})

console.log(book) // {_year: 2004, edition: 1}
book.year = 2010
console.log(book) // {_year: 2010, edition: 7}

Object.getOwnPropertyDescriptor()

  • 用于获取属性的描述对象
  • 第1个参数:属性所属的对象;第2个参数:属性名
  • 返回该属性的描述符对象
Object.getOwnPropertyDescriptor(obj, 'name')

instanceof

  • 验证对象是不是原型链上面的构造函数创建出来的实例
function Dog() {}

function Cat() {}

Cat.prototype = new Dog() // 继承

var a = new Cat() // 通过 cat 创建实例

console.log(a.constructor) // ? Dog() {}

console.log(a.__proto__) // Dog {}
console.log(a.__proto__.__proto__) // {constructor: ?}
console.log(a.__proto__.__proto__.__proto__) // {constructor: ?, __defineGetter__: ?, …}
console.log(a.__proto__.__proto__.__proto__.__proto__) // null

console.log(a instanceof Cat) // true
console.log(a instanceof Dog) // true
console.log(a instanceof Object) // true

在这里插入图片描述

验证数组
  1. 使用 typeof
var arr = []
console.log(typeof arr) // object
  1. 使用 instanceof
var arr = []
console.log(arr instanceof Array) // true

arr 不一定是 Array 的实例,也有可能是某继承了 Array 的构造函数的实例

  1. 使用 API(IE9 开始兼容)
var arr = []
console.log(Array.isArray(arr)) // true

检测数据类型的方法

使用 Object.prototype.toString.call()

Object.prototype.toString() // "[object Object]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call(function () {}); // "[object Function]"
Object.prototype.toString.call([]); // "[object Array]"

Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call("123"); // "[object String]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(null); // "[object Null]"

必须通过 Object.prototype 调用 toString(),因为子类可能重写了该方法(eg:Number(1).toString() = 1)

继承

原型链继承

将父级的实例作为子类的原型

子类可以重写父类的方法。重写后,子类的方法会覆盖父类的方法。

function People(name) {
    this.name = name // 设置 People 的实例的属性
}

// 设置 People 原型的属性,是 People 的所有实例共享的属性
People.prototype.sayHello = function () {
    console.log("名字:" + this.name)
}

function Student(name, id) {
    this.name = name // 设置 Student 的实例的属性
    this.id = id
}

// 继承:Student 的原型 = People 的实例
Student.prototype = new People('大明') // 创建了父类实例,造成父类实例的属性数据冗余

// 设置 Student 的原型的属性,是 Student 的所有实例共享的属性
// 同时也是实例 '大明' 自己的属性,会覆盖 People 原型的属性
Student.prototype.sayHello = function () {
    console.log("姓名:" + this.name, "学号:" + this.id)
}

var Hong = new Student("小红", 1001)

Hong.sayHello() // 姓名:小红 学号:1001

console.log(Hong.__proto__) // People {name: "大明", sayHello: ?}
Hong.__proto__.sayHello() // 姓名:大明 学号:undefined

console.log(Hong.__proto__.__proto__) // {sayHello: ?, constructor: ?}
Hong.__proto__.__proto__.sayHello() // 名字:undefined

在这里插入图片描述

构造函数继承

  • 可以简单地认为是,复制父类实例的属性给子类
  • 方法都在父类的构造函数中定义,只能继承父类实例的属性
  • 继承不涉及父类的原型链,不能继承父类的原型链上的属性
  • 每个子类都有父类实例的函数的副本,影响性能
function People(name) {
    this.name = name
}

People.prototype.sayHello = function () {
    alert("你好我是" + this.name)
}

function Student(name, id) {
    // 继承:调用父类函数
    People.call(this, name)
    this.id = id
}

Student.prototype.study = function () {
    console.log("好好学习,天天向上")
}

var hong = new Student("小红", 1001)
console.log(hong.name, hong.id)
hong.study()
// hong.sayHello() // 会报错

在这里插入图片描述

组合继承

就是原型链继承构造函数继承组合在一起:

  • 通过构造函数继承,继承父类的属性
  • 通过原型链继承,继承父类的原型链的属性,以实现函数的复用
function People(name) {
    this.name = name
}

People.prototype.sayHello = function () {
    console.log("名字:" + this.name)
}

function Student(name, id) {
    People.call(this, name) // 构造函数继承:通过调用父类函数,继承父类的属性
    this.id = id
}

// 原型链继承:通过父类的实例继承父类的原型链上的属性
Student.prototype = new People('大明') // 这里创建的父类实例的属性数据冗余了

Student.prototype.study = function () {
    console.log("好好学习,天天向上")
}

var hong = new Student("小红", 1001)
console.log(hong) // 小红 1001
hong.sayHello() // 名字:小红
  • 如果不用构造函数继承sayHello 输出的名字是大明

寄生组合继承

通过空的构造函数,得到没有属性的子类原型。这样,在进行原型链继承时,就可以避免父类的实例属性数据的冗余

function People(name) {
    this.name = name
}

People.prototype.sayHello = function () {
    console.log("你好我是" + this.name)
}

function Student(name, id) {
    People.call(this, name) // 构造函数继承
    this.id = id
}

// 核心语句
function Fn() {} // 定义空的构造函数,没有任何属性
Fn.prototype = People.prototype // 插入到父类的原型链中
Student.prototype = new Fn() // 原型链继承

Student.prototype.study = function () {
    console.log("好好学习,天天向上")
}

var hong = new Student("小红", 1001)
hong.sayHello() // 你好我是小红

在这里插入图片描述

圣杯模式

就是将寄生组合继承封装成函数

function inherit(People, Student) {
    function Fn() {} // 定义空父类
    Fn.prototype = People.prototype // 插入原型链
    Student.prototype = new Fn() // 继承
    Student.prototype.constructor = Student // 完善原型链
    Student.prototype.parent = People // 添加'父类'属性
}
inherit(People, Student)

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-20 15:00:21  更:2021-08-20 15:00:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 6:10:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计