说明:前端
此摘要笔记系列是我最近看《JavaScript高级程序设计(第3版)》随手所记。
里面分条列举了一些我认为重要的、须要记下的、对我有帮助的点,是按照我看的顺序来的。
摘要笔记自己没有系统性,没有全面性可言,写在这里供有必定基础的前端开发者参考交流。
里面的知识点、例子大部分来源于本书,或者延伸出来的,都通过个人测试是对的,可是没办法保证100%正确,若是有人看到错误的地方,但愿指出来,谢谢。函数
用这种方法若是不设置原型的 constructor 属性,则原型的 constructor 属性跟普通对象同样,指向 Object,
如:测试
var Person = function () {} Person.prototype = { name: 'abc', sayHello: function () { console.log('hello') } } Person.prototype.constructor === Person // false Person.prototype.constructor === Object // true var ming = new Person() ming.constructor === Person // false ming.constructor === Object // true ming.__proto__ === Person.prototype // true ming instanceof Person // true
以后的表现跟在原生的原型对象上添加属性同样,
如:this
var Person = function () {} Person.prototype = { constructor: Person, name: 'abc', sayHello: function () { console.log('hello') } } Person.prototype.constructor === Person // true var ming = new Person() ming.constructor === Person // true ming.__proto__ === Person.prototype // true ming instanceof Person // true
可是,重设 constructor 属性会致使它的 [[Enumerable]] 特性被设置成 true,变成可枚举的。
这个问题能够用 Object.defineProperty() 来改正。
如:prototype
var Person = function () {} Person.prototype = { name: 'abc', sayHello: function () { console.log('hello') } } Object.defineProperty(Person.prototype, 'constructor', { enumerable: false, value: Person })
若是不重设构造函数的 prototype 原型对象,那么,咱们对原型对象的任何修改都可以反映到实例上,即便先建立实例后修改原型。设计
若是重设构造函数的 prototype 原型对象,那么,会切断新的原型对象和任何以前已经存在的构造函数实例之间的联系,它们引用的仍然是最初的原型。code
建立自定义类型的最经常使用方式,就是组合使用构造函数模式和原型模式。构造函数用于定义实例属性,原型模式用于定义方法和共享的属性。对象
好处:每一个实例都会有本身的实例属性的副本,同时又共享着对方法的引用,最大限度的节省了内存。
还支持向构造函数传递参数。
如:继承
function Person (name, age) { this.name = name this.age = age this.friends = ['Ming', 'Li'] } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name) } } var zhang = new Person('zhang', 12) var yang = new Person('yang', 15) zhang.friends.push('wang') console.log(zhang.friends) // ['Ming', 'Li', 'wang'] console.log(yang.friends) // ['Ming', 'Li'] zhang.sayName === yang.sayName // true
如:ip
function Person (name, age) { this.name = name this.age = age if (typeof this.sayName !== 'function') { Person.prototype.sayName = function () { console.log(this.name) } } } // 注意在用这种模式时,不能使用对象字面量重写原型。
这种模式的基本思想就是建立一个函数,该函数的做用仅仅是封装建立对象的代码,而后再返回新建立的对象。但从表面看,这个函数很像构造函数。
如:
function Person (name, age) { var person = { name: name, age: age, sayName: function () { console.log(this.name) } } return person } var ming = new Person('ming', 12) ming.sayName() // 'ming' ming instanceof Person // false ming instanceof Object // true ming.__proto__ === Object.prototype // true ming.constructor === Object // true
注意:这个模式除了使用new操做符并把包装的函数叫作构造函数外,跟工厂模式是一摸同样的。
说明:返回的对象与构造函数或者与构造函数的原型属性没有关系。
(由于不使用new操做符,因此函数名称就不首字母大写了)
稳妥构造函数模式与寄生构造函数相似,但有两点不一样:一是新建立的实例方法不引用this;二是不使用new操做符调用构造函数。
如:
function person (name, age) { var o = {} o.sayName = function () { console.log(name) } return o; } var ming = person('ming', 12) ming.sayName() // 'ming' ming instanceof person // false ming instanceof Object // true
注意:在这里除了调用 sayName 方法,没有其它办法访问 name 的值
说明:同寄生构造函数模式,返回的对象与构造函数或者与构造函数的原型属性没有关系。
关于对象原型部分结束。下一篇是继承相关的内容