以前有篇博客曾提到过一点js的面向对象编程:js面向对象编程.javascript
这里就结合js高程详细剖析一下javascript的面向对象编程.html
前序:vue
1⃣️Object.defineProperty()java
var obj = { _name:'jack' }; Object.defineProperty(obj,'name',{ configurable:false,//表示可否经过delete删除属性从而从新定义属性,默认值true value:'orange',//属性的数据值,默认值undefined writable:false,//表示可否修改属性的值,默认值为true enumerable:false,//是否可枚举,可否经过for-in循环返回属性,默认值为true get:function(){//getter return this._name; }, set:function(newval){//setter this._name = newval; } })
vue2.x版本的双向数据绑定就是基于该API和订阅/发布模式实现的;编程
若是同时定义多个属性,可经过以下API:函数
Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } }
} });
2⃣️读取属性的特性Object.getOwnPropertyDescriptor() this
var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); alert(descriptor.value); //2004 alert(descriptor.configurable); //false
正文:spa
3⃣️建立对象prototype
3.1 工厂模式code
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o;
} var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor");
工厂模式建立了n个互不关联的对象,可是却没有解决对象识别的问题(即怎样知道一个对象的类型) .
3.2 构造函数模式
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
由于函数也是一个对象,因此能够经过该方式建立一个Person对象;
按照惯例,构造函数始终都应该以一个 大写字母开头,而非构造函数则应该以一个小写字母开头 ;
要建立 Person 的新实例,必须使用 new 操做符。以这种方式调用构造函数实际上会经历如下 4 个步骤:
(1) 建立一个新对象;
(2) 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true
alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true
构造函数模式虽然好用,但也并不是没有缺点。使用构造函数的主要问题,就是每一个方法都要在每一个实例上从新建立一遍,不能共享。虽然咱们能够将该方法写到全局做用域,而后在构造函数内部调用,可是这种作法显然耦合度太高.
3.3 原型模式
能够顺便参照以前的博客:js继承的实现.
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
能够看到,原型属性上的属性值和属性方法是被全部实例共享的.
3.3.1实例属性和原型属性
person1.name = "Greg"; alert(person1.name); //"Greg"——来自实例 alert(person2.name); //"Nicholas"——来自原型
delete person1.name; alert(person1.name); //"Nicholas"——来自原型
咱们看到访问实例属性的时候,优先级是实例属性-->原型属性,删除属性的时候优先级也是如此;
实例上有该属性,就直接拿实例的该属性,没有的话就去原型上找.
3.3.2 hasOwnProperty() 判断属性是否是来自于实例
var person1 = new Person(); var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false person1.name = "Greg"; alert(person1.name); //"Greg"——来自实例 alert(person1.hasOwnProperty("name")); //true
实例的原型属性不可枚举:
var keys = Object.keys(Person.prototype); alert(keys); //"name,age,job,sayName"
var p1 = new Person(); p1.name = "Rob"; p1.age = 31; var p1keys = Object.keys(p1); alert(p1keys); //"name,age"