1:构造函数和new命令
对象相当于一个实物的抽象,其中封装了属性和方法(可以用一个变量,函数等作为对象),而在面向对象编程语言之中存在一个“类”的概念,这个类就相当于是对象的模板,对象就相当于是类的实例。但是在JS之中,没有这个类,对象是基于构造函数以及原型链,也就是说,构造函数是对象的模板,对象是构造函数的实例
构造函数当做模板,使用new命令执行,并且返回实例对象
构造函数特点:
1:使用this关键字
2:在执行时使用new命令
new命令
基本用法:1:可以执行构造函数,返回一个实例对象
2:使用new命令时,根据需要,构造函数可以添加参数
3:执行构造函数的时候,构造函数后面可以加括号,也可以不加括号
如果某个构造函数没有使用new命令,就相当于是一个普通函数,此时,函数里面的this指向的就是全局变量,而不会生成一个实例对象,如果想要解决这种问题
第一种方法:使用严格模式,在函数的第一句加上use strict,如果没有使用new命令,this就会指向全局变量,而在严格模式下面,函数内部的this不能指向全局变量,此时,就会报错
第二种方法:使用函数判断是否使用new命令
<script>
function a(foo,bar){
if(!(this instanceof a)){
return new a(foo,bar);
}
this._foo=foo;
this._bar=bar;
}
console.log(a(1,2)._foo);
</script>
使用new命令的基本原理:
首先先创建一个空对象,作为要返回的实例对象,其次将这个空对象,指向prototype属性,接着将空对象指向函数内部的this变量,最后开始执行构造函数
而在构造函数中有return的时候,如果return后面跟着一个对象,使用new命令调用的时候,就会返回该对象,否则就会返回this指向的对象
而在函数中如果没有使用this却使用new命令调用,该函数就相当于是一个普通函数,使用new命令调用,就会返回一个空对象
new命令简化流程
new.target 属性
如果一个函数使用了new命令,用new.target就会返回该函数,否则就会返回undefined,利用这一方法,可以判断函数中是否使用new命令
<script>
function f(){
if(!(new.target)){
return "请使用new命令调用";
}
}
console.log(f());
</script>
object.create()
以某个实例为模板,生成另一个实例
this
this的使用场合:
有三种
1:this可以指向全局变量window
2:this可以在构造函数中使用,指向对象
3:适用于对象的方法中
将A对象的方法赋给B对象,在这个过程中this指向也会从A转为B
在逻辑运算符中,||运算符,如果||前面为false,那么就会返回后面这个元素的值,如果||前面为true,那么就会返回||前面的值
this中的注意点
1:避免第二层使用this
例如:
var o={
f1:function(){
console.log(this);
var f2=function(){
console.log(this);
}();
}
};
o.f1();
这个例子中两层函数中都是用了this,而第一个返回object,第二个则返回window,说明第一个this指向对象,而第二个函数则指向了全局变量
而如果将代码改一下,引入一个中间值
var o={
f1:function(){
console.log(this);
var that=this;
var f2=function(){
console.log(that );
}();
}
};
o.f1();
则返回的结果都是object,因为赋值给that的this变量是指向外层this的,而在JS严格模式下,当函数中的this变量指向全局变量的时候,就会报错
2:数组处理方法中的map。forEach方法中的this调用时,也要注意this的指向
案例:
var o={
v:"hello",
p:["a1","a2"],
f:function (){
this.p.forEach(function(item){
console.log(this.v+" "+item);
});
}
}
forEach遍历中的this指向的是全局变量,内部函数中的this是没有办法指向外部的,所以办法拿到o.v,就会返回undefined
如果修改一下代码:
var o={
v:"hello",
p:["a1","a2"],
f:function (){
var that=this;
that.p.forEach(function(item){
console.log(that.v+" "+item);
});
}
}
此时就会返回 hello a1 hello a2
还有一种方法处理,就是将this写成是forEach的第二个参数
var o={
v:"hello",
p:["a1","a2"],
f:function (){
this.p.forEach(function(item){
console.log(this.v+" "+item);
},this);
}
}
o.f();
就会返回 hello a1 hello a2
绑定this的方法
绑定this的方法有三种
1:function.prototype.call()
指定函数内部的this指向,
一般情况下,括号里面如果是空,null或者是undefined,this默认指向全局变量:window
call的第一个参数是this指向的参数,后面的参数是函数调用过程中需要用到的参数,一般在应用中,call方法用于调用对象的原生方法之中。
2:function.prototype.apply();
apply方法和call方法很相似,唯一的区别是,apply可以使用数组来调用函数的参数,第一个参数是this指向的参数,第二个参数是由存放有函数调用需要的参数组成数组
应用:
找出数组中的最大元素:使用MAth方法和apply的方法相结合 Math.Max.apply();
将一个数组中的空对象转化为undefined:空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined。因此,遍历内部元素的时候,会得到不同的结果。
转换类似数组对象:上面代码的apply方法的参数都是对象,但是返回结果都是数组,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键。
绑定回调函数对象
3:functio.prototype.bind();
bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
bind比call和apply更先进的一步是除了可以调用this关键字之外,还可以调用函数自身的参数
如果bind的第一个参数是null或者是undefined,就表示说this指向全局变量
bind的一些注意事项
1:每次返回一个新的函数,监听事件的时候,不能写成下面这样。element.addEventListener(‘click’, o.m.bind(o));
click事件绑定bind方法生成的一个匿名函数。这样会导致无法取消绑定,正确的是var listener = o.m.bind(o);
element.addEventListener(‘click’, listener);
// …
element.removeEventListener(‘click’, listener);
2:回调函数使用:回调函数是JavaScript最常用的模式之一,但是一个常见的错误是,将包含this的方法直接当作回调函数。还有一种情况比较隐蔽,就是某些数组方法可以接受一个函数当作参数。这些函数内部的this指向,很可能也会出错。
3:利用bind改写JS的原生方法适用形式
4:call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别