继承
面向对象三大特征:封装、继承、多态
对象的拷贝(继承)
// 继承演示(对象的继承)
function extend(child, parent) {
for (var key in parent) {
if (child[key]) continue; // 如果child中有该成员,不替换成parent对象中的成员
child[key] = parent[key];
}
}
var parent = {
name: '王健林',
age: 60,
house: '别墅',
money: 1000000,
car: '玛莎拉蒂',
play: function () {
console.log('弹吉他');
}
};
var child = {
name: '王思聪',
age: 18
};
// 把parent对象的所有成员 拷贝到 child对象上 (实现继承)
extend(child, parent);
原型继承
// 1 原型继承
function Super() {
this.color = 'red';
}
function Sub() {
}
Sub.prototype = new Super();
Sub.prototype.constructor = Super;
var sub = new Sub();
console.log(sub.color);
原型继承的问题:无法给构造函数传参
借构造函数继承
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, score) {
Person.call(this, name, age, sex);
this.score = score;
}
var stu = new Student('zs', 18, '男', 100);
console.log(stu);
借用构造函数继承问题:无法重用方法
组合式继承
// 结合原型继承和组合式继承
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.sayHi = function () {
console.log(this.name);
}
function Student(name, age, sex, score) {
Person.call(this, name, age, sex);
this.score = score;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
var stu = new Student('zs', 18, '男', 100);
console.log(stu);
函数进阶
函数的定义方式
- 函数声明
- 函数表达式
new Function
函数声明
function foo () {
}
函数表达式
var foo = function () {
}
函数声明与函数表达式的区别
- 函数声明必须有名字。会函数提升,声明前后都可以调用。
- 函数表达式可以没有名字,例如匿名函数。类似于变量赋值只是该变量进行提升,函数没有变量提升,必须在表达式执行之后才可以调用。
函数的调用方式
- 普通函数
- 构造函数
- 对象方法
函数内 this
指向的不同场景
函数的调用方式决定了 this
指向的不同:
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
函数内部的this,是由函数调用的时候来确定其指向的
函数也是对象
- 所有函数都是
Function
的实例
call,apply,bind
-
call 和 apply 特性一样
- 都是用来调用函数,而且是立即调用
- 但是可以在调用函数的同时,通过第一个参数指定函数内部
this
的指向 - call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
- apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
- 如果第一个参数指定了
null
或者undefined
则内部 this 指向 window
-
bind
- 它和 call、apply 最大的区别是:bind 不会立即调用
例子
//让数组的每一项作为方法的参数
// Math.max(arr)不能求数组中的最大值 Math.max.apply(Math, arr)可以
var arr = [2, 1, 8, 9, 10, 3];
console.log(Math.max.apply(Math, arr));
console.log.apply(console, arr);
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域
// 创建一个新函数,将"this"绑定到module对象
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81
函数的其它成员
- arguments
- 实参集合
- caller
- 函数的调用者
- length
- 形参的个数
- name
- 函数的名称
function max() {
// 当函数的参数个数不固定的时候
// 在函数内部,可以通过arguments获取到实际传过来的参数
var max = arguments[0];
for (var i = 0; i < arguments.length; i++) {
if (max < arguments[i]) {
max = arguments[i];
}
}
return max;
}
console.log(max(5, 1, 3, 8, 2));
高阶函数
- 函数可以作为参数
- 函数可以作为返回值
作为参数
设置断点的方法:f12,Sources,在源码里点击某一行即可设置断点,f5刷新,点击f11进行下一步操作
function eat (callback) {
setTimeout(function () {
console.log('吃完了')
callback()
}, 1000)
}
eat(function () {
console.log('去唱歌')
})