你不知道的JavaScript:this和对象原型

this在调用时绑定,完全取决于函数的调用位置。
绑定规则

  1. 默认绑定(独立函数调用,绑定到全局对象,但严格模式下this会绑定到undefined)
function foo() {
    console.log(this.a);
}
var a = 2;
foo(); // 2
  1. 隐式绑定:当函数引用有上下文对象时,this绑定在这个上下文对象上,最后一层调用位置起作用
function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
}
var a = "hello";
obj.foo(); // 2

隐式丢失

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
}
var bar = obj.foo; //实际上指向foo本身,独立函数调用
var a = "hello world";
bar(); // hello world
  1. 显示绑定,call和apply,第一个参数是对象,函数调用时将this绑定到这个对象上
    硬绑定
function foo() {
    console.log(this.a);
}
var obj = {
    a: 2
}
var bar = function() {
    foo.call(obj);
}
bar(); // 2
setTimeout(bar, 1000); // 2
var a = "hello world";
bar.call(window); // 2
  1. new绑定:用new调用函数时,会创建一个新对象,并将这个新对象绑定到函数调用的this上。
function foo(a) {
    this.a = a;
}
var bar = new foo(2); //将返回的对象bar绑定在foo的this上
console.log(bar.a); //2

绑定规则优先级

  1. 显示绑定高于隐式绑定
function foo() {
    console.log(this.a);
}
var obj1 = {
    a: 2,
    foo: foo
}
var obj2 = {
    a: 3,
    foo: foo
}
obj1.foo();//2
obj2.foo();//3
obj1.foo.call(obj2);//3,先将foo中的this绑定到obj2,在被obj1调用
obj2.foo.call(obj1);//2
  1. new绑定高于隐式绑定
function foo(something) {
    this.a = something;
}
var obj1 = {
    foo:foo
};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a); //2
obj1.foo.call(obj2,3);
console.log(obj2.a); //3
var bar = new obj1.foo(4);
console.log(bar.a);//4
console.log(obj1.a);//2
  1. new绑定高于硬绑定(new 和call或者apply不能同时使用)
function foo(something) {
    this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); //2
var baz = new bar(3);
console.log(obj1.a); //2
console.log(baz.a);//3

new中使用硬绑定,可以预先设置一些参数,使用new初始化时只需传入其他的参数,柯里化的一种

function foo(p1, p2) {
    this.val = p1 + p2;
}
var bar = foo.bind(null, "p1"); //不关心硬绑定到哪里,this会被new修改
var baz = new bar("p2");
console.log(baz.val);//p1p2

绑定例外
把null或者undefined传入call,apply,bind等,忽略this

function foo() {
    console.log(this.a);
}
var a = 2;
foo.call(null);//2,实际使用默认绑定

间接引用

function foo() {
    console.log(this.a);
}
var a = 2;
var o = {a:3, foo:foo};
var p = {a:4};
o.foo();//3
(p.foo = o.foo)();//2,返回值是目标函数的引用,所以是默认绑定

软绑定

function foo() {
    console.log("name: " + this.name);
}
var obj = {name:obj},
    obj2 = {name:obj2},
    obj3 = {name:obj2};
var fooOBJ = foo.softBind(obj);
fooOBJ(); //name:obj
obj2.foo = foo.softBind(obj);
obj2.foo();//name:obj2
fooOBJ.call(obj3);//name:obj3
setTimeout(obj2.foo, 10);//name:obj

箭头函数:根据外层作用域来决定this,箭头函数的绑定无法修改

function foo() {
    return (a) => {
        //this继承自foo()
        console.log(this.a);
    }
}
var obj1 = {a:2};
var obj2 = {a:3};
var bar = foo.call(obj1);
bar.call(obj2);//2

数组,添加数字类属性,数组长度增加

var myArray = ["foo", 42, "bar"];
myArray.baz = "baz";
console.log(myArray.length);
myArray["3"] = "baz";
console.log(myArray.length);

属性描述符:writable,是否可以修改属性的值;configurable,属性描述符是否可修改,为false的话禁止删除这个属性;Enumerable,可枚举
getter / setter

var myObject = {
    get a() {
        return this._a_;
    },
    set a(val) {
        this._a_ = val * 2; 
    }
};
myObject.a = 2;
console.log(myObject.a);

属性的存在性,值为undefined或者不存在都返回

undefined
var myObject = {
    a:2
};
"a" in myObject; // true, 会检查原型链
"b" in myObject; //false
myObject.hasOwnProperty("a");//true,只检查对象本身
myObject.hasOwnProperty("b");//false

混入

1、 显示混入

function mixin(sourceObj, targetObj) {
    for(var key in sourceObj) {
        if(!(key in targetObj)) {
            targetObj[key] = sourceObj[key];
        }
    }
    return targetObj;
}

var Vehicle = {
    engine: 1,
    ignition: function() {
        console.log("turning on my engine.");
    },
    drive: function() {
        this.ignition();
        console.log("steering and moving forward!");
    }
};

var Car = mixin(Vehicle, {
    wheels: 4,
    drive: function() {
        Vehicle.drive.call(this);
        console.log("rolling on all" + this.wheels + "wheels!");
    }
});

2、混合混入,先进行复制,之后再特殊化,效率低,不常用

function mixin(sourceObj, targetObj) {
    for(var key in sourceObj) {
        targetObj[key] = sourceObj[key];
    }
    return targetObj;
}

var Vehicle = { 
    //...
};

var Car = mixin(Vehicle, {});
mixin({
    wheels: 4,
    drive:function(){
        //...
    }
}, car);

3、寄生继承

function Vehicle() {
    this.engine = 1;
}
Vehicle.prototype.ignition = function() {
    console.log("turning on my engine.");
};
Vehicle.prototype.drive = function() {
    this.ignition();
    console.log("steering and move forward!");
};
function Car() {
    var car = new Vehicle();
    car.wheels = 4;
    var vehDrive = car.drive;
    car.drive = function() {
        vehDrive.call(this);
        console.log("rolling on all" + this.wheels + "wheels!");
    }
    return car;
}
var mycar = new Car();
mycar.drive();

4、 隐式混入

var Something = {
    cool: function() {
        this.greetng = "hello world";
        this.count = this.count ? this.count + 1 : 1;
    }
};

Something.cool();
Something.greetng; // hello world
Something.count; // 1

var Another = {
    cool: function() {
        Something.cool.call(this);
    }
};
Another.cool();
Another.greetng; //hello world
Another.count; // 1, count 不是共享状态

隐式屏蔽

var anotherObject = {
    a: 2
};
var myObject = Object.create(anotherObject);
anotherObject.a; // 2
myObject.a; //2
anotherObject.hasOwnProperty("a"); //true
myObject.hasOwnProperty("a"); //false
myObject.a++; //隐式屏蔽
anotherObject.a; //2
myObject.a;//3
myObject.hasOwnProperty("a");//true

构造函数 || 调用

function nosp() {
    console.log("don't mind me!");
}
var a = new nosp(); //don't mind me!
a; // {} 

委托模式

Task = {
    setID: function(ID) {this.id = ID;},
    outputID: function() {console.log(this.id);}
};

//让XYZ委托Task
XYZ = Object.create(Task);

XYZ.prepareTask = function(ID, Lable) {
    this.setID(ID);
    this.Lable = Lable;
};

XYZ.outputTaskDetails = function() {
    this.outputID();
    console.log(this.Lable);
};

时间有点急,这篇可能有些格式上的问题,以后再看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容