1.instanceof 可以判断实例是否在某个对象的原型上:
function A() { this.a = "a"; } function B() { this.b = "b"; } B.prototype = new A(); var test = new B(); console.log(test instanceof A); //true console.log(test instanceof B); //true console.log(test instanceof Object); //true //test拥有A、B、Object任何一个构造器的属性和方法
2.hasOwnProperty 可以判断对象是否有prototype原型的属性,但是不包括继承过来的属性和方法,如果要判断包括继承的属性,用 in。
function A() { this.a = "a"; } A.prototype.b = "b"; console.log(A.prototype.hasOwnProperty("a")); //false console.log(A.prototype.hasOwnProperty("b")); //true console.log(A.prototype.hasOwnProperty("hasOwnProperty")); //false console.log('hasOwnProperty' in A); //true
2.5.访问实例属性时,先在该实例搜索该属性。如果没有该属性,就搜索原型。如果通过原型链实现继承,就会顺着原型链往上搜索。 也就是说,子类的属性不会覆盖继承自原型链的属性。
function A(){ this.prop = 'a'; } function B(){ this.prop = 'b'; this.method = function(){ console.log(this.prop); //b delete this.prop; console.log(this.prop); //a } } B.prototype = new A(); var test = new B(); test.method();
3.每个对象的prototype原型上都有constructor属性,指向构造它的函数
function A() { this.a = "a"; } console.log(A.prototype.constructor === A); //true
4.call和apply可以改变this的作用域
function A() { this.name = "a"; this.method = function(){ var arr = Array.prototype.slice.call(arguments); console.log(arr.join(' ') + " " + this.name); } } var a = new A(); var b = { name: "b" }; a.method.call(b, '1', '2', '3'); //1,2,3 b
function A(name) { this.name = name; this.method = function(){ console.log(this.name); } } function B() { A.call(this, "a"); } var test = new B(); test.method(); // a test.name = "b"; test.method(); // b
区别是appy用的是数组
function A(arg1, arg2) { this.method = function() { console.log(arg1, arg2); }; } function B() { A.apply(this, ["1", "2"]); } var test = new B(); test.method(); // 1, 2
5.组合继承方式用call继承属性,用prototype实例化对象继承方法
function A(name) { this.name = name; } A.prototype.method = function() { console.log(this.name); } function B(name) { A.call(this, name); } B.prototype = new A(); var t1 = new B("2"); t1.method(); //2 var t2 = new B("3"); t2.method(); //3 console.log(t1.method == t2.method); //true
6.工厂模式和寄生构造函数模式
除了寄生构造函数模式需要用new实例化构造函数,并且包装名被叫做构造函数以外,和工厂模式没有本质性的区别。
也可以说两者就是概念的区别,结果一样,只是用new能够直观看出是寄生构造函数。
寄生构造函数应用场景在于不污染原生对象的情况下添加方法,缺点在于不能用instanceof来确定所属对象。
函数第一次调用时,生成执行上下文与活动对象(actviation object)。
活动对象里面包含arguments,this,函数内部声明的变量
7.function的this永远指向调用它的对象,而不是函数创建时所在的对象。而鉴于JS所谓的“万物皆对象”,这个this因此可以是任何物件,比如Global对象。
var x = 0; var foo = { x:1, bar:{ x:2, baz: function () { console.log(this.x); } } } foo.bar.baz(); // 2 var a = foo.bar.baz; a(); //0 (foo.bar.baz = foo.bar.baz)() //0
因为this永远指向函数被调用时的对象,由于 var a = foo.bar.baz; ,相当于把 foo.bar.baz 的函数复制了一份给 a ,所以执行 a() 的时候,相当于 window.a() ,也就是this指向了执行的对象 window,所以输出0。
而(foo.bar.baz = foo.bar.baz)(); 这句先执行括号内的赋值语句,赋值完成后返回foo.bar.baz 方法。但是执行的却是IIFE,也就是函数而不是对象的方法,this指向的是window这个对象,所以也输出0。
foo = function(){ this.myName = "Foo function."; } foo.prototype.sayHello = function(){ console.log(this.myName); } foo.prototype.bar = function(){ setTimeout(this.sayHello, 10); } var f = new foo; f.bar();
setTimeout会将第一个参数推到下一个事件循环的全局环境执行。由于this指向被调用的环境,相当于setTimeout里的this指向window。所以在这里sayHello方法里的this指向了window导致输出undefined。
如果要输出foo.myName的话,可以用bind方法将setTimeout中的 this 指向foo里的this。setTimeout(this.sayHello.bind(this), 10);
8.变量当对象的属性
var obj = {}; var p1; var p2 = "a"; obj[p1] = 123; obj[p2] = 456; console.log(obj[p1]); //123 console.log(obj.a === obj[p2]); //true