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知识库 -> ES6增强对象原型 -> 正文阅读

[JavaScript知识库]ES6增强对象原型

原型是JavaScript继承的基础,在早起版本中,JavaScript严重限制了原型的使用。随着语言逐渐成熟,开发者们也更加熟悉原型的运作方式,他们希望获得更多对于原型的控制力,并以更简单的方式来操作原型。于是,ECMAScript 6针对原型进行了改进。

改变对象的原型

正常情况下,无论是通过构造函数还是Object.create()方法创建对象,其原型都是在对象被创建时指定的。对象原型在实例化之后保持不变,直到ECMAScript 5都是Java编程最重要的设定之一,虽然在ECMAScript 5中添加了Object.getPrototypeOf()方法来返回任意指定对象的原型,但仍缺少对象在实例化后改变原型的标准方法。

所以,在ECMAScript 6中添加了Object.setPrototypeof()方法来改变这一现状,通过这个方法可以改变任意指定对象的原型,它接受两个参数:被改变原型的对象及替代第一个参数原型的对象。举个栗子:

let person = {
    getGreeting() {
        return "Hello";
    }
}

let dog = {
    getGreeting() {
        return "Woof";
    }
}
// 以person对象为原型
let friend = Object.create(person);
// Hello
console.log(friend.getGreeting());
// true
console.log(Object.getPrototypeOf(friend) === person);

// 将原型对象设置为dog
Object.setPrototypeOf(friend,dog);
// Woof
console.log(friend.getGreeting());
// true
console.log(Object.getPrototypeOf(friend) === dog);

这段代码中定义了链各个基对象:person和dog。二者都有getGreeting()方法,且都返回一个字符串。firend对象先继承person对象,调用getGreeting()方法输出"Hello";当原型被替换为dog对象时,原先与person对象的关联被解除,调用friend.getGreeting()方法时输出的内容变为了"Woof"。
对象原型的真实值被储存在内部专用属性[[Prototype]]中,调用Object.getPrototypeOf()方法返回储存在其中的值,调用Object.setPrototypeOf()方法改变其中的值。然而,这不是操作[[Prototype]]值的唯一方法。

简化原型访问的Super引用

正如之前提及的,原型对于JavaScript而言非常重要,ECMAScript 6中许多改进的最终目标就是为了使其更易用。以此为目标,ECMAScript 6引入了Super引用的特性,使用它可以更便捷地访问对象原型。举个例子,如果你想重写对象实例的方法,又需要调用与它同名的原型方法,则在ECMAScript 5中可以这样实现:

let person = {
    getGreeting() {
        return "Hello";
    }
}

let dog = {
    getGreeting() {
        return "Woof";
    }
}
// 以person对象为原型
let friend = {
    getGreeting() {
        return Object.getPrototypeOf(this).getGreeting.call(this) + ",Hi !";
    } 
}
Object.setPrototypeOf(friend,person);
// Hello,hi!
console.log(friend.getGreeting());
// true
console.log(Object.getPrototypeOf(friend) === person);

// 将原型对象设置为dog
Object.setPrototypeOf(friend,dog);
// Woof,hi!
console.log(friend.getGreeting());
// true
console.log(Object.getPrototypeOf(friend) === dog);

在这个示例中,friend对象的getGreeting()方法调用了同名的原型方法。Object.getPrototypeOf()方法可以确保调用正确的原型,并向输出字符串叠加了另一个字符串;后面的.call(this)可以确保正确设置原型方法中的this值。

要准确记得如何使用Object.getPrototypeOf()和.call(this)方法来调用Super引用相当于指向对象原型的指针,实际上也就是Object.getPrototypeOf(this)的值。于是,可以这样简化上面的getGreeting()方法:

let friend = {
    getGreeting() {
        // return Object.getPrototypeOf(this).getGreeting.call(this) + ",Hi !";
        return super.getGreeting() + ",Hi !";
    } 
}

调用super.getGreeting()方法相当于在当前上下文中调用Object.getPrototypeOf(this).getGreeting.call(this)。同样,可以通过Super引用调用对象原型上所有其他的方法。当然,必须要在使用简写方法的对象中使用Super引用,但如果在其他方法声明中使用会导致语法错误。就想这样

// 以person对象为原型
let friend = {
    getGreeting: function() {
        // return Object.getPrototypeOf(this).getGreeting.call(this) + ",Hi !";
        return super.getGreeting() + ",Hi !";
    } 
}

报错信息:Uncaught SyntaxError: ‘super’ keyword unexpected here (at prototype.js:25:16)
在这个示例中用匿名function定义了一个属性,由于在当前上下文中Super引用时非法的,因此调用super.getGreeting()方法会抛出语法错误。

另外,Super引用在多重继承的情况下非常有用。因为在这种情况下,使用Object.getPrototypeOf()方法将会出现问题

let person = {
    getGreeting() {
        return "Hello";
    }
}

// 以person对象为原型
let friend = {
    getGreeting() {
        return Object.getPrototypeOf(this).getGreeting.call(this) + ",Hi !";
        // return super.getGreeting() + ",Hi !";
    } 
}
Object.setPrototypeOf(friend,person);


let relative = Object.create(friend);

console.log(person.getGreeting());
console.log(friend.getGreeting());
console.log(relative.getGreeting());

在这里插入图片描述

prototype.js:10 Uncaught RangeError: Maximum call stack size exceeded
    at Object.getGreeting (prototype.js:10:9)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)
    at Object.getGreeting (prototype.js:10:56)

this时relative,relative的原型是friend对象,当执行relative的getGreeting方法时,会调动firend的getGreeting方法,而此时的this值为relative,Object.getPrototypeOf(this)又会返回friend对象。所以就会进入递归调用直到触发栈溢出报错。
在ECMAScript 5中很难解决这个问题,但在ECMAScript 6中,使用Super引用便可以迎刃而解

let person = {
    getGreeting() {
        return "Hello";
    }
}

// 以person对象为原型
let friend = {
    getGreeting() {
        return super.getGreeting() + ",Hi !";
    } 
}
Object.setPrototypeOf(friend,person);


let relative = Object.create(friend);

console.log(person.getGreeting());
console.log(friend.getGreeting());
console.log(relative.getGreeting());

Super引用不是动态变化的,它总是指向正确的对象,在这个示例中,无论有多少其他方法继承了getGreeting方法,super.getGreeting始终都指向person.getGreeting()方法。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:46:33  更:2022-10-31 11:51:26 
 
开发: 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年5日历 -2024/5/17 15:59:03-

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