ES6-8 - 函数名/对象拓展、描述符、getter/setter

函数名

有两种特殊情况:bind方法创造的函数,name属性返回bound加上原函数的名字;Function构造函数创造的函数,name属性返回anonymous。

  • bind函数名
// 以bound开头
function foo() { }
const fnName = foo.bind().name
console.log(fnName) // bound foo
  • getter setter

如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。

const obj = {
  get foo() {},
  set foo(x) {}
};

obj.foo.name
// TypeError: Cannot read property 'name' of undefined

const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');

descriptor.get.name // "get foo"
descriptor.set.name // "set foo"

对象方法的简写

const o = {
  method() {
    return "Hello!";
  }
};
  • node common.js写法+
    ES6-8 - 函数名/对象拓展、描述符、getter/setter_第1张图片

ES6-8 - 函数名/对象拓展、描述符、getter/setter_第2张图片

属性名表达式

ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';

let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
};
let obj = {
  ['h' + 'ello']() {
    return 'hi';
  }
};

obj.hello() // hi
  • 属性名可以重复,重复则覆盖
let b = 'b'
let obj = {
	['a' + 'b'] : undefined,
	['a' + b] : 1, // 属性名和上面重复,永远取最后的,obj最后依然只有一个键‘ab’
}
属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心。
const keyA = {a: 1};
const keyB = {b: 2};

const myObject = {
  [keyA]: 'valueA',
  [keyB]: 'valueB'
};

myObject // Object {[object Object]: "valueB"}
// 1. 属性名相同覆盖
// 2. 将一切js变量转为字符串,作为属性名
  1. 一个对象的属性名可以是任何有效的 JavaScript 字符串,或者可以被转换为字符串的任何类型,包括空字符串。然而,一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。
  2. JavaScript中的对象只能使用String类型作为键类型。

属性描述符

  • getOwnPropertyDescriptor是构造器上的方法
  • 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)若无返回undefined
  • Object.getOwnPropertyDescriptor(obj, prop)
    ES6-8 - 函数名/对象拓展、描述符、getter/setter_第3张图片

一个属性描述符是一个记录,由下面属性当中的某些组成的:

  1. value
    该属性的值(仅针对数据属性描述符有效)
  2. writable
    当且仅当属性的值可以被改变时为true。(仅针对数据属性描述有效)
    重新赋值,不包括删除!
  3. get
    获取该属性的访问器函数(getter)。如果没有访问器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)
  4. set
    获取该属性的设置器函数(setter)。 如果没有设置器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)
  5. configurable
    当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为true。
    delete obj.a
  6. enumerable
    当且仅当指定对象的属性可以被枚举出时,为 true。
Object.defineProperty(o, "baz", {
  value: 8675309,
  writable: false, // 重写baz属性会静默失败;而严格模式重写则报错
  enumerable: false
});
  • 注意:在 ES5 中,如果该方法的第一个参数不是对象(而是原始类型),那么就会产生出现 TypeError。而在 ES2015,第一个的参数不是对象的话就会被强制转换为对象。
Object.getOwnPropertyDescriptor('foo', 0);
// 类型错误: "foo" 不是一个对象  // ES5 code

Object.getOwnPropertyDescriptor('foo', 0);
// Object returned by ES2015 code: {
//   configurable: false,
//   enumerable: true,
//   value: "f",
//   writable: false
// }

getter、setter在对象上

使用Object.defineProperties的方法,同样也可以对一个已创建的对象在任何时候为其添加getter或setter方法。这个方法的第一个参数是你想定义getter或setter方法的对象,第二个参数是一个对象,这个对象的属性名用作getter或setter的名字,属性名对应的属性值用作定义getter或setter方法的函数。

  • set必须要有参数,否则报错Uncaught SyntaxError: Setter must have exactly one formal parameter.
var o = {
  a: 7,
  get b() { 
    return this.a + 1;
  },
  set c(x) {
    this.a = x / 2
  }
};

console.log(o.a); // 7 
console.log(o.b); // 8 注意访问方式 get直接读
o.c = 50; // set要赋值
console.log(o.a); // 25
var language = {
    set add(name){
        this.ln.push(name)
    },
    ln: []
}
language.add = 'EN'
language.add = 'FN'
console.log(language.ln) // ["EN","FN"]

mdn getter
mdn setter

ES6-8 - 函数名/对象拓展、描述符、getter/setter_第4张图片

  • a也是o的属性,只是用getter、setter劫持了
  • 如果getter和属性重名,会报错 Uncaught RangeError: Maximum call stack size exceeded

不可能同时将一个 getter 绑定到一个属性并且该属性实际上具有一个值。
使用get语法时,不能与另一个 get 或具有相同属性的数据条目同时出现在一个对象字面量中。
不允许使用 { get x() { }, get x() { } } 和 { x: …, get x() { } })。
在对象字面量中,不能为一个已有真实值的变量使用 set ,也不能为一个属性设置多个 set。
( { set x(v) { }, set x(v) { } } 和 { x: …, set x(v) { } } 是不允许的 )

var o = {
  _a: 7,
  get a() { 
    return this._a + 1;
  },
  set a(x) {
    this._a = x / 2
  }
};

console.log(o.a); // 8
o.a = 10
console.log(o.a); // 6
console.log(Object.keys(o)) // ["_a","a"]

ES6-8 - 函数名/对象拓展、描述符、getter/setter_第5张图片

  • Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #
    var obj = {
        get a(){
            return 2
        }
    }
    // 注意:这里也不能再为已有的对象属性,使用defineProperty
    Object.defineProperty(obj, 'b', {
        get: function(){
            return this.a + 100
        },
        // value: 2 写了get不能再写value/writable,否则报错
    })
    console.log(obj.a) // 2
    console.log(obj.b) // 102
    
    • get和set一般是成对出现的,并且不应写死,不然没有意义

    getter/setter → 伪属性

    • Object.defineProperty与创建对象时定义getter/setter的区别
    • Object.defineProperty的getter/setter/其余普通属性不可枚举、不可配置
    const obj = {
        a: 2
    }
    Object.defineProperty(obj, 'b', {
        set: function (x) {
            this.a = x
        }
    })
    const res = Object.getOwnPropertyDescriptor(obj, 'b')
    console.log(res)
    console.log(Object.keys(obj))
    
    const obj2 = {
        _a: 2,
        get a() {
            return this._a
        },
        set a(val) {
            this._a = val
        }
    }
    const res2 = Object.getOwnPropertyDescriptor(obj2, 'a')
    console.log(res2)
    console.log(res2.get.name) // get a
    console.log(res2.set.name) // set a
    console.log(Object.keys(obj2))
    

    ES6-8 - 函数名/对象拓展、描述符、getter/setter_第6张图片
    ES6-8 - 函数名/对象拓展、描述符、getter/setter_第7张图片

    你可能感兴趣的:(系统学习,#,ES6)