[TOC]
>[success] # 更强大的原型
原型是在`JS`中进行继承的基础, `ES6` 则在继续让原型更强大。早期的`JS`版本对原型的使用 有严重限制,然而随着语言的成熟,开发者也越来越熟悉原型的工作机制,因此他们明显希 望能对原型有更多控制权,并能更方便地使用它。于是 ES6 就给原型引入了一些改进。
>[success] ## ES6新增对象方法
~~~
首先介绍一下,下面几个对象的方法:
~~~
<br/>
>[success] ### Object.setPrototypeOf()
~~~
'Object.setPrototypeOf()' 方法'设置一个指定的对象的原型'(即, 内部[[Prototype]]属性)
到另一个对象或 null,和'Object.create()'类似,两者的区别:'Object.create()'是新建一个对象
可以为这个对象指定另一个对象的'原型','Object.setPrototypeOf()' 是改变源对象,为其指定另一个
对象的'原型'
语法:
Object.setPrototypeOf(obj, prototype)
参数:
1. 'obj':要设置其原型的对象。
2. 'prototype' : 该对象的新原型(一个对象 或 null)
~~~
1. 简单例子
~~~
function fun1 () { }
// 下面的操作,相当于在这个原型链里面新增了一些方法
// fun1.prototype.age = '18';
let obj1 = new fun1()
Object.setPrototypeOf(obj1, { age: '18' })
console.log(obj1)
~~~
<br/>
>[success] ### Object.defineProperty()
~~~
'Object.defineProperty()'的作用就是直接在一个对象上'定义一个新属性',或者'修改一个已经存在的属性'
语法:
Object.defineProperty(obj, prop, desc)
参数:
1. 'obj' : 需要定义属性的当前对象
2. 'prop' :当前需要定义的属性名
3. 'desc': 属性描述符
~~~
1. 添加(修改)属性
~~~
var o = {}; // 创建一个新对象
// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
~~~
<br/>
>[success] ### Object.defineProperties() 对象新增(修改)属性,返回对象
~~~
'Object.defineProperties()'方法直接在一个对象上定义'新的属性或修改现有属性',并'返回该对象'。
~~~
~~~
语法:Object.defineProperties(obj, props)
参数:
'obj' 需要定义属性的当前对象
'prop' 当前需要定义的属性名
~~~
<br/>
>[success] ### Object.getOwnPropertyDescriptor 获取对象属性的属性描述符
~~~
let obj = {
aa:'111',
bb:'222'
}
console.log(Object.getOwnPropertyDescriptor(obj,'aa')) // {"aa":{"value":"111","writable":true,"enumerable":true,"configurable":true}}
语法:Object.getOwnPropertyDescriptor(obj, props)
参数:
'obj' 要在其中查找属性的对象
'prop' Symbol要检索其描述的名称或属性。
~~~
<br/>
>[success] ### Object.getOwnPropertyDescriptors 获取对象全部属性的属性描述符
~~~
let obj = {
aa:'111',
bb:'222'
}
console.log(Object.getOwnPropertyDescriptors(obj,'aa')) // {"aa":{"value":"111","writable":true,"enumerable":true,"configurable":true},"bb":{"value":"222","writable":true,"enumerable":true,"configurable":true}}
语法:Object.getOwnPropertyDescriptors(obj)
参数:
'obj' 要查找属性的对象
~~~
<br/>
>[success] ## 修改原型
~~~
let person = {
getGreeting() {
return "Hello"
}
}
let dog = {
getGreeting() {
return "Woof"
}
}
// 原型为 person
let friend = Object.create(person)
console.log(friend.getGreeting()) // "Hello"
console.log(Object.getPrototypeOf(friend) === person) // true
// 将原型设置为 dog
Object.setPrototypeOf(friend, dog)
console.log(friend.getGreeting()) // "Woof"
console.log(Object.getPrototypeOf(friend) === dog) // true
~~~
<br/>
>[success] ## 使用 super 引用的简单原型访问
[参考文章:js中的super的使用](http://www.fly63.com/article/detial/4207)
~~~
1. 'this关键词'指向函'数所在的当前对象'
2. 'super'指向的是'当前对象的原型对象'
~~~
<br/>
>[success] ### ES5原型访问
~~~
// 原型对象1
const person = {
name: '小明1',
test(){
console.log('我是原型的方法1')
}
}
// 基础原型对象
const man = {
name: '小明',
test(){
console.log('我是自身的方法')
},
getProtoAttr() { // 调用原型属性
return Object.getPrototypeOf(this).name
},
getProtoFun(){ // 调用原型方法
return Object.getPrototypeOf(this).test.call(this)
}
}
// 修改man对象的原型对象为person
Object.setPrototypeOf(man, person)
// 调用自身的私有属性以及方法
console.log(man.name) // 小明
man.test() // 我是自身的方法
// 调用原型链的属性和方法
console.log(man.getProtoAttr()) // 小明1
man.getProtoFun() // 我是原型的方法
~~~
<br/>
>[success] ### ES6原型访问
~~~
// 原型对象1
const person = {
name: '小明1',
test(){
console.log('我是原型的方法1')
}
}
// 基础原型对象
const man = {
name: '小明',
test(){
console.log('我是自身的方法')
},
getProtoAttr() { // 调用原型属性
return super.name // 注意这里
},
getProtoFun(){ // 调用原型方法
return super.test() // 注意这里
}
}
// 修改man对象的原型对象为person
Object.setPrototypeOf(man, person)
// 调用自身的私有属性以及方法
console.log(man.name) // 小明
man.test() // 我是自身的方法
// 调用原型链的属性和方法
console.log(man.getProtoAttr()) // 小明1
man.getProtoFun() // 我是原型的方法
~~~
<br/>
>[success] ### super中的this指向(易混淆)
1. super.name 指向的是原型对象 person 中的 name ,但是绑定的 this 还是当前的 man 对象。
~~~
'属性重名': 自身'私有属性'和原型链属性'重名'时'super'先调用'自身私有属性',如果自身没有这个属性,'super'会自动去'原型链'找这个属性并且'调用'。
'方法重名','super'只会调用'原型链方法'不会调用本地的方法
const person = {
age:'20多了',
name(){
return this.age
}
}
const man = {
age:'18岁了',
sayName(){
return super.name()
}
}
// 为man对象设置原型对象
Object.setPrototypeOf( man, person )
// 调用原型链方法
console.log( man.sayName() ) // 18岁了
~~~
2. Object.getPrototypeOf(this).name 指向的是 person 的 name,绑定的 this 也是 person
~~~
const person = {
age: '20多了',
name() {
return this.age
}
}
const man = {
age: '18岁了',
sayName() {
return Object.getPrototypeOf(this).name()
}
}
// 为man对象设置原型对象
Object.setPrototypeOf(man, person)
// 调用原型链方法
console.log(man.sayName()) //20多了
~~~
3.Object.getPrototypeOf(this).name.call(this)指向的是person的name,不过通过call改变了函数的执行上下文,所以this指向的还是man
~~~
const person = {
age: '20多了',
name() {
return this.age
}
}
const man = {
age: '18岁了',
sayName() {
return Object.getPrototypeOf(this).name.call(this)
}
}
// 为man对象设置原型对象
Object.setPrototypeOf(man, person)
// 调用原型链方法
console.log(man.sayName()) //18岁了
~~~
<br/>
>[success] ### Class中的super
1. Class中的super(),它在这里表示父类的构造函数,用来新建父类的this对象 ,super()相当于Parent.prototype.constructor.call(this)
~~~
// 父类
class Demo {
constructor(x, y) {
this.x = x
this.y = y
}
customSplit() {
return [...this.y]
}
}
// 子类继承父类
class Demo2 extends Demo {
constructor(x, y) { // 如果不写constructor,js会自动生成一个空的constructor
super(x, y)
}
customSplit() {
return [...this.x]
}
task1() { // 调用父类(原型链)方法
return super.customSplit()
}
task2() { // 调用自身方法
return this.customSplit()
}
}
let d = new Demo2('hello', 'world')
console.log(d.task1()) //["w", "o", "r", "l", "d"]
console.log(d.task2()) //["h", "e", "l", "l", "o"]
~~~
2. 子类没有自己的this对象,而是继承父亲的this对象,然后进行加工。如果不调用super,子类就得不到this对象
~~~
class Demo2 extends Demo {
constructor(x, y) {
this.x = x //this is not defined
}
}
~~~
ES5的继承,实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上(Parent.call(this)). ES6的继承,需要先创建父类的this,子类调用super继承父类的this对象,然后再加工。
如果子类没有创建 constructor ,这个方法会被默认添加:
~~~
// 创建父类
class Demo{
constructor(x) {
this.x = x;
}
}
// 继承父类
class Demo2 extends Demo{}
// 实例化对象
let d = new Demo2('hello');
d.x //hello
~~~
3. super 在静态方法之中指向父类,在普通方法之中指向父类的原型对象。
可以理解成,没有实例化对象时候,使用静态的方法只能引静态的方法,实例化后原型的方法可以使用,并且原型方法权重高所以就引用了原型的方法
~~~
// 父类
class Parent {
// 静态方法
static myMethod(msg) {
console.log('static', msg)
}
myMethod(msg) {
console.log('instance', msg)
}
}
// 子类继承父类
class Child extends Parent {
// 静态方法
static myMethod(msg) {
super.myMethod(msg)
}
myMethod(msg) {
super.myMethod(msg)
}
}
// 直接引用静态方法
Child.myMethod(1) // static 1
// 实例化子类对象
let child = new Child()
child.myMethod(2) // instance 2
~~~
<br/>
>[warning] ### super 使用时需注意
~~~
'super'只可以在'简写方法'内使用,在'非简写'的情况下使用会报错
~~~
~~~
let man= {
test: function () {
// 语法错误
return super.test()
}
}
~~~
- Javascript基础篇
- Array数组
- 数组插入值
- filter()
- forEach()
- push()
- pop()
- unshift()
- shift()
- valueOf()
- 面向对象思想
- Javascript 面向对象编程(一):封装
- Javascript面向对象编程(二):构造函数的继承
- Javascript面向对象编程(三):非构造函数的继承
- 解构
- 数组的解构赋值
- 对象的解构赋值
- 函数参数解构
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 圆括号问题
- 字符串.
- split()
- charAt()
- charCodeAt()
- concat()
- indexOf()
- lastIndexOf()
- match()
- replace()
- includes()
- 初识递归
- 渲染ul-li树形结构
- 异步函数解决方案
- 1. callback回调函数
- 2. ES6 - Promise
- JavaScript高级程序设计(书)
- 在html中使用JavaScript
- script标签的位置
- 延迟脚本
- 异步脚本
- <noscript>元素
- 基本概念
- 严格模式
- 变量详解
- 数据类型
- typeof操作符
- undefined类型
- Null类型
- Boolean类型
- Number类型
- 深入了解ES6(书)
- var 、let 、 const
- 字符串与正则表达式
- 字符串
- 正则表达式
- 函数
- 函数形参默认值
- 使用不具名参数
- 函数构造器的增强能力
- 扩展运算符
- name属性
- 明确函数的多重用途
- 块级函数
- 箭头函数
- 尾调用优化
- 扩展的对象功能
- 对象类别
- 对象字面量语法的扩展
- ES6对象新增方法
- 重复的对象属性
- 自有属性的枚举顺序
- 更强大的原型
- 解构:更方便的数据访问
- 为什么要用解构?
- 对象解构
- 数组解构
- 混合解构
- 参数解构
- Symbol与Symbol属性
- 创建Symbol
- Symbol的使用方法
- Symbol全局私有属性
- Symbol与类型强制转换
- Symbol属性检索
- Symbol的一些构造方法
- Set集合与Map集合
- Set集合
- Weak Set集合(弱引用Set集合)
- Map集合
- JS标准内置对象
- Object 构造函数及属性
- Object 构造方法
- Symbol 内建对象类的函数及属性
- Set 构造函数及属性
- Weak Set 构造函数及属性
- JS杂项
- 类数组对象
- Class类的理解和使用