在常见的编程语言中如果你需要一个对象,那么可以通过类来创建,但是Javascript它并没有类这个概念,javascript创建对象是通过克隆另外一个对象而来的,既然如此那么它肯定有一个基类,这个基类就是Object.prototype,这是一个顶级根对象,其他所有对象都是通过克隆它而来的,比如你通过new Object()实际上就是克隆了Object.prototype。通过克隆我们可以得到一个一模一样的对象,但是这个prototype原型只有函数才有,因此我们得先创建一个函数,如下:
function Fn(){
this.name = 'JS';
}
Fn.prototype.sayHello = function(){
alert(this.name);
};var js = new Fn();
console.log(js);
这里我们用到了new ,实际上new干了两件事一个是把Fn里面的this指向了js另外一件事就是js的__proto__指向了Fn.prototype,__proto__属于隐藏的属性,但是谷歌浏览器和火狐浏览器控制台已经公开了。__proto__的作用就是,当你这个对象没有某些方法或者属性的时候,这个对象就会通过__proto__上面找,__proto__又指向了那个构造函数的prototype,因此它又跑去prototype上面找对应的属性或方法。
下面我们手动模拟一下new的实现
function createObj(fn){
var obj = new Object();
fn.call(obj); //通过call让fn里面的this指向obj
obj.__proto__ = fn.prototype; //指向fn.prototype 继承方法和属性
return obj;
}
console.log(createObj(Fn));
new的内部实现可能要比这复杂,但大致是这样的一个过程。
ES5提供了一种新的克隆对象方法它叫Object.create(对象);
var obj = {a:1,b:2};
var cloneObj = Object.create(obj);
console.log(cloneObj);
如果你通过谷歌浏览器你可以看到这样一个画面。
Object {}
__proto__: Object
a: 1
b: 2
__proto__: Object
也就是说这个Object.create这个方法实际上就是将cloneObj的__proto__指向了obj。Ok我们也来实现一个。
var obj = {a:1,b:2};
function createObj(obj){
function Fn(){
}
Fn.prototype = obj;
return new Fn();
}
console.log(createObj(obj));
有可能你会奇怪,正如我之前郁闷一件事,就是为什么不直接return返回这个obj不就好了吗。
var obj = {a:1,b:2};function createObj(obj){
return obj;
}
console.log(createObj(obj));
虽然你看上去没啥区别,但其实不是这样,实际上通过prototype并不是去真正的创建一个对象,而是继承,这很重要,如果你按照上面的那种错误做法是真的去创建了另一个对象了,这样的话内存中又多出来一个对象,而往往我们没有必要这样做,只是希望如果本身这个对象没有的话,我在去继承你那个对象,这样不岂妙哉。
通过Object.create来创建对象多少和new Object()还是有区别的,首先Object.create支持传递一个null,如果传的是null的话,它创建的真的是一个彻彻底底的空对象,它的__proto__不指向任何东西,因此它不继承任何的属性和方法,而new Object()创建的它的__proto__指向Object.prototype,简单来说Object.create(null)没有原型,即一个空对象,而new Object()有原型对象。