JavaScript原型

来源:互联网 发布:淘宝二手车交易 编辑:程序博客网 时间:2024/05/20 03:47

一、对象的创建:new
function foo( a ) {
  this.a = a;
}
var  bar = new foo( 2 );
console.log( bar.a ); // 2
  • 创建(或者构建一个)新的对象。
  • 新对象会被执行[[原型]]链接
  • 新对象绑定到函数调用的this。
  • 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
关于new:
new会劫持所有普通函数并用构造对象的形式来调用它。其实foo仅仅是一个普通的函数,只是使用new来调用它时,他就会像构造一个对象并赋值给bar,这看起来像new的一个副作用(无论如何都会构造一个对象)。这个调用是构造函数调用,但是函数foo本身并不是一个构造函数。
换句话说,在JavaScript中对于“构造函数”最准确的解释是,所有带new的函数调用。
函数并不是构造函数,但是当且仅当使用new时,函数会变成“构造函数调用”。
二、原型链:[[Prototype]]
myObject.foo = "bar";
  • 如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属性值。
  • 如果foo 不是直接存在于myObject 中,[[Prototype]]链就会被遍历,类似 [[Get]] 操作。如果属性名 foo 既出现在 myObject 中也出现在 myObject[[Prototype]] 链上层,那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObject.foo 总是会选择原型链中最底层的 foo 属性。
  • 如果原型链上找不到 foofoo就会被直接添加到 myObject 上。([[PropsType]]链最终都会指向内置的Object.prototype)
每个函数function都有一个prototype,即原型。
每个对象都有一个__proto__,可成为隐式原型。
每个对象都有一个__proto__属性,指向创建该对象的函数的prototype。
 
三、构造函数
1、每个对象都有一个__proto__属性,指向创建该对象的函数的prototype:
function foo() {
  // ...
}
 
var a = new Foo();
Foo.prototype.myName = function a() {};
var b = new Foo();
Object.getPrototypeOf(a) === Foo.prototype; // true
Console.log(Foo.prototype);
Console.log( a. myName) // function a() {}
Console.log( b. myName) // function a() {}
创建a后的第一步就是给a一个内部的[[prototype]]链接,关联到Foo.prototype指向的那个对象上。这里关联的意思是a.constructor指向Foo.prototype的引用,不是复制。
2、.constructor
由于a.constructor === Foo意味着a确实有个指向Foo的.constructor属性,但是事实并非如此。
实际情况是.constructor引用被委托给了Foo.prototype,而Foo.prototype.constructor默认指向Foo。
即a._proto_指向Foo.prototype,而Foo.prototype含有Foo.prototype.constructor属性指向Foo。
Foo.prototype的constructor属性只是Foo函数在声明时的默认。
 
四、Object.create
function Foo(name) {
  this.name = name;
}
 
Foo.prototype.myName = function() {
  return this.name;
}
 
function Bar(name, label) {
  Foo.call(this, name);
  this.label = label;
}
 
Bar.prototype = Object.create(Foo.prototype);
 
Bar.prototype.myLabel = function() {
  return this.label;
}
 
var a = new Bar('a''object a');
 
console.log('a.myName', a.myName()); // a
console.log('a.myLabel', a.myLabel()); // object a
console.log(Foo.prototype.constructor === Bar.prototype.constructor); // true
console.log(Foo.prototype === Bar.prototype); // false
 
这段代码的核心部分就是语句Bar.prototype = Object.create(Foo.prototype);调用Object.create(...)会凭空创建一个“”对象并把新对象关联到新对象内部的[[Prototype]]关联到你指定的对象。
    if (!Object.create) {
      Object.create = function(o) {
        function Foo() {}
        Foo.prototype = o;
        return new foo();
      };
    }
这个新对象是Foo.prototype的新实例console.log(Foo.prototype === Bar.prototype); // false
但是新对象的constructor属性与Foo.prototype.constructor属性都指向Foo函数。
Object.create的polyfill
Object.create(…)是在ES5中新增的函数,所以在ES5之前的环境中要使用polyfill。
 
 
五、隐式原型
绝大多数浏览器支持一种非标准的方法来访问对象内部[[prototype]]属性:
           Const a = new Foo();
           a.__proto__ ==== Object.getPrototypeoOf(a) === Foo.prototype; // true
访问a.__proto__时,实际上是调用了a.__proto__()(调用getter函数)。虽然getter函数存在于Object.prototype对象中,但是他的this指向对象a,所以和Object.getPrototypeoOf(a)结果相同。
 
原创粉丝点击