共计 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 应用最宽泛、认同度最高的创立自定义类型的办法是什么?其原理和劣势是什么?
- 动静原型模式是如何初始化原型的?其对原型的批改有哪些留神点?
- 寄生构造函数模式的原理是什么?为什么其创立的实例,与其构造函数或构造函数的原型没有关联?
- 稳当构造函数模式的原理是什么?为什么该模式比拟“稳当”?
正文完
发表至: javascript
2021-01-04