继承和函数


继承

对象继承

对象拷贝 for…in

// 封装一个对象之间继承的函数
 function extend(parent, child) {
   for (var k in parent) {
     // 子级有的属性不需要继承
     if (child[k]) {
       continue;
     }
     child[k] = parent[k];
   }
 }
 // 调用函数实现继承
 extend(laoli,xiaoli);

原型继承

 // 封装的构造函数就是用来创建一类对象
 // 继承指的是 类型 和 类型之间的继承
 // 人类类型
function Person(name,age,sex) {
   this.name = name;
   this.age = age;
   this.sex = sex;
 }
 // 学生类型
 function Student(score) {      
   this.score = score;
 }
 // 老师类型
 function Teacher(salary) {
   this.salary = salary;
 }
 // 原型对象,可以将自己的属性和方法继承给将来的实例对象使用
 Student.prototype = new Person("zs",18,"男");
 Student.prototype.constructor = Student;
 // 生成一个实例
 var s1 = new Student(89);
 var s2 = new Student(100);
 console.dir(s1);
 console.dir(s2);
 console.log(s1.name);
 console.log(s1.constructor);

构造函数继承(属性和方法)

属性

// 构造函数的属性的继承
// 人类类型
function Person(name,age,sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
}
// 学生类型
function Student(name,age,sex,score) {
  // 直接对父类型的构造函数进行一个普通调用
  // Person 普通调用过程中,内部的 this 指向的是 window
  // 可以通过 call 方法更改Person 内部的 this
  Person.call(this,name,age,sex); 
  this.score = score;
}
// 老师类型
function Teacher(name,age,sex,salary) {
  Person.call(this,name,age,sex); 
  this.salary = salary;
}
// 创建学生的实例对象
var s1 = new Student("zs",18,"男",89);
var s2 = new Student("ls",19,"男",92);
console.dir(s1);
console.dir(s2);

方法

// 构造函数的属性的继承
// 人类类型
function Person(name,age,sex) {
  this.name = name;
  this.age = age;
  this.sex = sex;
}
// 父类型的原型对象中有方法也需要继承
Person.prototype.sayHi = function () {
  console.log("你好");
};
// 学生类型
function Student(name,age,sex,score) {
  Person.call(this,name,age,sex); 
  this.score = score;
}

Student.prototype = new Person();
Student.prototype.constructor = Student;

// 创建学生的实例对象
var s1 = new Student("zs",18,"男",89);
var s2 = new Student("ls",19,"男",92);

s1.sayHi();

组合继承

属性在构造函数内部继承,方法通过原型继承

 // 组合继承:属性在构造函数内部继承,方法通过原型继承
 function Person(name,age) {
    this.name = name;
    this.age = age;
  }
  Person.prototype.sayHi = function () {
    console.log("你好");
  }
  // 生成一个子类型
  function Teacher(name,age,salary) {
    // 继承父类的属性
    Person.call(this,name,age);
    this.salary = salary;
  }
  // 方法继承,通过原型对象继承
  Teacher.prototype = new Person();
  Teacher.prototype.constructor = Teacher;
  // 生成老师的一个实例
  var t1 = new Teacher("wang",45,10000);
  console.dir(t1);
  console.log(t1.name);
  t1.sayHi();

函数

函数定义方式

• 函数声明
• 函数表达式
• new Function

函数声明与函数表达式的区别

• 函数声明必须有名字
• 函数声明会函数提升,在预解析阶段就已创建,声明前后都可以调用

// 函数声明提升
fun();
fn();
// 函数声明
// 必须定义函数名
function fun() {
   console.log(1);
}

• 函数表达式类似于变量赋值
• 函数表达式可以没有名字,例如匿名函数
• 函数表达式没有函数提升,在执行阶段创建,必须在表达式执行之后才可以调用
• 函数本身也是一种对象,可以调用属性和方法

var fn = function () {
  console.log(2);
 };
 fn();
// 通过构造函数方法定义函数
// 函数本身也是一种对象
var fun = new Function('a','b','var a = "1";console.log(a+b)');
fun(2,3);
console.dir(fun);

函数的调用和this

调用

  • 普通函数
// 1. 普通的函数,是通过 给函数名或者变量名添加 () 方式执行
// 内部的 this 默认指向 window
function fun() {
  console.log(this);
}
fun();
  • 构造函数
// 2.构造函数,是通过 new 关键字进行调用
// 内部的 this 指向的是将来创建的实例对象
function Person(name) {
  this.name = name;
  console.log(this);
}
var p1 = new Person("zs");
Person();
  • 对象方法
 // 3.对象中的方法,是通过对象打点调用函数,然后加小括号
// 内部的 this 默认指向的是调用的对象自己
var o = {
  sayHi: function () {
    console.log("haha");
  },
  fn: fun
}
// this 的指向是要联系执行的上下文,在调用的时候,是按照什么方式调用,指向是不一样的
o.sayHi();
  • 事件函数
// 4.事件函数,不需要加特殊的符号,只要事件被触发,会自动执行函数
// 事件函数的内部 this 指向的是事件源
  document.onclick = function () {
    console.log("事件");
  };
  • 定时器、延时器的函数
 // 5.定时器和延时器中的函数,不需要加特殊的符号,只要执行后,在规定的时间自动执行
// 默认内部的 this 指向的是 window
  setInterval(function () {
    console.log("time");
  },1000);

this

在这里插入图片描述

call、apply、bind

call

• 语法:
fun.call(thisArg,arg1, arg2, arg3, …)

• thisArg
在 fun 函数运行时指定的 this 值
如果指定了 null 或者 undefined 则内部 this 指向 window

• arg1, arg2, … 指定的参数列

• .功能
第一个可以指定函数的 this,第二个可以执行函数并传参

• 返回值:就是函数自己的返回值

apply

• 语法:
fun.apply(thisArg, [argsArray]

• .功能
第一个可以指定函数的 this,第二个可以执行函数并传参

• 返回值:就是函数自己的返回值

bind

• 语法:
fun.bind(thisArg,arg1, arg2, arg3, …)

• thisArg:当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用 new 操作符调用绑定函数时,该参数无效。

• arg1, arg2, …:当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。

• .功能
第一个可以指定函数的 this,bind 方法不能执行函数,但是可以传参

• 返回值:
返回由指定的 this 值和初始化参数改造的原函数拷贝(返回一个新的指定了 this 的函数,也可以叫绑定函数)

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的 call 属性)。 当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。
一个绑定函数也能使用 new 操作符创建对象:这种行为就像把原函数当成构造器。提供的this 值被忽略,同时调用时的参数被提供给模拟函数。

总结

call 和 apply 特性一样

• 都是用来调用函数,而且是立即调用

• 但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向

• call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可

• apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递

• 如果第一个参数指定了 null 或者 undefined 则内部 this 指向window

bind

• 可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
• 它和 call、apply 最大的区别是:bind 不会调用

• bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递

  1. 在 bind 的同时,以参数列表的形式进行传递
  2. 在调用的时候,以参数列表的形式进行传递

• 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准
---- 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部

应用

var o = {
   0: 10,
   1: 20,
   2: 30,
   length: 3
 };
Array.prototype.push.call(o,50);
console.log(o);

 var arr = [1,3,4,6,8];
console.log(Math.max.apply(Math,arr));
console.log.apply(console,arr);

 // 想修改的是定时器的函数内部的 this
 var o = {
   name: "zs",
   age: 18,
   s: function () {
     setInterval(function () {
       console.log(this.age);
     }.bind(this),1000);
   }
 }
 // o.s();
 // 更改 事件函数中的 this
 document.onclick = function () {
   console.log(this);
 }.bind(o);

函数的其他成员

• arguments 实参集合
• arguments.callee 函数本身,arguments的一个属性
• fn.caller 函数的调用者,如果在全局调用,返回的调用者为 null。
• fn.length 形参的个数
• fn.name 函数的名称

function fn(a,b) {
  // 实际应用中,会在函数内部直接使用 一个 arguments 的关键字
   console.log(arguments);
   // console.log(arguments.callee);
   // 存储的是函数在调用时,传入的所有 实参 组成的一个类数组对象
   console.log(fn.arguments);
   // 函数的调用者,函数在哪个作用域调用,caller 就是谁,如果在全局调用,值就是 null
   console.log(fn.caller);
   // length 指的是形参的个数
   console.log(fn.length);
   // 函数的名字
   console.log(fn.name);
  }

高阶函数

函数可以作为参数

 // 1.函数作为另一个函数的参数
// 定义一个函数,吃饭的函数,吃完饭之后,可以做其他的事情,看电影、聊天、看书
  function eat(fn) {
   console.log("吃晚饭");
    // 接下来的要做的事情是不固定的
    fn();
  }
  eat(function () {
    console.log("看电影");
  });

函数可以作为返回值

// 2.函数作为一个函数的返回值
// 需求:通过同一段代码实现以下效果
 // 输出 100 + m
 // 输出 1000 + m
 // 输出 10000 + m
 function outer(n) {
   return function inner(m) {
     console.log(m + n);
   }
 }
 // 在外部执行 inner 函数
 //  100 + m
 var fun = outer(100);
 fun(3);
 fun(13);
 fun(23);
 var fun1 = outer(1000);
 fun1(3);

函数闭包

回顾作用域、作用域链、预解析

全局作用域
函数作用域
没有块级作用域
内层作用域可以访问外层作用域,反之不行

闭包

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。
在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

函数定义时天生就能记住自己生成的作用域环境和函数自己,将它们形成一个密闭的环境,这就是闭包。
不论函数以任何方式在任何地方进行调用,都会回到自己定义时的密闭环境进行执行。

// 体会闭包
// 将一个内部函数拿到父函数的外面,观察是否还能调用父函数内部的变量
 function outer() {
   // 形成闭包环境中的变量不是一成不变的,可以被更改
   var a = 10;
   function inner() {
     console.log(a++);
   }
   // 将inner 函数作为返回值
   return inner;
 }
 var inn = outer();
 inn();
 inn();

用途

可以在函数外部读取函数内部成员
让函数内成员始终存活在内存中

// 给数组中的每一项赋值一个 函数
var arr = [];
for (var i = 0 ; i <= 10 ; i++) {
  // 自调用函数
  (function (i) {
    arr[i] = function () {
      console.log(i);
    };
  })(i);
}
// 目的:调用数组对应的项,输出它的对应下标
arr[0]();
arr[1]();
arr[2]();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值