9.(ECMAScript)es6完全解读(8)

1. 重点提炼

  • 代理的使用与探究
  • 反射Reflect

2. 代理Proxy

  • 代理
  • 常用拦截方法

相当于对象的setget,拦截获取和设置操作。

es5代理 => Object.defineProperty

// ES5
let obj = {}
let newVal = '123456'
Object.defineProperty(obj, 'name', {
    get(){
        console.log('get')
        return newVal
    },
    set(val){
        console.log('set')
        // this.name = val 会造成死递归,内存溢出
        newVal = val
    }
})
obj.name = 'es'
console.log(obj.name)

但是注意set的时候不可以直接使用this.name = val,会造成死递归,内存溢出

image-20201125103612757

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.73
Branch: branch02

commit description:a2.73(代理Proxy——es5代理 => Object.defineProperty)

tag:a2.73


ES6 标准中新增的一个非常强大的功能是 Proxy,它可以自定义一些常用行为如查找、赋值、枚举、函数调用等。通过 Proxy这个名称也可以看出来它包含了“代理”的含义,只要有“代理”的诉求都可以考虑使用 Proxy来实现。

let p = new Proxy(target, handler)
参数含义必选
target用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)Y
handler一个对象,其属性是当执行一个操作时定义代理的行为的函数Y

Proxy对应两个参数,第一个是需要拦截的对象,第二个是配置参数,对应钩子函数。

如果给Proxy对象绑定了拦截对象,那么对该Proxy对象的操作,同样就会传递给拦截对象了。

MDN给出的解释偏官方,通俗的讲第一个参数 target就是用来代理的“对象”,被代理之后它是不能直接被访问的,而 handler 就是实现代理的过程。

// proxy
let obj = {}
let p = new Proxy(obj, {})
p.name = 'lisi'
console.log(obj.name)
for(let key in obj){
    console.log(key)
}

image-20201125104205558

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.74
Branch: branch02

commit description:a2.74(代理Proxy——使用)

tag:a2.74


2.1 get

拦截对象属性的读取

配置Proxy的钩子函数 => get方法

返回数组对应下标的值,如果没有则返回error=>

get参数 =>

target对应传入的拦截对象,即Proxy的第一个参数。

prop对应当前的索引值

prop in target => proptarget对应的key中是否有value

let arr = [7, 8, 9]
arr = new Proxy(arr, {
    get(target, prop) {
        console.log(target, prop)
        return prop in target ? target[prop] : 'error'
    }
})
console.log(arr[1])
console.log(arr[10])

image-20201125105312008

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.75
Branch: branch02

commit description:a2.75(代理Proxy——get钩子函数)

tag:a2.75


以上应用 => 实现一个字典小功能

let dict = {
    'hello': '你好',
    'world': '世界'
}
dict = new Proxy(dict, {
    get(target, prop) {
        return prop in target ? target[prop] : prop
    }
})
console.log(dict['world'])
console.log(dict['abc'])

image-20201125112946898

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.76
Branch: branch02

commit description:a2.76(代理Proxy——get钩子函数应用)

tag:a2.76


2.2 set

拦截对象属性的设置

set钩子函数 => 只能往数组中添加数值型值,返回bool类型。

set参数 =>

target 对应传入的拦截对象,即Proxy的第一个参数。

prop对应当前的索引值

value给目标属性设置的值

虽然通过proxy代理了数组,但是数组的自带的方法仍然可用(而defineProperty则不会)。即proxy代理并不会破坏对象的原有属性,兼容性更好。

let arr = []
arr = new Proxy(arr, {
    set(target, prop, val) {
        if (typeof val === 'number') {
            target[prop] = val
            return true
        } else {
            return false
        }
    }
})
arr.push(5)
arr.push(6)
console.log(arr[0], arr[1], arr.length)

image-20201125113857214

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.77
Branch: branch02

commit description:a2.77(代理Proxy——set钩子函数)

tag:a2.77


2.3 has

拦截propKey in proxy的操作,返回一个布尔值。

has钩子函数 => 判断当前对象是否有某个key,返回bool类型值

应用:判断当前的值,是否在某一个范围内。

// has
let range = {
    start: 1,
    end: 5
}

range = new Proxy(range, {
    has(target, prop){
        return prop >= target.start && prop <= target.end
    }
})
console.log(2 in range)
console.log(9 in range)

true

false

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.78
Branch: branch02

commit description:a2.78(代理Proxy——has钩子函数)

tag:a2.78


2.4 ownKeys

拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。

ownKeys => 拦截循环遍历方法

注意Symbol是一个变量,如果对象的key是变量,则需要加[] 中括号

回顾Symbol对象遍历 =>

let obj = {
    name: 'lisi',
    [Symbol('es')]: 'es6'
}
console.log(Object.getOwnPropertyNames(obj))  // 非Symbol的键名
console.log(Object.getOwnPropertySymbols(obj))  // 仅Symbol的键名
console.log(Object.keys(obj))  // 非Symbol的键名
for(let key in obj){ //非Symbol的键名
    console.log(key)
}

image-20201125121711392

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.79
Branch: branch02

commit description:a2.79(代理Proxy——回顾Symbol对象遍历)

tag:a2.79


_ 表示该属性为私有属性,对外不想暴露,比如密码

利用 for..inObject.keys都无法得到密码私有属性。

let userinfo = {
    username: 'lisi',
    age: 30,
    _password: '***'
}
userinfo = new Proxy(userinfo, {
    ownKeys(target) {
        return Object.keys(target).filter(key => !key.startsWith('_'))
    }
})

for (let key in userinfo) {
    console.log(key)
}
console.log(Object.keys(userinfo))

image-20201125122126027

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.80
Branch: branch02

commit description:a2.80(代理Proxy——ownKeys => 拦截循环遍历方法)

tag:a2.80


let user = {
    name: 'lisi',
    age: 30,
    _password: '***'
}
user = new Proxy(user, {
    get(target, prop) {
        // 防止对私有属性的访问
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            return target[prop]
        }
    }
})

// get拦截
console.log(user.age)
console.log(user._password)

image-20201125153301030

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.81
Branch: branch02

commit description:a2.81(代理Proxy——get拦截私有属性)

tag:a2.81


2.5 deleteProperty

拦截delete proxy[propKey]的操作,返回一个布尔值。

删除属性的拦截操作 => deleteProperty(target, prop),在其内部利用delete关键字,并且返回boolean类型变量。

let user = {
    name: 'lisi',
    age: 30,
    _password: '***'
}
user = new Proxy(user, {
    get(target, prop) {
        // 防止对私有属性的访问
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            return target[prop]
        }
    },
    set(target, prop, val) {
        // 防止对私有属性的设置
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            target[prop] = val
            return true
        }
    },
    deleteProperty(target, prop) { // 拦截删除
        // 防止对私有属性的删除
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            delete target[prop]
            return true
        }
    }
})

// set拦截
user.age = 18
console.log(user.age)
try {
    user._password = 'xxx'
} catch(e){
    console.log(e.message)
}

// 删除拦截
try {
    delete user.age
    delete user._password
} catch (e) {
    console.log(e.message)
}
console.log(user.age)

image-20201125153507520

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.82
Branch: branch02

commit description:a2.82(代理Proxy——set及delete拦截私有属性)

tag:a2.82


let user = {
    name: 'lisi',
    age: 30,
    _password: '***'
}
user = new Proxy(user, {
    get(target, prop) {
        // 防止对私有属性的访问
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            return target[prop]
        }
    },
    set(target, prop, val) {
        // 防止对私有属性的设置
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            target[prop] = val
            return true
        }
    },
    deleteProperty(target, prop) { // 拦截删除
        // 防止对私有属性的删除
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            delete target[prop]
            return true
        }
    },
    ownKeys(target) {
        // 防止对私有属性的遍历
        return Object.keys(target).filter(key => !key.startsWith('_'))
    }
})

for(let key in user){
    console.log(key)
}

image-20201125153929189

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.83
Branch: branch02

commit description:a2.83(代理Proxy——遍历拦截)

tag:a2.83


2.6 apply

拦截 Proxy实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)

apply => 拦截函数的调用以及call、apply等操作

定义一个求和函数,但其参数个数不确定。

之前代理都是对象,这里代理的是函数。

apply(target, ctx, args)

target拦截目标,即调用函数

ctx拦截上下文,this指向

args拦截的参数数组

拦截 后 将其求和结果乘2

// apply
let sum = (...args) => {
    let num = 0
    args.forEach(item => {
        num += item
    })
    return num
}

// 代理函数
sum = new Proxy(sum, {
    apply(target, ctx, args) {
        return target(...args) * 2
    }
})
console.log(sum(1, 2))
console.log(sum.call(null, 1, 2, 3))
console.log(sum.apply(null, [1, 2, 3]))

image-20201125155030720

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.84
Branch: branch02

commit description:a2.84(代理Proxy——apply函数调用拦截)

tag:a2.84


2.7 construct

拦截 Proxy实例作为构造函数调用的操作,比如new proxy(...args)

construct=> 拦截new命令

construct(target, args, newTarget)

target代理的目标对象

args构造函数的参数列表

newTarget实例化对象的时候new命令作用的构造函数

其必须返回一个对象

// construct  new
let User = class {
    constructor(name) {
        this.name = name
    }
}
User = new Proxy(User, {
    construct(target, args, newTarget) {
        console.log('construct')
        return new target(...args)
    }
})
console.log(new User('zhangsan'))

image-20201125155454937

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.85
Branch: branch02

commit description:a2.85(代理Proxy——construct对于new指令拦截)

tag:a2.85


2.8 拦截器小结

拦截器作用
get**拦截对象属性的读取,比如proxy.foo和proxy[‘foo’] **
set拦截对象属性的设置,返回一个布尔值,比如proxy.foo = v或 proxy[‘foo’] = v
has**拦截propKey in proxy的操作,返回一个布尔值 **
own Keys拦截 Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、 foj.in循环,返回一个数组。
deleteProperty拦截delete proxy[propKey]的操作,返回一个布尔值
apply拦截函数的调用、call和apply操作
construct拦截new命令,返回一个对象

3. 反射Reflect

  • Object属于语言内部的方法放到(转移)Reflect
  • 修改某些Object方法的返回结果,让其变得更合理
  • Object操作变成函数行为
  • Reflect对象的方法与Proxy对象的方法一一对应(两者相辅相成)
  • 估计以后的版本,一些已经移植到Reflect的方法,会从Object上删除

js设计初期,把很多方法放在了Object下了,这实际并不太合理,后期设计将Object属于语言内部的方法放到(转移)Reflect上,这样语法会更加规范。

// Object -> Reflect
let obj = {}
let newVal = ''
Reflect.defineProperty(obj, 'name', {
    get() {
        return newVal
    },
    set(val) {
        console.log('set')
        newVal = val
    }
})
obj.name = 'es'
console.log(obj.name)

image-20201125183631085

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.86
Branch: branch02

commit description:a2.86(反射Reflect——将Object属于语言内部的方法放到(转移)Reflect上)

tag:a2.86


修改某些Object方法的返回结果,让其变得更合理 =>

Object.defineProperty 定义某些属性的时候,如果当前某些属性无法定义的时候,它会抛出异常。

因此一般都嵌套try…catch,因为其没有返回值。

try {
    Object.defineProperty()
} catch (e) {}

但是Reflect下,它是有返回值的,写法如下:

if (Reflect.defineProperty()) { // boolean

} else {

}

让Object操作变成函数行为

之前的语法操作,实际上Object的操作都是命令式的。

判断某个方法是否在某个对象中,以前的写法是命令式的,而现在是函数式的。

console.log('assign' in Object) // true
console.log(Reflect.has(Object, 'assign'))// true

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.87
Branch: branch02

commit description:a2.87(反射Reflect——让Object操作变成函数行为)

tag:a2.87


Reflect对象的方法与Proxy对象的方法一一对应(两者相辅相成)

let user = {
    name: 'lisi',
    age: 30,
    _password: '***'
}
user = new Proxy(user, {
    get(target, prop) {
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            // return target[prop]
            return Reflect.get(target, prop)
        }
    },
    set(target, prop, val) {
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            // target[prop] = val
            Reflect.set(target, prop, val)
            return true
        }
    },
    deleteProperty(target, prop) { // 拦截删除
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            // delete target[prop]
            Reflect.deleteProperty(target, prop)
            return true
        }
    },
    ownKeys(target) {
        // return Object.keys(target).filter(key => !key.startsWith('_'))
        return Reflect.ownKeys(target).filter(key => !key.startsWith('_'))
    }
})

console.log(user.age)
try {
    console.log(user._password)
} catch (e) {
    console.log(e.message)
}

user.age = 18
console.log(user.age)
try {
    user._password = 'xxx'
} catch (e) {
    console.log(e.message)
}

for (let key in user) {
    console.log(key)
}

delete user.age
console.log(user.age)

image-20201125200625423

ctx=> this指向,无需改变,还指向target即可。

// apply
let sum = (...args) => {
    let num = 0
    args.forEach(item => {
        num += item
    })
    return num
}

sum = new Proxy(sum, {
    apply(target, ctx, args) {
        // return target(...args) * 2
        return Reflect.apply(target, target, [...args]) * 2
    }
})
console.log(sum(1, 2))
console.log(sum.call(null, 1, 2, 3))
console.log(sum.apply(null, [1, 2, 3]))

image-20201125200727585

参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a2.88
Branch: branch02

commit description:a2.88(反射Reflect——Reflect对象的方法与Proxy对象的方法一一对应(两者相辅相成))

tag:a2.88


Reflect是一个内置的对象,它提供拦截 JavaScript操作的方法,这些方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

与大多数全局对象不同,Reflect没有构造函数。你不能将其与一个new运算符一起使用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)


3.1 常用方法

3.1.1 Reflect.apply()

Reflect.apply(target, thisArgument, argumentsList)

参数含义必选
target目标函数Y
thisArgumenttarget函数调用时绑定的this对象N
argumentsListtarget函数调用时传入的实参列表,该参数应该是一个类数组的对象N
Reflect.apply(Math.floor, undefined, [1.75])
// 1

Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111])
// "hello"

Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index
// 4

Reflect.apply(''.charAt, 'ponies', [3])
// "i"

该方法与ES5Function.prototype.apply()方法类似:调用一个方法并且显式地指定this变量和参数列表(arguments) ,参数列表可以是数组,或类似数组的对象。

Function.prototype.apply.call(Math.floor, undefined, [1.75])

3.1.2 Reflect.construct()

Reflect.construct()方法的行为有点像 new操作符 构造函数 , 相当于运行 new target(...args)

Reflect.construct(target, argumentsList[, newTarget])

参数含义必选
target被运行的目标函数Y
argumentsList调用构造函数的数组或者伪数组Y
newTarget该参数为构造函数, 参考 new.target 操作符,如果没有newTarget参数, 默认和target一样N

注意如果target或者newTarget不是构造函数,抛出TypeError

Reflect.construct允许使用可变的参数来调用构造函数

var obj = new Foo(...args)
var obj = Reflect.construct(Foo, args)

var d = Reflect.construct(Date, [1776, 6, 4])
d instanceof Date // true
d.getFullYear() // 1776

如果使用 newTarget参数,则表示继承了 newTarget 这个超类:

function someConstructor() {}
var result = Reflect.construct(Array, [], someConstructor)

Reflect.getPrototypeOf(result) // 输出:someConstructor.prototype
Array.isArray(result) // true

3.1.3 Reflect.defineProperty

静态方法 Reflect.defineProperty() 基本等同于 Object.defineProperty()方法,唯一不同是返回 Boolean值。

Reflect.defineProperty(target, propertyKey, attributes)

参数含义必选
target目标对象Y
propertyKey要定义或修改的属性的名称Y
attributes要定义或修改的属性的描述Y
const student = {}
Reflect.defineProperty(student, 'name', {
    value: 'Mike'
}) // true
student.name // "Mike"

3.1.4 Reflect.deleteProperty()

Reflect.deleteProperty 允许你删除一个对象上的属性。返回一个 Boolean值表示该属性是否被成功删除。它几乎与非严格的delete operator相同。

Reflect.deleteProperty(target, propertyKey)

参数含义必选
target删除属性的目标对象Y
propertyKey将被删除的属性的名称Y
var obj = {
    x: 1,
    y: 2
}
Reflect.deleteProperty(obj, "x") // true
obj // { y: 2 }

var arr = [1, 2, 3, 4, 5]
Reflect.deleteProperty(arr, "3") // true
arr // [1, 2, 3, , 5]

// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo") // true

// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({
    foo: 1
}), "foo") // false

3.1.5 Reflect.get()

Reflect.get()方法的工作方式,就像从object (target[propertyKey])中获取属性,但它是作为一个函数执行的。

Reflect.get(target, propertyKey[, receiver])

参数含义必选
target需要取值的目标对象Y
propertyKey需要获取的值的键值Y
receiver如果遇到 getter,此值将提供给目标调用N
// Object
var obj = {
    x: 1,
    y: 2
}
Reflect.get(obj, 'x') // 1

// Array
Reflect.get(['zero', 'one'], 1) // "one"

// Proxy with a get handler
var x = {
    p: 1
}
var obj = new Proxy(x, {
    get(t, k, r) {
        return k + 'bar'
    }
})
Reflect.get(obj, 'foo') // "foobar"

3.1.6 Reflect.getOwnPropertyDescriptor()

静态方法 Reflect.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()方法相似。如果在对象中存在,则返回给定的属性的属性描述符,否则返回 undefined

Reflect.getOwnPropertyDescriptor(target, propertyKey)

参数含义必选
target需要寻找属性的目标对象Y
propertyKey获取自己的属性描述符的属性的名称N
Reflect.getOwnPropertyDescriptor({
    x: 'hello'
}, 'x')
// {value: "hello", writable: true, enumerable: true, configurable: true}

Reflect.getOwnPropertyDescriptor({
    x: 'hello'
}, 'y')
// undefined

Reflect.getOwnPropertyDescriptor([], 'length')
// {value: 0, writable: true, enumerable: false, configurable: false}

对比

如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError错误。而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理。

Reflect.getOwnPropertyDescriptor("foo", 0)
// TypeError: "foo" is not non-null object

Object.getOwnPropertyDescriptor("foo", 0)
// { value: "f", writable: false, enumerable: true, configurable: false }

3.1.7 Reflect.getPrototypeOf()

静态方法Reflect.getPrototypeOf()Object.getPrototypeOf()方法是一样的。都是返回指定对象的原型(即,内部的 [[Prototype]]属性的值)。

Reflect.getPrototypeOf(target)

参数含义必选
target获取原型的目标对象Y

3.1.8 Reflect.has()

Reflect.has用于检查一个对象是否拥有某个属性, 相当于in操作符

Reflect.has(target, propertyKey)

参数含义必选
target获取原型的目标对象Y
propertyKey属性名,需要检查目标对象是否存在此属性Y

3.1.9 Reflect.isExtensible()

Reflect.isExtensible 判断一个对象是否可扩展 (即是否能够添加新的属性),它与 Object.isExtensible()方法一样。

Reflect.isExtensible(target)

参数含义必选
target获取原型的目标对象Y

3.1.10 Reflect.ownKeys()

Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))

Reflect.ownKeys(target)

参数含义必选
target获取原型的目标对象Y
Reflect.ownKeys({
    z: 3,
    y: 2,
    x: 1
}) // [ "z", "y", "x" ]
Reflect.ownKeys([]) // ["length"]

var sym = Symbol.for("comet")
var sym2 = Symbol.for("meteor")
var obj = {
    [sym]: 0,
    "str": 0,
    "773": 0,
    "0": 0,
    [sym2]: 0,
    "-1": 0,
    "8": 0,
    "second str": 0
}
Reflect.ownKeys(obj)
// [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
// Indexes in numeric order,
// strings in insertion order,
// symbols in insertion order

3.1.11 Reflect.preventExtensions()

Reflect.preventExtensions 方法阻止新属性添加到对象 例如:防止将来对对象的扩展被添加到对象中)。该方法与 Object.preventExtensions() 方法一致

Reflect.preventExtensions(target)

参数含义必选
target获取原型的目标对象Y
// Objects are extensible by default.
var empty = {}
Reflect.isExtensible(empty) // === true

// ...but that can be changed.
Reflect.preventExtensions(empty)
Reflect.isExtensible(empty) // === false
Reflect.preventExtensions(1)
// TypeError: 1 is not an object

Object.preventExtensions(1)
// 1

3.1.12 Reflect.set()

Reflect.set 方法允许你在对象上设置属性。它的作用是给属性赋值并且就像property accessor语法一样,但是它是以函数的方式。

Reflect.set(target, propertyKey, value[, receiver])

参数含义必选
target获取原型的目标对象Y
propertyKey设置的属性的名称Y
value设置的值Y
receiver如果遇到 setter,this 将提供给目标调用N
// Object
var obj = {}
Reflect.set(obj, "prop", "value") // true
obj.prop // "value"

// Array
var arr = ["duck", "duck", "duck"]
Reflect.set(arr, 2, "goose") // true
arr[2] // "goose"

// It can truncate an array.
Reflect.set(arr, "length", 1) // true
arr // ["duck"]

// With just one argument, propertyKey and value are "undefined".
var obj = {}
Reflect.set(obj) // true
Reflect.getOwnPropertyDescriptor(obj, "undefined")
// { value: undefined, writable: true, enumerable: true, configurable: true }

3.1.13 Reflect.setPrototypeOf()

Reflect.setPrototypeOf 方法改变指定对象的原型 (即,内部的 [[Prototype]] 属性值)

Reflect.setPrototypeOf(target, prototype)

参数含义必选
target获取原型的目标对象Y
prototype对象的新原型 (一个对象或 null)Y
Reflect.setPrototypeOf({}, Object.prototype) // true

// It can change an object's [[Prototype]] to null.
Reflect.setPrototypeOf({}, null) // true

// Returns false if target is not extensible.
Reflect.setPrototypeOf(Object.freeze({}), null) // false

// Returns false if it cause a prototype chain cycle.
var target = {}
var proto = Object.create(target)
Reflect.setPrototypeOf(target, proto) // false

注意

对于以上所有 API 第一个参数是 Object 的,如果给定的不是 Object 则抛出一个 TypeError 异常




(后续待补充)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值