Constructor is a function that creates and initializes the newly created object.
构造函数是一个函数,用来创建并初始化新创建的对象。
function A() {
// 更新新创建的对象
this.x = 10;
// 但返回的是不同的对象
return [1, 2, 3];
}
var a = new A();
console.log(a.x, a); undefined, [1, 2, 3]
F = new NativeObject();
F.[[Class]] = "Function"
.... // 其它属性
F.[[Call]] = <reference to function> // function自身
F.[[Construct]] = internalConstructor // 普通的内部构造函数
.... // 其它属性
// F构造函数创建的对象原型
__objectPrototype = {};
__objectPrototype.constructor = F // {DontEnum}
F.prototype = __objectPrototype
// IE浏览器中 - "Object", "object", 其它浏览器 - "Function", "function"
alert(Object.prototype.toString.call(window.alert));
alert(typeof window.alert); // "Object"
function A(x) { // constructor А
this.x = x || 10;
}
// 不传参数的话,括号也可以省略
var a = new A; // or new A();
alert(a.x); // 10
// 显式传入参数x
var b = new A(20);
alert(b.x); // 20
F.[[Construct]](initialParameters):
O = new NativeObject();
// 属性[[Class]]被设置为"Object"
O.[[Class]] = "Object"
// 引用F.prototype的时候获取该对象g
var __objectPrototype = F.prototype;
// 如果__objectPrototype是对象,就:
O.[[Prototype]] = __objectPrototype
// 否则:
O.[[Prototype]] = Object.prototype;
// 这里O.[[Prototype]]是Object对象的原型
// 新创建对象初始化的时候应用了F.[[Call]]
// 将this设置为新创建的对象O
// 参数和F里的initialParameters是一样的
R = F.[[Call]](initialParameters); this === O;
// 这里R是[[Call]]的返回值
// 在JS里看,像这样:
// R = F.apply(O, initialParameters);
// 如果R是对象
return R
// 否则
return O
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10 – 从原型上得到
// 设置.prototype属性为新对象
// 为什么显式声明.constructor属性将在下面说明
A.prototype = {
constructor: A,
y: 100
};
var b = new A();
// 对象"b"有了新属性
alert(b.x); // undefined
alert(b.y); // 100 – 从原型上得到
// 但a对象的原型依然可以得到原来的结果
alert(a.x); // 10 - 从原型上得到
function B() {
this.x = 10;
return new Array();
}
// 如果"B"构造函数没有返回(或返回this)
// 那么this对象就可以使用,但是下面的情况返回的是array
var b = new B();
alert(b.x); // undefined
alert(Object.prototype.toString.call(b)); // [object Array]
function A() {}
var a = new A();
alert(a.constructor); // function A() {}, by delegation
alert(a.constructor === A); // true
function A() {}
A.prototype.x = new Number(10);
var a = new A();
alert(a.constructor.prototype); // [object Object]
alert(a.x); // 10, 通过原型
// 和a.[[Prototype]].x效果一样
alert(a.constructor.prototype.x); // 10
alert(a.constructor.prototype.x === a.x); // true
function A() {}
A.prototype = {
x: 10
};
var a = new A();
alert(a.x); // 10
alert(a.constructor === A); // false!
function A() {}
A.prototype = {
constructor: A,
x: 10
};
var a = new A();
alert(a.x); // 10
alert(a.constructor === A); // true
var foo = {x: 10};
Object.defineProperty(foo, "y", {
value: 20,
enumerable: false // aka {DontEnum} = true
});
console.log(foo.x, foo.y); // 10, 20
for (var k in foo) {
console.log(k); // only "x"
}
var xDesc = Object.getOwnPropertyDescriptor(foo, "x");
var yDesc = Object.getOwnPropertyDescriptor(foo, "y");
console.log(
xDesc.enumerable, // true
yDesc.enumerable // false
);
// 在修改A.prototype原型之前的情况
a.[[Prototype]] ----> Prototype <---- A.prototype
// 修改之后
A.prototype ----> New prototype // 新对象会拥有这个原型
a.[[Prototype]] ----> Prototype // 引导的原来的原型上
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10
A.prototype = {
constructor: A,
x: 20
y: 30
};
// 对象a是通过隐式的[[Prototype]]引用从原油的prototype上获取的值
alert(a.x); // 10
alert(a.y) // undefined
var b = new A();
// 但新对象是从新原型上获取的值
alert(b.x); // 20
alert(b.y) // 30
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10
var __newPrototype = {
constructor: A,
x: 20,
y: 30
};
// 引用到新对象
A.prototype = __newPrototype;
var b = new A();
alert(b.x); // 20
alert(b.y); // 30
// "a"对象使用的依然是旧的原型
alert(a.x); // 10
alert(a.y); // undefined
// 显式修改原型
a.__proto__ = __newPrototype;
// 现在"а"对象引用的是新对象
alert(a.x); // 20
alert(a.y); // 30
var foo = {};
Object.getPrototypeOf(foo) == Object.prototype; // true
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10
// 设置A为null - 显示引用构造函数
A = null;
// 但如果.constructor属性没有改变的话,
// 依然可以通过它创建对象
var b = new a.constructor();
alert(b.x); // 10
// 隐式的引用也删除掉
delete a.constructor.prototype.constructor;
delete b.constructor.prototype.constructor;
// 通过A的构造函数再也不能创建对象了
// 但这2个对象依然有自己的原型
alert(a.x); // 10
alert(b.x); // 10
if (foo instanceof Foo) {
...
}
function A() {}
A.prototype.x = 10;
var a = new A();
alert(a.x); // 10
alert(a instanceof A); // true
// 如果设置原型为null
A.prototype = null;
// ..."a"依然可以通过a.[[Prototype]]访问原型
alert(a.x); // 10
// 不过,instanceof操作符不能再正常使用了
// 因为它是从构造函数的prototype属性来实现的
alert(a instanceof A); // 错误,A.prototype不是对象
function B() {}
var b = new B();
alert(b instanceof B); // true
function C() {}
var __proto = {
constructor: C
};
C.prototype = __proto;
b.__proto__ = __proto;
alert(b instanceof C); // true
alert(b instanceof B); // false
function A(x) {
this.x = x || 100;
}
A.prototype = (function () {
// 初始化上下文
// 使用额外的对象
var _someSharedVar = 500;
function _someHelper() {
alert('internal helper: ' + _someSharedVar);
}
function method1() {
alert('method1: ' + this.x);
}
function method2() {
alert('method2: ' + this.x);
_someHelper();
}
// 原型自身
return {
constructor: A,
method1: method1,
method2: method2
};
})();
var a = new A(10);
var b = new A(20);
a.method1(); // method1: 10
a.method2(); // method2: 10, internal helper: 500
b.method1(); // method1: 20
b.method2(); // method2: 20, internal helper: 500
// 2个对象使用的是原型里相同的方法
alert(a.method1 === b.method1); // true
alert(a.method2 === b.method2); // true
// 写入
foo.bar = 10; // 调用了[[Put]]
console.log(foo.bar); // 10, 调用了[[Get]]
console.log(foo['bar']); // 效果一样
O.[[Get]](P):
// 如果是自己的属性,就返回
if (O.hasOwnProperty(P)) {
return O.P;
}
// 否则,继续分析原型
var __proto = O.[[Prototype]];
// 如果原型是null,返回undefined
// 这是可能的:最顶层Object.prototype.[[Prototype]]是null
if (__proto === null) {
return undefined;
}
// 否则,对原型链递归调用[[Get]],在各层的原型中查找属性
// 直到原型为null
return __proto.[[Get]](P)
if (window.someObject) {
...
}
if ('someObject' in window) {
...
}
O.[[Put]](P, V):
// 如果不能给属性写值,就退出
if (!O.[[CanPut]](P)) {
return;
}
// 如果对象没有自身的属性,就创建它
// 所有的attributes特性都是false
if (!O.hasOwnProperty(P)) {
createNewProperty(O, P, attributes: {
ReadOnly: false,
DontEnum: false,
DontDelete: false,
Internal: false
});
}
// 如果属性存在就设置值,但不改变attributes特性
O.P = V
return;
Object.prototype.x = 100;
var foo = {};
console.log(foo.x); // 100, 继承属性
foo.x = 10; // [[Put]]
console.log(foo.x); // 10, 自身属性
delete foo.x;
console.log(foo.x); // 重新是100,继承属性
// 例如,属性length是只读的,我们来掩盖一下length试试
function SuperString() {
/* nothing */
}
SuperString.prototype = new String("abc");
var foo = new SuperString();
console.log(foo.length); // 3, "abc"的长度
// 尝试掩盖
foo.length = 5;
console.log(foo.length); // 依然是3
var a = {testProperty: 10};
alert(a.testProperty); // 10, 点
alert(a['testProperty']); // 10, 索引
var propertyName = 'Property';
alert(a['test' + propertyName]); // 10, 动态属性通过索引的方式
var a = 10; // 原始值
// 但是可以访问方法(就像对象一样)
alert(a.toString()); // "10"
// 此外,我们可以在a上创建一个心属性
a.test = 100; // 好像是没问题的
// 但,[[Get]]方法没有返回该属性的值,返回的却是undefined
alert(a.test); // undefined
// 执行a.toString()的原理:
1. wrapper = new Number(a);
2. wrapper.toString(); // "10"
3. delete wrapper;
// 执行a.test = 100的原理:
1. wrapper = new Number(a);
2. wrapper.test = 100;
3. delete wrapper;
// 执行a.test的原理:
1. wrapper = new Number(a);
2. wrapper.test; // undefined
alert(1..toString()); // "1"
1.toString(); // 语法错误!
(1).toString(); // OK
1..toString(); // OK
1['toString'](); // OK
function A() {
alert('A.[[Call]] activated');
this.x = 10;
}
A.prototype.y = 20;
var a = new A();
alert([a.x, a.y]); // 10 (自身), 20 (继承)
function B() {}
// 最近的原型链方式就是设置对象的原型为另外一个新对象
B.prototype = new A();
// 修复原型的constructor属性,否则的话是A了
B.prototype.constructor = B;
var b = new B();
alert([b.x, b.y]); // 10, 20, 2个都是继承的
// [[Get]] b.x:
// b.x (no) -->
// b.[[Prototype]].x (yes) - 10
// [[Get]] b.y
// b.y (no) -->
// b.[[Prototype]].y (no) -->
// b.[[Prototype]].[[Prototype]].y (yes) - 20
// where b.[[Prototype]] === B.prototype,
// and b.[[Prototype]].[[Prototype]] === A.prototype
function A(param) {
if (!param) {
throw 'Param required';
}
this.param = param;
}
A.prototype.x = 10;
var a = new A(20);
alert([a.x, a.param]); // 10, 20
function B() {}
B.prototype = new A(); // Error
function A() {
alert('A.[[Call]] activated');
this.x = 10;
}
A.prototype.y = 20;
var a = new A();
alert([a.x, a.y]); // 10 (自身), 20 (集成)
function B() {
// 或者使用A.apply(this, arguments)
B.superproto.constructor.apply(this, arguments);
}
// 继承:通过空的中间构造函数将原型连在一起
var F = function () {};
F.prototype = A.prototype; // 引用
B.prototype = new F();
B.superproto = A.prototype; // 显示引用到另外一个原型上, "sugar"
// 修复原型的constructor属性,否则的就是A了
B.prototype.constructor = B;
var b = new B();
alert([b.x, b.y]); // 10 (自身), 20 (集成)
function inherit(child, parent) {
var F = function () {};
F.prototype = parent.prototype
child.prototype = new F();
child.prototype.constructor = child;
child.superproto = parent.prototype;
return child;
}
function A() {}
A.prototype.x = 10;
function B() {}
inherit(B, A); // 连接原型
var b = new B();
alert(b.x); // 10, 在A.prototype查找到
var inherit = (function(){
function F() {}
return function (child, parent) {
F.prototype = parent.prototype;
child.prototype = new F;
child.prototype.constructor = child;
child.superproto = parent.prototype;
return child;
};
})();
function A() {}
A.prototype.x = 10;
function B() {}
inherit(B, A);
B.prototype.y = 20;
B.prototype.foo = function () {
alert("B#foo");
};
var b = new B();
alert(b.x); // 10, 在A.prototype里查到
function C() {}
inherit(C, B);
// 使用"superproto"语法糖
// 调用父原型的同名方法
C.ptototype.foo = function () {
C.superproto.foo.call(this);
alert("C#foo");
};
var c = new C();
alert([c.x, c.y]); // 10, 20
c.foo(); // B#foo, C#foo
Object.create ||
Object.create = function (parent, properties) {
function F() {}
F.prototype = parent;
var child = new F;
for (var k in properties) {
child[k] = properties[k].value;
}
return child;
}
// 用法
var foo = {x: 10};
var bar = Object.create(foo, {y: {value: 20}});
console.log(bar.x, bar.y); // 10, 20