Showing posts with label Constructor. Show all posts
Showing posts with label Constructor. Show all posts

Sunday, June 20, 2010

relationship of constructor and prototype in javascript


var animal = function(status) {
this.status = status;
this.breathes = "yes";
this.action = function() {
console.log('flying...')
};
},
human = function() {
this.name = 'human';
},
cat = function() {
this.type = 'cat';
};

// javascript支持原型继承,这种方式比类继承更强大,类继承中一个对象可以继承结构和行为,而原型继承可以继承结构和行为之外,并可以继承一个对象的状态
// new一个animal的实例对象作为cat.prototype的原型,这个animal实例对象就成为cat的实例对象原型链上的一员
// __proto__这个魔法属性在这些浏览器不能工作: ie 6/7/8, safari < 5, opera < 10.50
//当在cat的某个实例上检索一个属性时,如果在其本身中没有找到,则会延着原型链向上检索,如下例子中的c.__proto__即为一个animal对象
//如果检索c.breathes,如果在c对象本身没有找到此属性,则会检索t.__proto__.breathes、t.__proto__.__proto__.breathes等原型链上的对象,直到找到为止,没找到返回undefined
cat.prototype = new animal("live");
//cat继承的原型对象是具有特定状态的animal对象
var c = new cat();
console.log(cat.prototype);
console.log(cat.prototype.constructor.tostring());
console.log(c.constructor.tostring());
console.log("cat breathes:" + c.breathes);
console.log("c.__proto__:", c.__proto__);
//ie不支持此属性
//你可以利用object.__proto__这个魔法属性修改当前对象的原型,下面将一只猫猫化为人形
var d = new cat();
d.__proto__ = new human();
console.log("d.__proto__:", d.__proto__);
//从上面结果可以看到cat的实例c.constructor不是指向cat这个构造函数,而是animal构造函数
//需要修改对象的constructor为其构造函数本身
//当一个函数对象被创建时,function构造器产生的函数对象会运行类似这样的一些代码:this.prototype = {constructor: this},参考javascript: the good parts 5.1节说明
//新函数对象被赋予一个prototype属性,其值是包含一个constuctor属性,并且其属性值为此新函数对象本身
//但是通过原型方式继承时,会给prototype重新赋予一个新对象,此prototype对象中的constructor是指向其自身的构造函数,而不是新函数的,所以需要重置其fn.prototype.constructor = this
//参考javascript权威指南第五版example 9-3. subclassing a javascript class
cat.prototype.constructor = cat;
console.log(cat.prototype.constructor.tostring());
console.log(c.constructor.tostring());
console.log(c.__proto__);
var tostring = object.prototype.tostring;
language = function() {
this.type = "programming";
return {
"locale": "en",
"class-free": function() {
return false
},
"tostring": function() {
return tostring.apply(this, arguments)
}
// 如果tostring方法被重写成非function对象,则后面console中无法输出对象j
}
},
javascript = function() {
this.value = "javascript";
this["class-free"] = function() {
return true
};
};
language.prototype = {
a: 1,
b: 2
};
javascript.prototype = new language();
var j = new javascript();
console.log(j);
console.log(j.__proto__);
//locale: en,此处因为language构造函数返回不是this,而是另一个object直接量,而object直接的构造方法为object(),因此language的原型被丢失了
console.log(language.prototype);
console.log(javascript.prototype);
console.log(j.constructor.tostring());
//function object() { [native code] }


构造函数与其返回值


构造函数会返回一个对象,如果没有直接return语句,构造函数会自动返回当前对象:"return this;",也可以返回一个对象直接量,而不返回this,这样会中断正常的原型链。

prototype.js中class对象定义是封装在一个匿名函数里的,从而使得其内部变量和方法与外界隔离,其中有二句代码为:

function subclass() {};
subclass.prototype = parent.prototype;

因为parent的构造可能返回语句不是返回this对象,而是返回了一个其他的对象,如{tostring:true},如果不用subclass.prototype=parent.prototype这样写,可能这样会丢失原型链上的方法和属性,通过subclass这个空构造将parent.prototype引用到自身的prototype上,从而保持住部分原型链。
这其实也已经不是原型继承了,因为它不是通过new parent()来获取原型对象,丢失了new parent所得对象中的属性和方法。
prototype中的class其实放弃了原型对象,只是简单的继承了parent.prototype对象,已经失去原型继承可以继承对象状态的功能,这样操作其实是很好的模似了类继承方式。

var class = (function() {
function subclass() {};
function create() {
var parent = null,
properties = $a(arguments);
if (object.isfunction(properties[0])) parent = properties.shift();

function klass() {
this.initialize.apply(this, arguments);
}

object.extend(klass, class.methods);
klass.superclass = parent;
klass.subclasses = [];

if (parent) {
// 因为parent的构造可能返回对象直接量,而不是返回this,如{tostring:true}
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
parent.subclasses.push(klass);
}

for (var i = 0; i < properties.length; i++) klass.addmethods(properties[i]);
if (!klass.prototype.initialize) klass.prototype.initialize = prototype.emptyfunction;
klass.prototype.constructor = klass;
return klass;
}
function addmethods(source) {
var ancestor = this.superclass && this.superclass.prototype;
var properties = object.keys(source);
if (!object.keys({
tostring: true
}).length) {
if (source.tostring != object.prototype.tostring) properties.push("tostring");
if (source.valueof != object.prototype.valueof) properties.push("valueof");
}
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i],
value = source[property];
if (ancestor && object.isfunction(value) && value.argumentnames().first() == "$super") {
var method = value;
value = (function(m) {
return function() {
return ancestor[m].apply(this, arguments);
};
})(property).wrap(method);
value.valueof = method.valueof.bind(method);
value.tostring = method.tostring.bind(method);
}
this.prototype[property] = value;
}
return this;
}
return {
create: create,
methods: {
addmethods: addmethods
}
};
})();

Friday, November 28, 2008

construnctor of javascript

Object
the superclass of all JavaScript objects
Constructor
new Object( );
This constructor creates an empty object to which you can add arbitrary properties.

Properties
All JavaScript objects, how ever they are created, have the following properties.
constructor

var f = function(){}
var g = function(){}
var f1 = new f();
var f2 = new f();
var g1 = new g();
console.log(f.constructor); // Function()
console.log(g.constructor); // Function()
console.log(f.constructor == g.constructor); // true
console.log(f1.constructor); // function() [f]
console.log(g1.constructor); // function() [g]
console.log(f1.constructor == g1.constructor); // false
console.log(f1.constructor == f2.constructor); // true
console.log(f1.constructor === f2.constructor); // true

Wednesday, August 13, 2008

Tweak your Object constructor [javascript tips]

注意代码中的变量名和function名的关系,书写一定要分清楚各个变量的词法作用域:
第一种情况,虽然名字相同,但词法作用域不同,不相关系。

function Tweak() { // 这里的Tweak是window的一个全局方法
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}

var t = Tweak(1,2);
console.log(t.args); // [1, 2] // [object Arguments]

第二种是变量名覆写了方法名
// 如果javascript代码如下
var Tweak = Tweak(1, 2); // javascript中的function会先被解析器解析,这里Tweak(1, 2)已经在调用下面的Tweak方法,但此方法调用完成后马上被变量Tweak覆写
function Tweak() {
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}
// Tweak(1, 2); // 这句代码已经执行错误,因为Tweak已经是一个对象,而不是方法了。

第三种是方法名覆写了变量名
// 如果javascript代码如下
var Tweak = {};
Tweak = function () { // Tweak 变量被重新赋为一个function对象
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}
Tweak(1, 2); // 这句代码可以执行

Monday, January 07, 2008

NOTE CLASS OR MODULE? [R4R page 175]

When you see a construct like :
ActionController::Routing::Route
you can’t tell from that construct what’s a class and what’s a module. If there’s a call to new, you can be pretty sure the last element in the chain is a class, but otherwise the last element could be any constant—class, module, or other—and the elements on the left could be either classes or modules. In many cases, the fact that you can’t tell classes from modules in this kind of context doesn’t matter; what matters is the nesting or chaining of names in a way that makes sense. That’s just as well, because
you can’t tell what’s what without looking at the source code or the documentation. This is a consequence of the fact that classes are modules—the class Class is a subclass of the class Module—and in many respects (with the most notable exception being the fact that classes can be instantiated), their behavior is similar.

Monday, October 15, 2007

Function() constructor of JavaScript

There are a few points that are important to understand about the Function() constructor:

The Function() constructor allows JavaScript code to be dynamically created and compiled at runtime. It is like the global eval() function (see Part III) in this way.

The Function() constructor parses the function body and creates a new function object each time it is called. If the call to the constructor appears within a loop or within a frequently called function, this process can be inefficient. By contrast, a function literal or nested function that appears within a loop or function is not recompiled each time it is encountered. Nor is a different function object created each time a function literal is encountered. (Although, as noted earlier, a new closure may be required to capture differences in the lexical scope in which the function is defined.)

A last, very important point about the Function() constructor is that the functions it creates do not use lexical scoping; instead, they are always compiled as if they were top-level functions, as the following code demonstrates:


var y = "global";
function constructFunction() {
var y = "local";
return new Function("return y"); // Does not capture the local scope!
}

// This line displays "global" because the function returned by the
// Function() constructor does not use the local scope. Had a function
// literal been used instead, this line would have displayed "local".
alert(constructFunction()()); // Displays "global"

Thursday, July 12, 2007

Prototype of Javascript


<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

function Google (name) {
// constructor body...
var url = 'http://www.google.com';
this.url = url;
this.name = name;
}

Google.prototype.desc = "this is google.";
Google.prototype.title = "GOOGLE";
Google.prototype.toString = function () {
return "Object [Google].";
}

var g = new Google('yu');
doc('g=' + g);
g.test = 'test';
doc("g.test=" + g.test);
doc("g['test']=" + g['test']);
doc("g.url=" + g.url);

g = null;

function ExtGoogle (argument) {
this.ext = argument;
}

ExtGoogle.prototype = new Google('yu'); // before toString and ajax function.
ExtGoogle.prototype.toString = function () { return "Object [ExtGoogle]."};
ExtGoogle.prototype.ajax = function (url) {return 'Ajax function.'}

doc('');
var e = new ExtGoogle('yu');
doc(e.ajax('Google'));
doc(e);
doc("e['ext']=" + e['ext']);
doc(e.url);
doc(e.title);

e = null;
</script>