四种绑定规则
优先级从低到高:默认绑定、隐式绑定、显示绑定、new绑定。
默认绑定
function foo(){
console.log(this.a)
}
var a = 'window.a'
foo() // window.a,函数调用模式
//严格模式下,全局对象将无法使用默认绑定,即执行会报undefined的错误:
function foo(){
"use strict"
console.log(this.a)
}
var a = 'window.a'
foo() // Uncaught TypeError: Cannot read property 'a' of undefined,函数调用模式
隐式绑定
除直接对函数进行调用外,有些情况,函数的调用是在某个对象上触发的,即调用位置上存在上下文对象:
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
}
obj.foo() // obj.a,方法调用模式
多层调用链:
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj1 = {
a: 'obj1.a',
foo1: foo
}
var obj2 = {
a: 'obj2.a',
foo2: obj1
}
obj2.foo2.foo1() // obj1.a,方法调用模式
函数别名(隐式丢失):
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
}
var bar = obj.foo // obj.foo是引用属性,赋值给bar的实际上就是foo函数
bar() // window.a,函数调用模式
回调函数(隐式丢失):
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
}
setTimeout(obj.foo,100) // window.a,函数调用模式
显示绑定
通过改变对象的prototype关联对象,call和apply作用一样,区别是接受参数方式不同:
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj1 = {
a: 'obj1.a'
}
var obj2 = {
a: 'obj2.a'
}
foo.call(obj1) // obj1.a ,间接调用函数
foo.apply(obj2)// obj2.a ,间接调用函数
硬绑定:
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj1 = {
a: 'obj1.a'
}
var obj2 = {
a: 'obj2.a'
}
var bar = function(){
foo.call(obj1) // foo已经显示绑定了obj1,this指向obj1.
}
setTimeout(bar ,100) // obj1.a ,函数调用模式
bar.call(obj2) // obj1.a , 间接调用函数
new 绑定
function foo(a) {
this.a = a;
}
var a = 'window.a'
var bar1 = new foo('bar1.a');
console.log(bar1.a) // bar1.a ,构造函数调用模式
var bar2 = new foo('bar2.a');
console.log(bar2.a) // bar2.a ,构造函数调用模式
箭头函数(拓展)
箭头函数的this绑定取决于外层(函数或全局)作用域:
①正常调用:
//普通函数
function foo(){
console.log( this.a );
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
};
obj.foo(); // obj.a
// 箭头函数
var foo = () => {
console.log( this.a );
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
};
obj.foo(); // window.a
foo.call(obj) // window.a
②回调函数:
// 普通函数
function foo(){
return function(){
console.log( this.a );
}
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
};
var bar = obj.foo();
bar(); // window.a
// 箭头函数
var foo = () => {
return function(){
console.log( this.a );
}
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
};
var bar = obj.foo();
bar(); // obj.a
函数调用
4种调用模式:函数调用模式、方法调用模式、构造函数调用模式、间接调用模式。
函数调用模式
function foo(){
console.log(this.a)
}
var a = 'window.a'
foo() // window.a ,函数调用模式
方法调用模式
一个函数被保存为对象的一个属性时,称它为一个方法。当一个方法被调用时,this被绑定到该对象。如果调用表达式包含一个提取属性的动作,那么它就是被当做一个方法来调用:
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj = {
a: 'obj.a',
foo: foo
}
obj.foo() // obj.a ,方法调用模式
构造函数调用模式
函数或者方法调用之前带有关键字new,它就构成构造函数调用:
function foo(a) {
this.a = a;
}
var a = 'window.a'
var bar1 = new foo('bar1.a');
console.log(bar1.a) // bar1.a ,构造函数调用模式
间接调用模式
function foo(){
console.log(this.a)
}
var a = 'window.a'
var obj1 = {
a: 'obj1.a'
}
var obj2 = {
a: 'obj2.a'
}
foo.call(obj1) // obj1.a ,间接调用函数
foo.apply(obj2) // obj2.a ,间接调用函数
New
操作符
new
操作符新建一个对象,这个对象原型指向构造函数的prototype
,执行构造函数后返回这个对象:
var Func = function(){} //声明构造函数Fun
var func = new Func() //新建实例fun
创建一个空对象
var obj = new Object()
链接到原型
//当调用构造函数创建一个实例后,实例内部将包含一个指针(内部属性__proto__)指向构造函数的原型对象
obj.__proto__ = Func.prototype
绑定this
指向,执行构造函数
//创建新对象后,将构造函数的作用域赋给新对象,因此this就指向了这个新对象
var result = Func.call(obj)
确保返回的是对象
if(typeof(result) == "object"){//判断返回值类型
func = result //引用类型,返回这个引用类型的对象
}else {
func = obj //基本数据类型,返回新创建的对象obj
}