1- 继承
(1)借用构造函数继承成员
<script>
function Person(name,age){
this.type = 'Person-我的属性'
this.name = name
this.age = age
}
Person.prototype.sayName = function(){
console.log("我是原型的方法");
}
function Student(name,age){
// 借用构造函数继承成员
Person.call(this,name,age)
}
var s1 = new Student("张三",91)
console.log(s1.type);
console.log(s1.name);
console.log(s1.age);
// 继承不会继承构造函数的原型,只能继承构造函数
console.log(s1.sayName());
</script>
新构造函数中使用的是(需要继承的构造函数名字).call(this,继承的属性)从而继承
// 继承不会继承构造函数的原型,只能继承构造函数
(2)原型对象拷贝继承原型对象成员
for(var key in Person.prototype){
Student.prototype[key] = Person.prototype[key]}
此时Student实例可以使用Person原型中的方法,继承了Person原型中的内容
(3)原型继承
Student.prototype = new Person()
此时Student实例可以使用Person原型中的方法,继承了Person原型中的内容
2- 函数
函数声明必须有名字
函数声明:
函数声明会函数提升,在预解析阶段就已经创建,声明前后都可以调用
function foo(){
}
函数表达式:
var foo = function (){
}
函数表达式类似于变量赋值
函数表达式可以没有名字,例如匿名函数
函数表达式没有变量提升,在执行阶段创建,必须在表达式执行之后才可以调用
var foo = function(){
}
函数的调用方式:函数的调用方式决定了this指向
普通函数调用:非严格=>window,严格:undefined
构造函数调用:非严格=>实例对象,原型方法中的this也指向实例对象
对象方法调用:非严格=>该方法所属对象
3- call、apply、bind
(1)call:
<script>
function fn(a,b){
console.log(this,a,b);
}
fn();
// 原来指向的是window,undefined
// 修改了this指向就能打印1,2
var obj = {name:123}
fn.call(obj,1,2)
</script>
function fn(a,b){
console.log(this,a,b);
}
fn();
打印
创建一个对象并用call调用:
var obj = {name:123}
fn.call(obj,1,2)
修改了this指向从window变为了对象obj
打印
(2)apply
apply()与call()方法类似,只有一个区别,就是call()方法接收的是若干个参数的列表,而"apply()"方法接收的是数组,只能传数组
<script>
function fn(a, b) {
console.log(this, a, b);
}
var obj = {name:"buka"}
fn.apply(obj,[1,2])
// apply就修改成只传接数组的形式
</script>
(3)bind
4- 高阶函数
注:
函数可以作为参数
在eat中传入函数
eat(function(){
console.log("吃完了");
})
函数可以作为返回值:闭包
5- 闭包
闭包的用途:闭包就是函数内部和外部的桥梁
可以在函数外部读取函数内部的成员
让函数内的成员始终存活在内存中
通过这样的操作可以实现:内部的匿名函数可以访问其外部的a=10
在这种情况下,内部函数可以访问并操作外部函数的变量a,并且在外部函数调用后仍然保持对a的访问权限。
6- 函数作用域、作用域链
(1)无块级作用域
<script>
{
var foo = 'bar'
}
console.log(foo);
if(true){
var a = 123
}
console.log(a);
</script>
(2)内层作用域可以访问外层,反之不行,比如同级函数不能调用同级函数里的变量,也就是外部不能调用内部成员
// 作用域链
var a = 10
function fn(){
var b = 20
function fn1(){
var c = 30
console.log(a+b+c);
}
function fn2(){
var d = 40
console.log(c+d);
}
fn1()
fn2()
}
fn()
fn2()不能访问fn1()中的成员c
7- 函数递归
本质上就是函数自己调用自己
<script>
var i = 0;
// 函数内部调用函数本身的时候就形成了递归
function fn(){
i++;
if(i>10){
return
}
console.log(i);
fn();
}
fn();
</script>
不在fn()内自调用fn(),只能打印1,调用了可以打印1到10
8- 阶乘
<script>
// 阶乘
function f(num){
if(num<=1){
return 1;
}
return num*f(num-1)
}
var a = f(5);
console.log(a);
// 1、5*f(4)
// 2、5*4*f(3)
// 3、5*4*3*f(2)
</script>
return num*f(num-1) ==>return 自己(函数本身)同时传参
9- 数组与伪数组
(1)对象与数组的关系
对象.length是undefined,因为其不具有数组内置的length特性
(2)伪数组
<script>
// 数组 索引
var arr = [1,2,3,4,5];
arr[0];
console.log(arr.length);
// 对象 key (伪数组)
var obj ={0:"a",1:"b",2:"c",length:3}
console.log(obj[0]);
console.log(obj.length);
for(var i = 0;i<obj.length;i++){
console.log(obj[i]);
}
// 伪数组 本质是对象
// 伪数组 不能使用数组的api(原型中的方法)
// 伪数组 数据类型是对象
</script>
-->伪数组有length属性
-->伪数组也有0、1、2、3等属性对象,看起来像数组,但不是数组
不定义length就不能使用.length
常见的伪数组:
1、函数内部的arguments
2、dom对象列表
3、jQuery对象$(“div”)
伪数组是一个对象,不是数组。其存在的意义就是让普通对象也能正常使用数组的很多方法
这里的a1没有任何作用,就是一个媒介,自始至终都是空的