渐进增强过程:
-> 刚学习js的时候,一般都是用如下的方式来写代码:
var decimalDigits = 2,tax = 5;
function add(x, y){ return x + y;}
function subtract(x, y){return x - y;}
-> 学习了原型后,我们可以使用如下方式来美化代码:
var Calculator = function(decimalDigits, tax){
this.decimalDigits = decimalDigits;
this.tax = tax;
}
然后,通过Calculator对象的prototype属性赋值对象字面量来设定Calculator对象的原型。
Calculator.prototype = {
add: function(x, y){return x + y;},
subtract: function(x, y){return x - y;}
}
这样,就可以new Calculator对象后,调用add等方法了。
-> 第二种方式,在赋值原型prototype的时候使用function立即执行的表达式来赋值,即如下格式:
Calculator.prototype = function(){}();
它的好处就是封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果,修改代码如下:
Calculator.prototype = fucntion(){
var add = function(x, y){
return x + y;
},
subtract = function(x, y){
return x - y;
}
return {
add: add,
subtract: subtract
}
}();
->再来一点,分步声明:
上述使用原型的时候,有一个限制就是一次性设置了原型对象,我们再来说一下如何分开来设置原型的每个属性。
var BaseCalculator = function(){
//为每一个实例都声明一个小数位数
this.decimalDigits = 2;
}
//使用原型给BaseCalculator扩展2个对象方法
BaseCalculator.prototype.add = function(x, y){
return x + y;
}
BaseCalculator.prototype.subtract = function(x, y){
return x - y ;
}
var Calcalculator = function(){
//为每个实例都声明一个税收数字
this.tax = 5;
}
Calculator.prototype = new BaseCalculator();
至此,Calculator的原型是指向到 BaseCalculator的一个实例上的,目的是让Calculator集成它add(x,y)和subtract(x,y)这2个function,还是有一点是:由于它的原型是BaseCalculator的一个实例,所以不管你创建多少个Calculator对象实例,他们的原型指向的都是同一个实例。
var calc = new Calculator();
calc.add(1,1);
calc.decimalDigits;
如果我们不想让Calculator访问BaseCalculator的构造函数里声明的属性值:
var Calculator = function(){
this.tax = 5;
}
Calculator.prototype = BaseCalculator.prototype;
通过将BaseCalculator的原型赋值给Calculator的原型,这样你在Calculator的实例上 就访问不到那个decimalDigits值了。
-> 重写原型
在使用第三方JS类库的时候,往往有时候他们定义的原型方法不能满足我们的需求,但是又离不开这个类库,所以这时候我们就需要重写他们 的原型中的一个或者多个属性或function,我们可以通过继续声明的同样的add代码形式来达到覆盖重写前面add的功能,代码如下:
//覆盖前面的Calculator的add function
Calculator.prototype.add = function(x, y){
return x + y + this.tax;
}
需要注意一点:那就是重写的代码需要放在最后,这样才能覆盖前面的代码。
-> hasOwnProperty函数
hasOwnProperty是Object.prototype的一个方法,它能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty是JavaScript中唯一一个处理属性但是不查找原型链的函数。
但是有个恶心的地方时:JS不会保护hasOwnProperty被非法占用,因此如果一个对象碰巧存在这个属性,就需要使用外部的hasOwnProperty函数来获取正确的结果。
var foo = {
hasOwnProperty: function(){
return false;
},
bar: ‘Here be dragons‘
};
foo.hasOwnProperty(‘bar‘);//总是返回false
//使用{}对象的hasOwnProperty并将其上下为设置为foo
{}.hasOwnProperty.call(foo,‘bar‘);//true
当检查对象上某个属性是否存在时,hasOwnProperty是唯一可用的方法。同时在使用for in loop遍历对象时,推荐总是使用hasOwnProperty方法,这将会避免原型对象扩展带来的干扰。
Object.prototype.bar = 1;
var foo = {moo:2}
for(var i in foo){
console.log(i);//输出两个属性:bar和moo
}
我们没办法改变for in语句的行为,所以想过滤结果只能使用hasOwnProperty方法,代码如下:
for(var i in foo){
foo.hasOwnProperty(i) && console.log(i);
}