JavaScript基础学习-原型
从对象说起
JavaScript是面向对象的语言,而JavaScript的实现方式和常见的(比如Java)不一样,JavaScript不通过类来抽象对象,直接创建创建对象,JavaScritpt中只有对象。
[[Prototype]]
几乎所有对象在创建的时 对象的[[Prototype]]都会被赋予一个非空的值
这个值可以通过a.__proto__获取,也可以通过Object.getPrototypeOf(a)来获取
var a = {}
对象的[[Prototype]]最终会指向Objects.prototype
原型的作用
JavaScript面向对象的方式不是通过类的复制(像Java一样),而是通过对象的关联,对象的关联就是通过原型
我们创建一个对象b并把它关联到对象a,发现b的原型指向a。
当我们访问b.a时,虽然b中不存在a,会通过原型一直向上查找(直到找到Object),在a的原型中找到a。
var a = { a: 2 },
b = Object.create(a);
console.log(b);
console.log(b.a); // 2
console.log(Object.getPrototypeOf(b) === a); // true
对象b
关于函数
- 函数也是对象也会有原型,函数还有一个prototype属性,当我们使用new 来调用这个函数时,生成的对象[[Prototype]]会关联函数的prototype
- JavaScript中并不存在构造函数,只有当使用new 调用函数时,函数调用会变成 构造函数调用。
- 通常我们会把通过new 调用的函数的函数名首字母大写,然而对于JavaScript引擎来说首字母大写没有任何意义。
当我们使用new 调用一个函数时,发生了下面的过程
- 创建一个新对象
- 这个对象会被执行[[Prototype]]连接
- 这个新对象会绑定到函数调用的this
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象(this)
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
var a = new Foo('a');
console.log(a);
console.log(a.myName()); // a
console.log(a.constructor === Foo); // true
console.log(Foo.constructor === Function);
console.log(Foo.prototype.constructor === Foo); // true
对象a
a有一个自身的name属性,a的原型有一个来自Foo的myName()函数,和构造器constructor,a的constructor指向Foo,Foo.prototype.constructor也默认指向Foo。
a的 .constructor属性指向Foo,并不能说明a是由Foo“构造的”,它们之间只是委托关系
Foo.prototype的.constructor属性只是Foo函数在声明时的默认属性,可以修改
当修改了Foo.prototype后,a.constructor在“{}”中没有发现constructor属性,继续向原型链上层查找,找到Object,所以a.constructor===Object
function Foo() {}
Foo.prototype = {};
var a = new Foo();
console.log(a.constructor === Foo); // false
console.log(a.constructor === Object); // true
继承
- Bar.prototype = Object.create(Fun.prototype)。通过Object.create()的方式创建Bar.prototype 会创建一个新的对象并把新对象内部的[[prototype]]关联到Foo.prototype。这样做会使Bar.prototype.constructor属性丢失
- 当使用Bar.prototype = Fun.prototype时 ,会使Bar.prototype和Fun.prototype共同引用同一个对象,当对Bar.prototype赋值时,同时也会使Fun.prototype变化,失去继承的意义。
- ES6提供了更好的方法 Object.setPrototypeOf(Bar.prototype,Fun.prototype)
function Fun(name) {
this.name = name;
}
Fun.prototype.myName = function() {
return this.name;
};
function Bar(name, lable) {
Fun.call(this, name);
this.lable = lable;
}
// Bar.prototype = Fun.prototype;
// Bar.prototype = new Fun();
Bar.prototype = Object.create(Fun.prototype);
// Object.setPrototypeOf(Bar.prototype, Fun.prototype);
Bar.prototype.myName = function() {
return this.name + 'jsong';
};
var a = new Bar('jsong');
console.log(a.myName()); // jsongjsong
var b = new Fun('js');
console.log(b.myName()); // js