• 1. Object.getOwnPropertyNames()

  在学习使用该方法的时候,查阅了《JavaScript高级程序设计》与 MDN 来综合学习。

  先来看看MDN对其的表述:

  参数

     obj:
  一个对象,其自身的可枚举和不可枚举属性的名称被返回。

  返回值

      在给定对象上找到的属性对应的字符串数组。

   描述

    Object.getOwnPropertyNames() 返回一个数组,该数组对元素是 obj自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for...in 循环(或 Object.keys)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。

  

  同时,举出了几个例子来表显示,例如:

var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]

// 类数组对象
var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]

// 使用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
  console.log(val + " -> " + obj[val]);
});
// 输出
// 0 -> a
// 1 -> b
// 2 -> c

//不可枚举属性
var my_obj = Object.create({}, {
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});
my_obj.foo = 1;

console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]

  正如:MDN上所述,该方法返回的是对象自身的可枚举与不可枚举属性,即返回的是一个数组。并且在查阅《JavaScript高级程序设计》这本书籍的时候,却发现了一个问题。

function Person(){

}
Person.prototype.name = 'asfd'
Person.prototype.age = 15
Person.prototype.sayName = function () {
console.log(this.name)
}
var keys = Object.getOwnPropertyNames(Person.prototype) console.log(keys) 
// 书籍中表述keys返回的是 ['constructor', 'name', 'age', 'sayName']
// 但是当将Person.property设置一个以对象字面量形式创建的对象时,就不再返回constructor. 书籍中已经解释此时的constructor不再指向Person
// 于是,我真的操作了一遍才发现,真的如此
// 实例如下:
function Person(){ } Person.prototype = { name: 'zwj', age: 21, say: function () { console.log('say') } }
var keys = Object.getOwnPropertyNames(Person.property)
console.log(keys)
// 此时返回的 ['name','age','sayName']

  我根据书中理解如下:设置一个以对象字面量形式创建的对象,虽然结果相同,但是constructor不再指向Person,这就涉及到原型链了

  首先,每个构造函数被创建的时候,同时就创建了一个构造函数对应的原型对象,即: 构造函数.prototype 

  这个对象就会自动获得一个constructor属性,这个属性就是该对象指向构造函数的指针,你也可以试试输出: Person.prototype    Person.prototype.constructor     Person.prototype.constructor.prototype 等等,就会发现形成了一个闭环...

  这里我们使用的语法去接收属性值,本质上默写了prototype对象,这时候,改写的对象默认的constructor指向为Object构造函数,毕竟函数也是对象,在JS中一切皆为对象...

  所以如果我们通常为了在原型上进行大量的属性写入,就必须对这部分操作进行注意,需要在使用设置对象字面量方式之后手动为其添加constructor属性的指向,这样做的目的就是为了确保通过该属性能够访问到适当的值...

  当然你会觉得这样设置并不是完美,毕竟对于constructor这个属性,他应该是不可枚举的,此时,却是可枚举的,这是就需要我们使用Object.defineProperty()进行相应的设置.相应的代码如下:

function Person(){
}
// 此时重写了prototype对象 constructor指向Object
Person.prototype = {
  name: 'Nick',
  age: 15,
  sayName: function(){
    consolelog(this.name)
  }  
}
// 对constructor进行设置修改
Object.defineProperty(Person.prototype, 'constructor', {
   enumerable: false,   // 设置是否可枚举  false为不可枚举
   value: Person         // 设置值为Person
})
//可以通过definePrototype进行更改数据属性的共有6个,其余4个分别为:
// configurable  ----------> 表示是否可以通过delete进行删除 默认为true
// writable        ----------> 表示是否可以修改属性的值 默认为true
// get ----------> 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
// set --------> 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。

  

  总结: 在进行创建构造函数的时候,以前习惯只是将constructor直接写在重写的prototype对象中,但是却忽略了其中最重要的一条信息,那就是constructor属性本身是不可枚举的属性,还需要更深一层的操作去设置constructor.看问题不能只看表面,更应该注重于内在...