this
玩转this的一些函数——bind、apply、call 的用法
- bind:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
bind()
方法创建一个新的函数,当函数被调用时,将其this值设定为bind的第一个参数。之后的参数数列作为参数传递给被调用函数。
- apply:
fun.apply(thisArg,[argsArray])
apply()
方法调用一个函数,使其具有一个指定的this值,以及作为一个数组(或类数组)提供的参数。在ES5开始,只要有一个length属性和[0...length)范围内的整数属性,即可传给apply来使用。
- call:
fun.call(thisArg[, arg1[, arg2[, ...]]])
call()
方法同样是调用一个函数,使其具有指定的this值和提供的参数(列表)。可以让call()中的对象调用当前对象所拥有的function。
call()
与apply()
的作用是类似的,只有一个区别: call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。
一些练习题:
在没有call、apply、bind 的情况下,this的值通常依赖于函数的调用者
- 1
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() //弹出 John: hi! 因为函数调用者是 对象john
- 2
func()
function func() {
alert(this)
}
//申明提升,再调用函数,调用者为window,所以弹出window
- 3
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
//先打印document,再打印window,因为第一个打印的调用者是document,而setTimeout的调用者通常是window。
- 4
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)
//弹出John,使用call方法将函数的this值指向了john对象。
- 5
var module= {
bind: function(){//添加 _this = this
$btn.on('click', function(){
console.log(this) //this指向的是$btn,所以下面的调用是无法成功的
this.showMsg();//_this.showMsg()
})
},
showMsg: function(){
console.log('饥人谷');
}
}
原型链
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
Preson
是构造函数,也是一个对象。
p
为Person
的实例,拥有Person
原型链上的属性和方法。
p.__proto__
指向Person.prototype
。
Person
中的prototype
中的__proto__
指向的是Object()的prototype,其中有toString
等方法,所以p
可以调用toString
方法。
原型链:每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。
原型链、instanceOf 参考
instanceOf:
instanceOf
运算符用来测试一个对象在其原型链中是否存在一个构造函数prototype 属性。其逻辑是沿着原型链层层递进,比较对象中是否存在构造函数的prototype。
function instanceof(obj, fn) {
var objProto = obj.__proto__
while (objProto) {
if (objProto === fn.prototype) {
return true
}else{
objProto = objProto.__proto__
}
}
return false
}
小题目:对String做扩展,实现如下方式获取字符串中频率最高的字符
String.prototype.getMostOften = function () {
var target = {};
this.split('').forEach(function (i) {
target[i] ? target[i] += 1 : target[i] = 1;
})
console.log(target)
var max = 0,
maxKey = ''
Object.keys(target).forEach(function (key) {
if (target[key] > max) {
max = target[key]
maxKey = key
}
return maxKey
}
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次
继承
继承有啥用:
1.子类拥有父类的属性和方法,不需要重复写代码,也不需要更多的空间,修改时也只需修改一份代码
2.可以重写和扩展父类的属性和代码,又不影响父类本身
继承的一些小问题:
1.下面两种写法有什么区别?
//方法1
function People(name, sex){
this.name = name;
this.sex = sex;
this.printName = function(){
console.log(this.name);
}
}
var p1 = new People('饥人谷', 2)
//方法2
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('若愚', 27);
方法一的printName是在父类自身里的一个方法,当子类继承时,将产生一个属于子类自己的功能相同的新的printName。
方法二中的printName是存在于原型链中的一个方法,当子类继承时,由于同时继承了prototype,所以子类也可以使用printName的方法。
方法二与方法一相比,法二可以节省部分内存。
2.Object.create
有什么作用?兼容性如何?
Object.create() 方法会使用指定的原型对象及其属性去创建一个新的对象。
3.hasOwnProperty
有什么作用? 如何使用?
hasOwnProperty() 方法会返回一个布尔值,指示对象是否具有指定的属性作为自身(不继承)属性。
var o = {
a: 1;
b: 2
}
o.hasOwnProperty("a")//true
o.hasOwnProperty("c")//false
o.hasOwnProperty("toString")//false
4.如下代码中call
的作用是什么?
function Person(name, sex){
this.name = name;
this.sex = sex;
}
function Male(name, sex, age){
Person.call(this, name, sex); //这里的 call 有什么作用
this.age = age;
}
在调用Male时,运行到Person函数时,将Person的this 指定为 Male的this。并且将Male的 name和sex 作为参数传给Person。
5.补全代码,实现继承
function Person(name, sex){
this.name = name
this.sex = sex
}
Person.prototype.printName = function(){
console.log(this.name)
};
function Male(name, sex, age){
this.name = name
this.sex = sex
this.age = age
}
Male.prototype = Object.create(Person.prototype)
Male.prototype.getAge = function(){
console.log(this.age)
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();