关于javascript:javascript高级程序设计学习笔记-82创建对象

4次阅读

共计 16100 个字符,预计需要花费 41 分钟才能阅读完成。

关注前端小讴,浏览更多原创技术文章

创建对象

  • 创立单个对象:Object 构造函数 和 对象字面量
  • 毛病:应用一个接口创立很多对象,产生大量反复代码

相干代码 →

工厂模式

  • 形象创立特定对象的过程,依照特定接口 创建对象
function createPerson(name, age, job) {var o = new Object()
  o.name = name
  o.age = age
  o.job = job
  o.sayName = function () {console.log(this.name)
  }
  return o
}
var person1 = createPerson('Nicholas', 29, 'Engineer')
var person2 = createPerson('Greg', 27, 'Doctor')
console.log(person1)
console.log(person2)
  • 工厂模式解决了创立多个类似对象的问题,但 没有解决对象辨认问题(怎么晓得一个对象的类型)

构造函数模式

  • 除了 Object 和 Array 等原生构造函数,还能够 创立自定义的构造函数
  • 构造函数模式 vs 工厂模式

    • 不显式的创建对象
    • 间接将属性和办法赋给 this 对象
    • 没有 return
function Person(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.sayName = function () {console.log(this.name)
  }
}
var person1 = new Person('Nicholas', 29, 'Software Engineer')
var person2 = new Person('Greg', 27, 'Doctor')
  • 构造函数用大写字母结尾,创立实例时用 new 操作符
  • 构造函数 new 一个对象后:

    • 创立了一个新对象(实例)
    • 新对象外部的 [[Prototype]] 个性被赋值为构造函数的 prototype 属性(独特指向原型)
    • 将构造函数的作用域(即 this)赋给新对象
    • 执行构造函数中的代码(即:为这个对象增加新属性)
    • 返回新对象或非空对象
  • 创立的对象(实例)既是 Object 的实例 ,又是 构造函数的实例 ,其 constructor 属性 指向构造函数
  • 能够确保自定义构造函数的 实例被标识为特定的类型,是构造函数模式胜过工厂模式的中央
console.log(person1.constructor === Person) // true,constructor 属性指向构造函数
console.log(person2.constructor === Person) // true,constructor 属性指向构造函数
console.log(person1 instanceof Object) // true,person1 是 Object 的实例
console.log(person1 instanceof Person) // true,person1 是 Person 的实例
console.log(person2 instanceof Object) // true,person2 是 Object 的实例
console.log(person2 instanceof Person) // true,person2 是 Person 的实例
  • 构造函数也能够应用 函数表达式 示意,实例化 不传参数 时,构造函数前面的 括号可加可不加
var PersonExpression = function () {
  // 构造函数的函数表达式
  this.name = 'Jake'
  this.sayName = function () {console.log(this.name)
  }
}
var personNoBrackets = new PersonExpression() // 实例化不传参数,可不加括号

构造函数也是函数

  • 构造函数与一般函数 惟一的区别 调用形式不同 :应用new 操作符调用的就是构造函数,不应用的是一般函数
  • 默认状况下,调用函数时的 this 指向 Global 对象(浏览器中指向 window 对象)
var person3 = new Person('Nicholas', 29, 'Software Engineer') // 用构造函数创建对象
person3.sayName() // 'Nicholas'
Person('Greg', 27, 'Doctor') // 'Greg',不应用 new 操作符,间接调用
global.sayName() // 间接调用函数,this 指向 Global 对象(浏览器中指向 window 对象)var o = new Object() // 新对象 o
var p = new Object() // 新对象 p
Person.call(o, 'Kristen', 25, 'Nurse') // 将对象 o 指定为 Person()外部的 this 值,call()别离传入每个参数
Person.apply(p, ['Kristen', 25, 'Nurse']) // 将对象 o 指定为 Person()外部的 this 值,apply()传入参数数组
o.sayName() // 'Kristen'
p.sayName() // 'Kristen'

构造函数的问题

  • 定义的办法会在每个实例上都创立一遍,每定义一个函数,就实例化一个对象,创立 2 个实现同样工作的 Function 实例没有必要
function Person2(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.sayName = new Function(console.log(this.name)) // 与申明函数逻辑等价,每创立一个对象就要创立一个 Function 实例
}
console.log(person1.sayName === person2.sayName) // false,新对象的 2 个办法的作用域链和标识符解析不同
  • 将对象的办法移到构造函数内部,防止屡次创立 Function 实例
function Person3(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.sayName = sayName
}
function sayName() {console.log(this.name) // 将 sayName 设置成全局函数
}
var person4 = new Person('Nicholas', 29, 'Software Engineer')
  • 构造函数 仍未解决 的问题:① 创立的全局函数实际上只须要被某个对象中调用;② 若对象有多个办法,需创立很多全局办法

原型模式

  • 每个函数都有 prototype 属性,该属性是一个 指针 ,指向函数(通过 调用构造函数 而创立的那个对象实例的)原型对象
  • 应用原型对象的益处是,其所有对象实例 共享其所蕴含的属性和办法
function PersonPrototype() {}
PersonPrototype.prototype.name = 'Nicholas' // 为 PersonPrototype 的原型对象增加属性
PersonPrototype.prototype.age = 29 // 为 PersonPrototype 的原型对象增加属性
PersonPrototype.prototype.job = 'Software Engineer' // 为 PersonPrototype 的原型对象增加属性
PersonPrototype.prototype.sayName = function () {
  // 为 PersonPrototype 的原型对象增加办法
  console.log(this.name)
}

var person5 = new PersonPrototype()
var person6 = new PersonPrototype()

person5.sayName() // 'Nicholas'
person6.sayName() // 'Nicholas'
console.log(person5.sayName === person6.sayName) // true,原型对象上创立的属性和办法,由所有实例共享

了解原型对象

  • 只有 创立一个函数 ,就会为函数创立prototype 属性 指向原型对象 ,(默认状况下)原型对象主动取得constructor 属性,指回与之关联的构造函数
console.log(PersonPrototype.prototype.constructor) // PersonPrototype 构造函数,原型对象的 constructor 属性指向与之关联的构造函数
console.log(PersonPrototype === PersonPrototype.prototype.constructor) // true,都指向构造函数
  • 实例外部蕴含 [[Prototype]] 指针,指向 实例的构造函数的 原型对象,但没有规范的形式拜访[[Prototype]]
  • 在浏览器中,可用 __proto__ 属性实现 [[Prototype]] 的性能
console.log(person5.__proto__) // 原型对象,PersonPrototype {name: 'Nicholas',age: 29,job: 'Software Engineer',sayName: [Function] }
console.log(person5.__proto__ === PersonPrototype.prototype) // true,都指向原型对象
console.log(person5.__proto__.constructor) // Function: PersonPrototype 构造函数
console.log(person5.__proto__ === person6.__proto__) // true,共享同一个原型对象
  • instanceof查看 实例的原型链 中,是否 蕴含指定构造函数的原型
console.log(person5 instanceof PersonPrototype) // true,person5 是 PersonPrototype 的实例
console.log(person5 instanceof Object) // true,person5 是 Object 的实例
console.log(PersonPrototype.prototype instanceof Object) // true,所有实例对象和原型对象都是 Object 的实例
  • 原型对象的 isPrototypeOf()办法,检测 实例 是否有指向原型对象 的指针
console.log(PersonPrototype.prototype.isPrototypeOf(person5)) // true,person5 蕴含指向 PersonPrototype 的原型对象的指针
console.log(PersonPrototype.prototype.isPrototypeOf(person1)) // false,person1 不蕴含指向 PersonPrototype 的原型对象的指针
  • Object.getPrototypeOf()办法(参数个别为实例),返回参数的 [[Prototype]] 的值(个别为原型对象)
console.log(Object.getPrototypeOf(person5)) // 原型对象
console.log(Object.getPrototypeOf(person5) === person5.__proto__) // true,都指向原型对象
console.log(Object.getPrototypeOf(person5) === PersonPrototype.prototype) // true,都指向原型对象
console.log(Object.getPrototypeOf(person5).name) // 'Nicholas'
console.log(Object.getPrototypeOf(person5).constructor) // Function: PersonPrototype 构造函数
  • Object.setPrototypeOf()办法,向实例(参数一)的 [[Prototype]] 写入一个新值(参数二),从而 重写 一个对象的 原型继承关系
var biped = {numLegs: 2,}
var person = {name: 'Matt',}
Object.setPrototypeOf(person, biped)
console.log(person.name) // 'Matt'
console.log(person.numLegs) // 2
console.log(person.__proto__) // {numLegs: 2},person 的 [[Prototype]] 指针指向 biped
  • 为防止 Object.setPrototypeOf() 可能 重大影响代码性能 ,可应用Object.create() 创立一个新对象 ,同时为其 指定原型(参数)
var biped2 = {numLegs: 3,}
var person = Object.create(biped2)
console.log(person.numLegs) // 3
console.log(person.__proto__) // {numLegs: 3},person 的 [[Prototype]] 指针指向 biped2

原型层级

  • 代码读取对象属性的搜寻过程:

    • 1. 搜寻对象实例自身 -> 有属性 → 返回属性值 -> 完结
    • 2. 对象实例自身无属性 -> 搜寻原型对象 → 有 / 无属性 → 返回属性值 /undefined → 完结
  • 能够 通过实例 拜访 原型中属性的值(如 constructor 属性),但 无奈 通过实例 重写 原型中属性的值
  • 如果增加的实例属性与原型的属性 同名 ,则实例属性 屏蔽 原型中的属性
var person7 = new PersonPrototype()
person7.name = 'Greg'
console.log(person7.name) // 'Greg',来自实例
console.log(person5.name) // 'Nicholas',来自原型
  • 删除 同名的实例属性,可 复原 被屏蔽的原型的属性
delete person7.name
console.log(person7.name) // 'Nicholas',来自原型
  • 应用 hasOwnProperty()办法,检测 属性是否存在于实例 中(存在返回 true),参数为要检测的属性
var person8 = new PersonPrototype()
var person9 = new PersonPrototype()
console.log(person8.hasOwnProperty('name')) // false,name 不存在在 person8 的实例中
person8.name = 'Simon'
console.log(person8.name) // 'Simon',来自实例
console.log(person8.hasOwnProperty('name')) // true,name 存在在 person8 的实例中
console.log(person9.name) // 'Nicholas',来自原型
console.log(person9.hasOwnProperty('name')) // false,name 不存在在 person8 的实例中
delete person8.name
console.log(person8.name) // 'Nicholas',来自原型
console.log(person8.hasOwnProperty('name')) // false,person8 实例的 name 属性已被删除
  • 可在原型对象上调用 Object.getOwnPropertyDescriptor(),获取原型属性的描述符
console.log(Object.getOwnPropertyDescriptor(person8, 'name')) // undefined,person8 实例上没有 name 属性
console.log(Object.getOwnPropertyDescriptor(person8.__proto__, 'name')) // {value: 'Nicholas',writable: true,enumerable: true,configurable: true},原型对象的 name 属性描述符

原型和 in 操作符

  • 独自应用 in 操作符:对象可能拜访指定属性则返回 true,无论属性在实例中还是原型中
function PersonIn() {}
PersonIn.prototype.name = 'Nicholas'
PersonIn.prototype.age = 29
PersonIn.prototype.job = 'Software Engineer'
PersonIn.prototype.sayName = function () {console.log(this.name)
}
var person9 = new PersonIn()
var person10 = new PersonIn()

console.log(person9.hasOwnProperty('name')) // false,实例 person9 中不含 name 属性
console.log('name' in person9) // true,通过 person9 能够拜访到 name 属性

person9.name = 'Greg'
console.log(person9.name); // 'Greg',来自实例
console.log(person9.hasOwnProperty('name')) // true,实例 person9 中蕴含 name 属性
console.log('name' in person9) // true,通过 person9 能够拜访到 name 属性
console.log(person10.name); // 'Nicholas',来自原型
console.log(person10.hasOwnProperty('name')) // false,实例 person10 中不含 name 属性
console.log('name' in person10) // true,通过 person10 能够拜访到 name 属性

delete person9 'name'
console.log(person9.name); // 'Nicholas',来自原型
console.log(person9.hasOwnProperty('name')) // false,实例 person9 中不含 name 属性
console.log('name' in person9) // true,通过 person9 能够拜访到 name 属性
  • 同时应用 hasOwnProperty()in操作符,判断 属性存在于实例还是原型
function hasPrototypeProperty(object, name) {return !object.hasOwnProperty(name) && name in object // 不存在于实例 && 能拜访到 → 存在于原型
}
var person11 = new PersonIn()
console.log(hasPrototypeProperty(person11, 'name')) // true,!false && true
person11.name = 'Greg'
console.log(hasPrototypeProperty(person11, 'name')) // false,!true && true
  • for-in 循环:返回对象所有 可能拜访的 可枚举的 属性(无论来自实例还是原型),屏蔽 不可枚举 ([[Enumerable]] 为 false)的属性(如:原型的 constructor、构造函数的 prototype)
for (var attr in person11) {console.log(`${attr}:${person11[attr]}`)
  /*  
    name:Greg
    age:29
    job:Software Engineer
    sayName:function () {console.log(this.name)
    } 
  */
}
  • Object.keys()办法返回对象(本身 可枚举的 属性的数组,参数为该对象
var keys = Object.keys(PersonIn.prototype) // 原型对象的所有可枚举属性
console.log(keys) // ['name', 'age', 'job', 'sayName']
var person12 = new PersonIn()
person12.name = 'Bob'
person12.age = 31
var p12keys = Object.keys(person12) // person12 的所有可枚举属性
console.log(p12keys) // ['name', 'age']
  • Object.getOwnPropertyNames()返回对象(本身 所有属性(无论是否可枚举)的数组,参数为该对象
var keys = Object.getOwnPropertyNames(PersonIn.prototype) // 原型对象的所有属性,蕴含不可枚举
console.log(keys) // ['constructor', 'name', 'age', 'job', 'sayName'],原型对象都蕴含 constructor 属性,指向构造函数
var p12keys = Object.getOwnPropertyNames(person12) // person12 的所有属性,蕴含不可枚举
console.log(p12keys) // ['name', 'age']
console.log(Object.getOwnPropertyNames(PersonIn)) // ['length', 'name', 'arguments', 'caller', 'prototype']
  • ES6 新增 Object.getOwnPropertySymbols() 办法,返回对象(本身 所有符号键属性(无论是否可枚举)的数组,参数为该对象
var k1 = Symbol('k1')
var k2 = Symbol('k2')
var o = {[k1]: 'k1', // 符号作为属性,需应用“计算属性”语法,即[属性名]
  [k2]: 'k2',
}
console.log(Object.getOwnPropertySymbols(o)) // [Symbol(k1), Symbol(k2) ]

属性枚举程序

  • for-in循环和 Object.keys()属性枚举程序 不确定 的,取决于浏览器的 JS 引擎
  • Object.getOwnPropertyNames()Object.getOwnPropertySymbols()Object.assign()属性枚举程序 确定 的:

    • 升序 枚举 数值键
    • 插入程序 枚举 字符串和符号键
var k1 = Symbol('k1')
var k2 = Symbol('k2')
var o = {
  1: 1,
  first: 'first',
  [k2]: 'sym2',
  third: 'third',
  0: 0,
}
o[k1] = 'sym1'
o[3] = 3
o.second = 'second'
o[2] = 2
console.log(Object.getOwnPropertyNames(o)) // ['0', '1', '2', '3', 'first', 'third', 'second']
console.log(Object.getOwnPropertySymbols(o)) // [Symbol(k2), Symbol(k1) ]

对象迭代

  • ES7 新增 Object.values()Object.entries()办法,接管参数对象,别离返回 对象值 对象键 / 值对 数组
var o = {
  foo: 'bar',
  baz: 1,
  qux: {},}
console.log(Object.values(o)) // ['bar', 1, {} ],迭代值
console.log(Object.entries(o)) // [[ 'foo', 'bar'], ['baz', 1], ['qux', {} ] ],迭代键值对
  • 非字符串属性 转换为字符串 ,办法执行对象的 浅复制
var o = {qux: {},
}
console.log(Object.values(o)) // [{} ]
console.log(Object.entries(o)) // [[ 'qux', {} ] ]
console.log(Object.values(o)[0] === o.qux) // true,浅复制,复制对象的援用
console.log(Object.entries(o)[0][1] === o.qux) // true,浅复制,复制对象的援用
  • 符号属性 会被 疏忽
var sym = Symbol()
var o = {[sym]: 'foo', // 符号属性
}
console.log(Object.values(o)) // [],符号属性被疏忽
console.log(Object.entries(o)) // [],符号属性被疏忽

其余原型语法

  • 蕴含所有属性和办法 新对象 字面量来 重写整个原型对象
function PersonLiteral() {}
PersonLiteral.prototype = {
  name: 'Nicholas',
  age: 29,
  job: 'Software Engineer',
  sayName: function () {console.log(this.name)
  },
}
  • 将构造函数的 prototype 属性设置为一个以 对象字面量 模式创立 新对象 ,其constructor 属性 不再指向原构造函数 ,而是新对象的constructor 属性,即Object 构造函数
var friend = new PersonLiteral()
console.log(friend instanceof Object) // true,friend 是 Object 的实例
console.log(friend instanceof PersonLiteral) // true,friend 是 PersonLiteral 的实例
console.log(friend.constructor === PersonLiteral) // false,constructor 属性变成了新对象——即对象字面量的 constructor
console.log(friend.constructor === Object) // true,新对象的 constructor 指向 Object 构造函数
  • 能够在对象字面量里设置 constructor 属性,让其指向原构造函数
  • 这样设置 constructor 属性属于 间接在对象上定义的属性 ,会导致constructor 属性的 [[Enumerable]] 为 true,能够被枚举进去
function PersonLiteral2() {}
PersonLiteral2.prototype = {
  constructor: PersonLiteral2, // 间接在对象上定义 constructor,指向原构造函数
  name: 'Nicholas',
  age: 29,
  job: 'Software Engineer',
  sayName: function () {console.log(this.name)
  },
}
var friend2 = new PersonLiteral2()
console.log(friend2.constructor === PersonLiteral2) // true,constructor 再次指向原构造函数
console.log(friend2.constructor === Object) // false
console.log(Object.keys(PersonLiteral2.prototype)) // ['constructor', 'name', 'age', 'job', 'sayName'],因为 constructor 是“间接在对象上定义的属性”,可被枚举进去
  • 不在对象字面量内设置 constructor 属性,而用 Object.defineProperty() 批改对象字面量中 constructor 属性的个性,以兼容 JavaScript 引擎
Object.defineProperty(PersonLiteral2.prototype, 'constructor', {
  enumerable: false,
  value: PersonLiteral2,
})
console.log(Object.keys(PersonLiteral2.prototype)) // ['name', 'age', 'job', 'sayName'],constructor 的 enumerable 已被设置为 false

原型的动态性

  • 原型对象 所做的 任何批改 立刻从实例上反映 进去,即便先创立实例后批改原型
function Person4() {}
var friend3 = new Person4() // 先创立实例
Person4.prototype.sayHi = function () {
  // 后批改原型对象
  console.log('Hi')
}
friend3.sayHi() // 'Hi',实例受影响,实例指向原型
  • 重写整个原型 ,会切断构造函数与最后原型之间的分割,(重写原型前创立的) 实例 的[[Prototype]]指针 指向最后的原型(重写原型后创立的实例指向新原型)
Person4.prototype = {
  // 重写原型
  constructor: Person4,
  name: 'Nicholas',
  age: 29,
  job: 'Software Engineer',
  sayName: function () {console.log(this.name)
  },
}
console.log(friend3.__proto__) // Person4 {sayHi: [Function] },friend3 在重写原型前创立,[[Prototype]]指向最后的原型对象
console.log(friend3.__proto__ === Person4.prototype) // false,重写整个原型切断了构造函数与最后原型之间的分割
friend3.sayName() // error:friend3.sayName is not a function

原生对象原型

  • 所有 原生的援用类型 (Array、Object、String…)都是用 原型模式 创立的,在其构造函数的 原型上定义了办法
console.log(Array.prototype) // 在浏览器中查看 Array 的原型对象,蕴含 sort()等办法
console.log(String.prototype) // 在浏览器中查看 Array 的原型对象,蕴含 substring()等办法
  • 能够像批改自定义对象的原型一样,批改原生对象的原型,增加或删除办法
  • 不举荐 批改原生对象的原型,可能会引起抵触或重写原生办法
String.prototype.startsWith = function (text) {
  // 给 String 的原型对象增加 startsWith 办法
  return this.indexOf(text) === 0
}
var msg = 'Hello World'
console.log(msg.startsWith('Hello')) // true
console.log(msg.startsWith('World')) // false
delete String.prototype.startsWith
console.log(msg.startsWith('Hello')) // error

原型的问题

  • 原型模式最大的问题是由其 共享 的本色导致的,尤其对于蕴含 援用类型 的属性,对实例的数组、对象等 援用类型的属性进行增删改 而非从新定义时,会对原型的援用类型属性造成影响
function PersonProblem() {}
PersonProblem.prototype = {
  constructor: PersonProblem,
  name: 'Nicholas',
  age: 29,
  job: 'Software Engineer',
  friends: ['Shelby', 'Court'],
  sayName: function () {console.log(this.name)
  },
}
var person13 = new PersonProblem()
var person14 = new PersonProblem()
person13.name = 'Greg' // 从新定义,在实例中屏蔽原型的属性
person13.friends.push('Van') // 非从新定义,而是向原型的数组中增加一个字符串
console.log(person13.name) // 'Greg',从实例取得
console.log(person14.name) // 'Nicholas',从原型中取得
console.log(person13.friends) // ['Shelby', 'Court', 'Van'],从原型中取得
console.log(person14.friends) // ['Shelby', 'Court', 'Van'],从原型中取得
console.log(person13.friends === person14.friends) // true
var person15 = new PersonProblem()
person15.friends = [] // 从新定义,在实例中屏蔽原型的属性
console.log(person15.friends) // [],从实例取得
console.log(person13.friends) // ['Shelby', 'Court', 'Van'],从原型中取得
console.log(person14.friends) // ['Shelby', 'Court', 'Van'],从原型中取得

总结 & 问点

创建对象 过程 毛病
Object 构造函数 1. 创立 Objecty 实例 2. 增加属性和办法 同一接口创立多个对象,大量反复代码
对象字面量 间接创立蕴含属性和办法的对象 同一接口创立多个对象,大量反复代码
工厂模式 1. 用函数封装创立 Object 实例的过程(增加属性和办法、返回该实例对象)2. 调用该函数 没有解决对象辨认问题,即怎么晓得一个对象的类型
构造函数模式 1. 构造函数封装(不显示的创建对象、属性和办法赋给 this 对象、无 return)2.new 调用构造函数 每个实例从新创立办法,机制雷同的 Function 对象被屡次实例化
原型模式 1. 构造函数封装(空的,无属性和办法)2. 原型对象上增加属性和办法 3.new 调用构造函数 对实例来自原型的援用类型属性批改而非从新定义时,会对原型造成影响
对象 属性 默认指向 用法
任何函数 prototype 原型对象 Person.prototype → 构造函数的原型对象
实例、原型 constructor 构造函数 person1.constructor === Person.prototype.constructor === Person
实例 [[Prototype]] 原型对象 person1.__proto__ === Person.prototype(没有规范形式拜访[[Prototype]],但可用 __proto__
操作符 含意 用法
new 创立构造函数的实例(四个步骤 var person = new Person()
delete 删除实例属性 delete person.name
in 是否通过对象拜访到属性(无论属性在实例还是原型中) console.log('name' in person)
for-in 返回所有能通过对象拜访到的、可枚举的属性(无论属性在实例还是原型中) for(var attr in person){console.log(attr)}
办法 含意 参数 返回值
isPrototypeOf() 实例是否有指向原型对象的指针 实例 true/false
Object.getPrototypeOf() 获取实例 [[Prototype]] 的值 实例 原型对象
Object.setPrototypeOf() 向实例的 [[Prototype]] 写入新值(指定原型) ① 实例 ② 指定原型
Object.create() 创立一个新对象,同时为其指定原型 指定原型
hasOwnProperty() 属性是否存在于实例中(非原型中) 属性 true/false
Object.keys() 获取对象(本身)所有可枚举的属性 对象 属性的字符串数组
Object.getOwnPropertyNames() 获取对象(本身)所有属性(无论是否可枚举) 对象 属性的字符串数组(原型对象蕴含 constructor 属性)
Object.getOwnPropertySymbols() 获取对象(本身)所有符号键属性(无论是否可枚举) 对象 属性的符号键数组(原型对象蕴含 constructor 属性)
办法 / 操作符 枚举程序
for-in 枚举程序不确定,取决于浏览器的 JS 引擎
Object.keys() 枚举程序不确定,取决于浏览器的 JS 引擎
Object.getOwnPropertyNames() 枚举程序确定:先以升序枚举数值键,后以插入程序枚举字符串和符号键
Object.getOwnPropertySymbols() 枚举程序确定:先以升序枚举数值键,后以插入程序枚举字符串和符号键
  • 创立单个对象有哪些办法?这些办法有什么毛病?
  • 工厂模式做出了怎么的优化?该模式有什么毛病?
  • 相比工厂模式,构造函数模式有哪些区别和劣势?其在 new 的过程中都产生了什么?
  • 构造函数创立出的对象,其 construtor 属性指向哪里?这样的对象是哪些构造函数的实例?
  • 相比一般函数,构造函数有什么相同点和区别?
  • 构造函数模式有什么毛病?用全局函数代替构造函数外部对象的办法,仍有什么毛病?
  • 函数的 prototype 属性是什么?应用原型对象的益处是什么?如何了解原型对象的 constructor 属性?
  • 构造函数、实例、原型对象之间,别离能够用什么形式互相获取?用什么办法检测实例是否含有指向原型对象的指针?
  • Object.getPrototypeOf()、Object.setPrototypeOf()、Object.create()别离的含意和用法是什么?
  • 代码读取对象属性时,经验了怎么的搜寻过程?是否能够通过实例拜访和批改原型中的属性值?
  • 在实例中增加与原型的同名属性会怎么?再删除这个实例中新增的属性呢?
  • 独自应用 in 操作符的含意是什么?其和 hasOwnProperty()办法的区别是什么?
  • 请写一段代码,判断某个属性存在于实例还是原型
  • for-in 的用法是什么?其返回哪些属性屏蔽哪些属性?
  • Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()、Object.values()、Object.entries()的用法别离是什么?
  • for-in、Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()在属性枚举时的程序有什么区别?
  • 用一个对象字面量的新对象重写整个原型对象时,原型对象的 constructor 指向产生了怎么的扭转?
  • 写一段代码,用对象字面量重写构造函数的原型对象,且原型对象的 constructor 仍指向原构造函数,并保留 construtor 属性“不可被枚举”的个性
  • 创立实例后再批改原型的属性,实例会受到影响么?为什么?
  • 重写整个原型对象后,构造函数的 prototype 指向哪里?重写前创立的实例的 [[Prototype]] 属性指向哪里?为什么?
  • 原生援用类型的办法是如何创立的?为什么不举荐批改原生援用类型的原型?
  • 原型模式的“共享”本色,在批改蕴含援用类型的属性时,会产生怎么的问题?
正文完
 0