this
this表示当前对象如果在全局作用范围内使用this则指代当前页面对象window 如果在函数中使用this则this指代什么是根据运行时此函数在什么对象上被调用 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向
先看一个在全局作用范围内使用this的例子
代码如下:
<script type=>
console
log( === window);
console
log(window
alert ===
alert);
console
log(
parseInt(
));
</script>
函数中的this是在运行时决定的而不是函数定义时如下
代码如下:
foo() {
console
log(
fruit);
}
fruit = ;
foo();
pack = {
fruit:
foo: foo
};
pack
foo();
全局函数apply和call可以用来改变函数中this的指向如下
代码如下:
foo() {
console
log(
fruit);
}
fruit = ;
pack = {
fruit:
};
foo
apply(window);
foo
apply(pack);
注apply和call两个函数的作用相同唯一的区别是两个函数的参数定义不同
因为在JavaScript中函数也是对象所以我们可以看到如下有趣的例子
代码如下:
foo() {
( === window) {
console
log();
}
}
foo
boo = () {
( === foo) {
console
log();
} ( === window) {
console
log();
}
};
foo();
foo
boo();
foo
boo
apply(window);
prototype
prototype本质上还是一个JavaScript对象 并且每个函数都有一个默认的prototype属性
如果这个函数被用在创建自定义对象的场景中我们称这个函数为构造函数 比如下面一个简单的场景
代码如下:
Person(name) {
name = name;
}
Person
prototype = {
getName: () {
name;
}
}
zhang = Person();
console
log(zhang
getName());
作为类比我们考虑下JavaScript中的数据类型 字符串(String)数字(Number)数组(Array)对象(Object)日期(Date)等 我们有理由相信在JavaScript内部这些类型都是作为构造函数来实现的比如
Array() {
}
arr = Array( );
arr = [ ];
同时对数组操作的很多方法(比如concatjoinpush)应该也是在prototype属性中定义的
实际上JavaScript所有的固有数据类型都具有只读的prototype属性(这是可以理解的因为如果修改了这些类型的prototype属性则哪些预定义的方法就消失了) 但是我们可以向其中添加自己的扩展方法
Arrayprototypemin = () {
min = [];
( i = ; i < length; i++) {
([i] < min) {
min = [i];
}
}
min;
};
consolelog([ ]min());
注意这里有一个陷阱向Array的原型中添加扩展方法后当使用forin循环数组时这个扩展方法也会被循环出来
下面的代码说明这一点(假设已经向Array的原型中扩展了min方法)
arr = [ ];
total = ;
( i arr) {
total += parseInt(arr[i] );
}
consolelog(total);
解决方法也很简单
arr = [ ];
total = ;
( i arr) {
(arrhasOwnProperty(i)) {
total += parseInt(arr[i] );
}
}
consolelog(total);
constructor
constructor始终指向创建当前对象的构造函数比如下面例子
代码如下:
arr = [
];
console
log(arr
constructor === Array);
Foo = () { };
console
log(Foo
constructor === Function);
obj = Foo();
console
log(obj
constructor === Foo);
console
log(obj
constructor
constructor === Function);
但是当constructor遇到prototype时有趣的事情就发生了
我们知道每个函数都有一个默认的属性prototype而这个prototype的constructor默认指向这个函数如下例所示
代码如下:
Person(name) {
name = name;
};
Person
prototype
getName = () {
name;
};
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);
当时当我们重新定义函数的prototype时(注意和上例的区别这里不是修改而是覆盖) constructor的行为就有点奇怪了如下示例
代码如下:
Person(name) {
name = name;
};
Person
prototype = {
getName: () {
name;
}
};
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);
为什么呢?
原来是因为覆盖Personprototype时等价于进行如下代码操作
代码如下:
Person
prototype = Object({
getName: () {
name;
}
});
而constructor始终指向创建自身的构造函数所以此时Personprototypeconstructor === Object即是
代码如下:
Person(name) {
name = name;
};
Person
prototype = {
getName: () {
name;
}
};
p = Person();
console
log(p
constructor === Object);
console
log(Person
prototype
constructor === Object);
console
log(p
constructor
prototype
constructor === Object);
怎么修正这种问题呢?方法也很简单重新覆盖Personprototypeconstructor即可
代码如下:
Person(name) {
name = name;
};
Person
prototype = Object({
getName: () {
name;
}
});
Person
prototype
constructor = Person;
p = Person();
console
log(p
constructor === Person);
console
log(Person
prototype
constructor === Person);
console
log(p
constructor
prototype
constructor === Person);