key-value
var cat = { name: 'tom', info: this.name + ': 1212', getName: function() { return this.name; } };
注意上例属性info中,使用了this.name,这里的this指向window对象,请尽可能避免在定义对象属性时使用表达式,而将有表达式的内容写入到函数中。javascript
var dog = new Object(); dog.name = 'tim'; dog.getName = function() { return dog.name; }
delete
删除对象的属性和方法delete dog.name;
在window做用域中,不能使用delete删除var, function定义的属性和方法,能够删除没有使用var, function定义的属性和方法java
在实际使用当中,字面量建立对象虽然颇有用,可是它并不能知足咱们的全部需求,咱们但愿可以可以和其余后台语言同样建立一个类,而后声明类的实例就可以屡次使用,而不用每次使用的时候都要从新建立它,因而,便有了工厂模式的出现。jquery
function person(name) { var o = new Object(); o.name = name; o.getName = function() { return this.name; } return o; } var person1 = person('rose'); var person2 = person('jake');
这种模式在函数的内部建立了一个空对象,而后逐一添加属性和方法,最后返回,实现了对象得以复用的目的。可是存在2个很大的问题chrome
console.log(person1 instanceof person); // false
console.log(person1.getName == person2.getName); // false
其实就至关于每次声明对象都被从新建立,只不过写法上简单了一点而已。浏览器
var Person = function(name) { this.name = name; this.getName = function() { return this.name; } } var person1 = new Person('tom'); var person2 = new Person('tim');
使用var或者function声明函数均可以,只是我写例子的时候想到什么就写了什么,这个区别在这里不是重点函数
和工厂模式相比,自定义构造函数没有在函数内部显示的建立和返回对象,而是使用this,固然,看上去简洁了许多,那么它解决了工厂模式的什么问题呢?this
console.log(person1 instanceof Person); // ture console.log(person1.getName == person2.getName); //false
从上面代码能够看出,对象的类别能够判断了,person1就是Person的对象,但是2个同名方法任然不是同一个方法,而是从新建立,其实构造函数内部的实现,能够将上面的代码写成这样来理解spa
var Person = function(name) { var this = {}; this.name = name; this.getName = function() { return this.name; } return this; }
看上去和工厂模式就有点像,只是this的声明和返回都是隐式的。下一步,咱们将要介绍关键先生,原型
prototype
原型并无那么神秘,由于在javascript中,它无处不在。为了了解原型,咱们能够在chrome浏览器的console中,随意建立一个函数指针
function a(){}
而后继续输入
a.prototype
获得的结果以下
a { constructor: function a(), _proto_: Object }
没错,获得的这个a,就是关键先生原型
了。每个函数都有一个prototype
属性,他就像一个指针同样指向它的原型,而每个原型,都有一个constructor
属性,指向他的构造函数。
那么原型在建立对象中有什么用呢?
一个例子,千锤百炼,以下
function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; } var person1 = new Person('rose'); var person2 = new Person('Jake');
在这里,咱们将属性写在了构造函数里,将使人头疼的方法写在原型里,看看上面的问题获得解决没有
console.log(person1 instanceof Person); // true console.log(person1.getName === person2.getName); // true
OK,问题完美解决。
固然也能够将属性写入原型中,可是若是那样的话,属性就会如同方法同样被公用了,所以通常来讲,属性会写入构造函数之中,方法写入原型之中。固然,这视状况而定。
若是你想进一步了解原型,能够看下图。
当咱们使用new Person
时便会建立一个实例,好比这里的person1与person2,这里的实例中,会有一个_proto_
属性指向原型。
当咱们使用实例person1
调用方法person.getName()
时,咱们首先找的,是看看构造函数里面有没有这个方法,若是构造函数中存在,就直接调用构造函数的方法,若是构造函数不存在,才回去查找原型中是否存在该方法
function Cat(name) { this.name = name; this.age = 12; this.getName = function() { return 'constructor'; } } Cat.prototype.name = 'proto name'; Cat.prototype.getName = function() { return this.name; } var tim = new Cat('Tim'); console.log(tim.name); // tim console.log(tim.getName()); // constructor
能够看到上例中,当原型和构造函数中拥有一样的方法和属性的时候,构造函数中的被执行。
因而,这里便会有一个十分重要的概念须要理解,那就是this的指向问题。
在整个建立对象的过程中,this到底指向谁?
function Person(name) { this.name = name; // this.getName = function() { // return 'constructor'; // } } Person.prototype.getName = function() { return this.name; } Person.prototype.showName = function() { return this.getName(); } var rose = new Person('rose'); console.log(rose.showName()); //rose
其实在new
执行时,构造函数中的this与原型中的this都被强行指向了new
建立的实例对象。
若是须要写在原型上的方法不少的话,还能够这样来写,让写法看上去更加简洁
Person.prototype = { constructor: Person, getName: function(){}, showName: function(){}, ... }
constructor:Person
这一句必不可少,由于{}
也是一个对象,当使用Person.prototype = {}
时,至关于从新定义了prototype的指向,所以手动修正{}
的constructor
属性,让他成为Person的原型。
其实经过上面方式,使用构造函数声明实例的专属变量和方法,使用原型声明公用的实例和方法,已是建立对象的完美解决方案了。但是惟一的不足在于,每次建立实例都要使用new来声明。这样未免太过麻烦,若是jquery对象也这样建立,那么你就会看到一段代码中有无数个new,但是jQuery仅仅只是使用了$('xxxx')便完成了实例的建立,这是如何作到的呢?
仍是按照惯例,先贴代码。
(function(window, undefined) { var Person = function(name) { return new Person.fn.init(name); } Person.prototype = Person.fn = { constructor: Person, init: function(name) { this.name = name; return this; }, getName: function() { return this.name; } } Person.fn.init.prototype = Person.fn; window.Person = window.$ = Person; })(window); console.log($('tom').getName());
一步一步来分析
(function(){ ... })()
传入window参数,是为了让jquery对象在外window中能够被访问,所以有以下一句代码
window.Person = window.$ = Person;
这样咱们就能够直接使用$
来调用Person构造函数
init
方法。其中的复杂关系,咱们借助下图来分析了解,表达能力实在有限,也不知道如何才能表达的更加简洁易懂。当外部调用$().getName()
时,函数内部的执行顺序以下
new Person.fn.init() // 而init的原型,经过下面一句指向了Person的原型 Person.fn.init.prototype = Person.fn; // 因而就能够调用原型中的getName方法了