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

3次阅读

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

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

创建对象

  • 创立单个对象: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 等原生构造函数,还能够创立自定义的构造函数
function Person(name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  this.sayName = function () {console.log(this.name)
  }
}
var person1 = Person('Nicholas', 29, 'Software Engineer')
var person2 = Person('Greg', 27, 'Doctor')
  • 构造函数模式 vs 工厂模式:① 不显式的创建对象;② 间接将属性和办法赋给 this 对象;③ 没有 return
  • 构造函数 new 一个对象后:① 创立了一个新对象;② 将构造函数的作用域(即 this)赋给新对象;③ 执行构造函数中的代码(即:为这个对象增加新属性);④ 返回新对象
  • 构造函数用大写字母结尾,创立实例时用 new 操作符
  • 创立的对象的 constructor 属性指向构造函数
  • 创立的对象既是 Object 的实例,又是构造函数的实例
console.log(person1.constructor === Person) // true,constructor 属性指向构造函数
console.log(person2.constructor === Person) // true,constructor 属性指向构造函数
console.log(person1 instanceof Object) // true,是 Object 的实例
console.log(person1 instanceof Person) // true,也是 Person 的实例
console.log(person2 instanceof Object) // true,是 Object 的实例
console.log(person2 instanceof Person) // true,也是 Person 的实例
  • 能够将自定义构造函数的实例标识为一种特定的类型,这是构造函数模式胜过工厂模式的中央
  • 以该办法定义的构造函数是定义在 Global 对象中的,在浏览器中则是 window 对象
// 构造函数 vs 一般函数
var person3 = new Person('Nicholas', 29, 'Software Engineer') // 用构造函数创建对象
person3.sayName() // 'Nicholas'
Person('Greg', 27, 'Doctor') // 不应用 new 操作符,间接调用
global.sayName() // 间接调用函数时,this 指向 Global 对象(浏览器中指向 window 对象)var o = new Object() // 新对象 o
var p = new Object() // 新对象 p
Person.call(o, 'Kristen', 25, 'Nurse') // 裁减作用域,在对象 o 中调用 Person()函数,call()别离传入每个参数
Person.apply(p, ['Kristen', 25, 'Nurse']) // 裁减作用域,在对象 p 中调用 Person()函数,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(构造函数)属性,指向 prototype 属性所在函数的指针,即构造函数
console.log(PersonPrototype.prototype.constructor) // Function: PersonPrototype 构造函数
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 构造函数
  • 原型对象的 isPrototypeOf()办法,检测实例中否有指向原型对象的指针
console.log(PersonPrototype.prototype.isPrototypeOf(person5)) // true,person5 蕴含指向 PersonPrototype 的原型对象的指针
console.log(PersonPrototype.prototype.isPrototypeOf(person1)) // false,person1 不蕴含指向 PersonPrototype 的原型对象的指针
  • ES5 追加 Object.getPrototypeOf()办法,参数为实例,返回实例的构造函数的原型对象
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 构造函数
  • 代码读取对象属性的搜寻过程:

    • 1. 搜寻对象实例自身 -> 有属性 → 返回属性值 -> 完结
    • 2. 对象实例自身无属性 -> 搜寻原型对象 → 有 / 无属性 → 返回属性值 /undefined → 完结
  • 能够通过实例拜访原型中属性的值,但无奈通过实例重写原型中属性的值
  • 如果增加的实例属性与原型的属性同名,则实例属性屏蔽原型中的属性
  • 删除同名的实例属性,可复原被屏蔽的原型的属性
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(‘ 属性 ’) 检测属性存在于实例 or 原型,存在于实例返回 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,判断属性存在于 对象 or 原型
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 循环应用 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']

更简略的原型语法

  • 蕴含所有属性和办法 新对象 字面量来 重写整个原型对象
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 属性属于“间接在对象上定义的属性”,会导致 PersonLiteral2.prototype 的 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
var keys = Object.keys(PersonLiteral2.prototype)
console.log(keys) // ['constructor', 'name', 'age', 'job', 'sayName'],因为 constructor 是“间接在对象上定义的属性”
  • 用 Object.defineProperty()批改对象字面量中 constructor 属性的个性,以兼容 ES5 的 javascript 引擎
Object.defineProperty(PersonLiteral2.prototype, 'constructor', {
  enumerable: false,
  value: PersonLiteral2,
})
var keys = Object.keys(PersonLiteral2.prototype)
console.log(keys) // ['name', 'age', 'job', 'sayName'],constructor 的 enumerable 已被设置为 false

原型的动态性

  • 对原型对象所做的任何批改都立刻从实例上反映进去,即便先创立实例后批改原型
function Person4() {}
var friend3 = new Person4()
Person4.prototype.sayHi = function () {console.log('Hi')
}
friend3.sayHi() // 'Hi',先在 friend3 实例中搜寻 sayHi 属性,没有找到则持续找原型对象
  • 重写整个原型对象,会切断构造函数与最后原型之间的分割,而实例的 [[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] },最后的原型对象
console.log(friend3.__proto__ === Person4.prototype) // false,实例的__proto__指向最后的原型对象,重写整个原型切断了构造函数与最后原型之间的分割
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'],从原型中取得

组合应用构造函数模式和原型模式

  • 构造函数模式用于 定义实例属性 ,原型模式用域 定义方法 共享的属性
  • 每个实例都有本人的一份实例属性的正本,同时共享着对办法的援用,最大限度 节俭内存
  • 该模式是目前 ECMAScript 中应用最宽泛、认同度最高的创立自定义类型的办法
function PersonMix(name, age, job) {
  // 在构造函数定义实例属性
  this.name = name
  this.age = age
  this.job = job
  this.friends = ['Shelby', 'Court']
}
PersonMix.prototype = {
  // 在原型定义方法和共享的属性
  constructor: PersonMix, // 间接在对象上定义 constructor 属性,指向构造函数,[[Enumerable]]为 true
  sayName: function () {console.log(this.name)
  },
}
var person16 = new PersonMix('Nicholas', 29, 'Software Engineer')
var person17 = new PersonMix('Greg', 27, 'Doctor')
person16.friends.push('Van') // 仅向 person16 实例自身的 friends 数组 push 数据
console.log(person16.friends) // ['Shelby', 'Court', 'Van']
console.log(person17.friends) // ['Shelby', 'Court']
console.log(person16.friends === person17.friends) // false,person16 实例的 friends 数组 push 了数据
console.log(person16.sayName === person17.sayName) // true,共享方法 sayName

动静原型模式

  • 将所有信息(属性、办法)都封装在构造函数中,通过查看某个办法是否无效,来决定是否须要初始化原型
function PersonDynamic(name, age, job) {
  // 属性
  this.name = name
  this.age = age
  this.job = job
  // 办法:①只有办法不存在时才增加到原型;②只在首次调用构造函数时执行;③会立刻在实例中体现
  if (typeof this.sayName !== 'function') {PersonDynamic.prototype.sayName = function () {console.log(this.name)
    }
  }
}
var person18 = new PersonDynamic('Nicholas', 29, 'Software Engineer')
person18.sayName() // 'Nicholas'
console.log(person18 instanceof PersonDynamic) // true,person18 是 PersonDynamic 的实例
  • 只有在办法不存在时,才会将办法增加到原型
  • 只在首次调用构造函数时才会执行,尔后原型曾经实现初始化
  • 对原型所做的批改,会立刻在实例中体现
  • 原型的动态性 同理,如果曾经创立了实例后再用 对象字面量 重写原型,会切断实例与新原型之间的分割,导致批改有效
PersonDynamic.prototype = {
  newName:
    typeof this.newName !== 'function'
      ? function () {console.log('prototype:', this.name)
        }
      : this.newName,
}
person18.newName() // error,person18 指向最后的原型,没有 newName 办法
var person19 = new PersonDynamic('Greg', 27, 'Doctor') // person19 是重写原型后创立的实例
person19.newName() // prototype: Greg
person19.sayName() // Greg

console.log(person18 instanceof PersonDynamic) // false,person18 不是重写原型后的 PersonDynamic 的实例,person18 指向最后的原型
console.log(person19 instanceof PersonDynamic) // true,person19 是重写原型后的 PersonDynamic 的实例

寄生构造函数模式

  • 构造函数仅封装 创建对象的代码,在构造函数外部用原生援用类型创立新对象,通过操作后再返回这个新对象
  • 构造函数外部跟工厂模式截然不同,调用时用 new 操作符,相似于工厂模式与构造函数模式的结合体
function PersonParasitic(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 person20 = new PersonParasitic('Nicholas', 29, 'Software Engineer')
person20.sayName() // 'Nicholas'
  • 寄生构造函数模式创立的实例,与构造函数或构造函数的原型 没有关联,不能依赖 instanceof 确定对象类型
  • 如果能够用其余模式,不倡议该模式创立自定义对象
function SpecialArray() {var values = new Array() // 用原生援用类型创立数组
  values.push.apply(values, arguments) // 增加值
  // 增加办法
  values.toPipedString = function () {return this.join('|')
  }
  return values // 返回通过操作后的数组
}
var colors = new SpecialArray('red', 'blue', 'green')
console.log(colors.toPipedString()) // red|blue|green
console.log(SpecialArray.prototype) // SpecialArray{},构造函数的原型对象
console.log(colors.__proto__) // [],构造函数外部通过 new Array()从新初始化,其原型对象是原生对象 Array
console.log(SpecialArray.prototype === colors.__proto__) // false,二者无关联
console.log(colors instanceof SpecialArray) // false,二者无关联

稳当构造函数模式

  • 与计生构造函数相似相似,在构造函数中用原生援用类型创立新对象,但 没有公共属性 其办法也不援用 this不应用 new 调用构造函数
  • 除了构造函数外部的办法,没有其余方法可拜访到构造函数外部的原始数据(即使有其余代码给对象增加办法或属性),该模式适宜在平安环境下应用
  • 寄生构造函数模式 ,该模式下创立的实例,与构造函数或构造函数的原型 没有关联,不能依赖 instanceof 确定对象类型
function PersonSafe(name, age, job) {var o = new Object() // 用原生援用类型创建对象
  o.sayName = function () {console.log(name)
  }
  return o
}
var person21 = new PersonParasitic('Nicholas', 29, 'Software Engineer')
person21.sayName() // 'Nicholas'

总结 & 问点

创建对象 过程 毛病
Object 构造函数 1. 创立 Objecty 实例 2. 增加属性和办法 同一接口创立多个对象,大量反复代码
对象字面量 间接创立蕴含属性和办法的对象 同一接口创立多个对象,大量反复代码
工厂模式 1. 用函数封装创立 Object 实例的过程(增加属性和办法、返回该实例对象)2. 调用该函数 没有解决对象辨认问题,即怎么晓得一个对象的类型
构造函数模式 1. 构造函数封装(不显示的创建对象、属性和办法赋给 this 对象、无 return)2.new 调用构造函数 每个实例从新创立办法,机制雷同的 Function 对象被屡次实例化
原型模式 1. 构造函数封装(空的,无属性和办法)2. 原型对象上增加属性和办法 3.new 调用构造函数 对实例的援用类型属性批改而非从新定义时,会对原型的援用类型属性造成影响
组合应用构造函数模式和原型模式 1. 构造函数封装实例属性 2. 原型模式定义办法和共享属性 3.new 调用构造函数 无显著毛病,目前最宽泛认同度最高,是默认模式
动静原型模式 1. 构造函数封装所有信息(属性、查看某个办法是否无效来决定是否初始化原型)2.new 调用构造函数 无显著毛病,不要应用对象字面量重写原型
寄生构造函数模式 1. 构造函数封装(原生援用类型创立新对象、增加值或办法、返回新对象)2.new 调用构造函数 实例与构造函数或构造函数的原型没有关联,不能依赖 instanceof 确定对象类型
稳当构造函数模式 1. 同寄生构造函数模式的构造函数封装(但办法不援用 this)2. 作为一般函数调用构造函数 实例与构造函数或构造函数的原型没有关联,不能依赖 instanceof 确定对象类型
对象 属性 指向 用法
任何函数 prototype 原型对象 Person.prototype → 构造函数的原型对象
实例、原型 constructor 构造函数 person1.constructor === Person.prototype.constructor === Person
实例 [[Prototype]] 原型对象 person1.__proto__ === Person.prototype(没有规范形式拜访[[Prototype]],但可用 __proto__
操作符 含意 用法
new 创立构造函数的实例(四个步骤 var person = new Person()
in 是否通过对象拜访到属性(无论属性在实例还是原型中) console.log('name' in person)
for-in 返回所有能通过对象拜访到的、可枚举的属性(无论属性在实例还是原型中) for(var attr in person){console.log(attr)}
delete 删除实例属性 delete person.name
对象 办法 含意 参数 返回值 用法
Object 对象 getPrototypeOf() 获取实例对象的原型 实例 原型对象 Object.getPrototypeOf('person') === Person.prototype
任何对象 hasOwnProperty() 对象本身(不包含原型)是否含有该属性 属性 true/false console.log(Person.hasOwnProperty('name'))
Object 对象 keys() 获取对象上所有可枚举的属性(仅对象本身) 对象 属性的字符串数组 Object.keys(person)
Object 对象 getOwnPropertyNames() 获取对象上所有属性(仅对象本身,无论是否可枚举) 对象 属性的字符串数组 Object.getOwnPropertyNames(person),原型对象会蕴含 constructor 属性
  • 创立单个对象有哪些办法?这些办法有什
    么毛病?
  • 工厂模式做出了怎么的优化?该模式有什么毛病?
  • 相比工厂模式,构造函数模式有哪些区别?如何创立其实例?
  • 构造函数在 new 的过程中都产生了什么?
  • 构造函数创立出的对象,其 construtor 属性指向哪里?这样的对象是哪些构造函数的实例?
  • 相比工厂模式,构造函数有什么劣势?
  • 构造函数与一般函数有什么相同点和区别?
  • 自定义对象的办法时,构造函数模式有什么毛病?
  • 用全局函数代替构造函数外部的对象属性的办法,仍有什么毛病?
  • prototype 属性的含意和用法?应用原型对象的益处是什么?
  • 原型对象的 constructor 属性的含意和用法?
  • 用什么办法检测实例是否含有指向原型对象的指针?
  • 构造函数、实例的哪些属性或办法可取得原型对象?如何通过实例取得构造函数?
  • 代码读取对象属性时,经验了怎么的搜寻过程?
  • 是否能够通过实例拜访和批改原型中的属性值?
  • 在实例中增加与原型的同名属性会怎么?再删除这个实例中的属性呢?
  • 用什么办法检测属性存在与实例 or 原型?
  • 用什么办法获取原型属性的描述符?
  • 独自应用 in 的用法是什么?其和 hasOwnProperty()办法的区别是什么?
  • for-in 的用法是什么?其返回哪些属性屏蔽哪些属性?
  • Object.keys()的和 Object.getOwnPropertyNames()用法别离是什么?
  • Object.getOwnPropertyNames()、Object.leys()、for-in 的区别是什么?
  • 用一个对象字面量的新对象重写整个原型对象时,原型对象的 constructor 指向产生了怎么的扭转?
  • 写一段代码,用对象字面量重写构造函数的原型对象,且让原型对象的 constructor 仍指向原构造函数,并保留 construtor 的 [[Enumerable]] 个性为 false
  • 创立实例后再批改原型的属性,实例会受到影响么?为什么?
  • 重写整个原型对象后,构造函数的 prototype 指向哪里?实例的 [[Prototype]] 属性指向哪里?为什么?
  • 原生援用类型的办法是如何创立的?为什么不举荐批改原生援用类型的原型?
  • 原型模式的“共享”本色,在批改蕴含援用类型的属性时,有怎么的问题?
  • ECMAScript 应用最宽泛、认同度最高的创立自定义类型的办法是什么?其原理和劣势是什么?
  • 动静原型模式是如何初始化原型的?其对原型的批改有哪些留神点?
  • 寄生构造函数模式的原理是什么?为什么其创立的实例,与其构造函数或构造函数的原型没有关联?
  • 稳当构造函数模式的原理是什么?为什么该模式比拟“稳当”?
正文完
 0