构造函数其实就是一个使用new操作符调用的函数
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
}
var person = new Person("Nicholas", 29, "Software Engineer");
例子解析:该this对象是在
运行时绑定的
,所以直接调用Person(),this会映射到window对象,例如下面这个测试例子:(没有new将它看成了普通函数)
var person = Person("Nicholas", 29, "Software Engineer");
alert(window.name); //"Nicholas"//
alert(window.age); //29
alert(window.job); //"Software Engineer"
从这个例子可以看到Person实例的三个属性被加到了window上
确认 this 对象是正确类型的实例
。如果不是,那么会创建新的实例并返回
function Person(name, age, job){
if (this instanceof Person){
this.name = name;
this.age = age;
this.job = job;
} else {
return new Person(name, age, job);
}
}
var person1 = Person("Nicholas", 29, "Software Engineer");
alert(window.name); //""
alert(person1.name); //"Nicholas"
var person2 = new Person("Shelby", 34, "Ergonomist");
alert(person2.name); //"Shelby"
if语句
,检查并确保this是person的实例,由此给出限制:要么new一个,要么在现有的person实例环境中调用构造函数
,所以最后结果是调用这个构造函数的时候无论是否使用了new操作符
,都会返回一个pperson的新实例,避免了给全局对象设置属性
构造函数模式
的继承
且不使用原型链,那么这个继承很可能被破坏function Polygon(sides){
if (this instanceof Polygon) {
this.sides = sides;
this.getArea = function(){
return 0;
};
} else {
return new Polygon(sides);
}
}
function Rectangle(width, height){
Polygon.call(this, 2);
this.width = width;
this.height = height;
this.getArea = function(){
return this.width * this.height;
};
}
var rect = new Rectangle(5, 10);
alert(rect.sides); //undefined
Polygon()函数的作用域是安全的
Rectangle 构造函数则不是,因此这个this对象并不是Polygon的实例
,所以会创建并返回一个新的Polygon对象,本来call方法会增长作用域链
,但是此时Rectangle 构造函数中的 this 对象并没有得到增长
,同时 Polygon.call() 返回的值也没有用到,所以 Rectangle 实例中就不会有 sides 属性function Polygon(sides){
if (this instanceof Polygon) {
this.sides = sides;
this.getArea = function(){
return 0;
};
} else {
return new Polygon(sides);
}
}
function Rectangle(width, height){
Polygon.call(this, 2);
this.width = width;
this.height = height;
this.getArea = function(){
return this.width * this.height;
};
}
Rectangle.prototype = new Polygon();
var rect = new Rectangle(5, 10);
alert(rect.sides); //2
var handler = {
message: "Event handled",
handleClick: function(event){
alert(this.message);
}
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick);
var handler = {
message: "Event handled",
handleClick: function(event){
alert(this.message);
}
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", function(event){
handler.handleClick(event);
});
之前在讲闭包的博客中提到过创建多个闭包可能会令代码变得难于理解和调试
function bind(fn, context){
return function(){
return fn.apply(context, arguments);
};
}
一个闭包
,闭包使用 apply()
调用传入的函数
,并给 apply() 传递 context 对象和参数)var handler = {
message: "Event handled",
handleClick: function(event){
alert(this.message);
}
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));
记得这里使用的 arguments 对象是内部函数的,而非 bind() 的
arguments
:是一个对象,是一个长的很像数组的对象,包含函数运行时的实参列表,有个callee属性中装了当前正在运行的函数