JS对象(三)

call和apply能指定函数的上下文

function sum() {
alert(this.chinese + this.math + this.english);
}
var xiaoming = {
chinese: 80,
math: 95,
english: 93
};
sum. call(xiaoming);
sum. apply( xiaoming);
函数.call(上下文);
函数.apply(上下文);

call和apply的区别

function sum(b1, b2) {
alert(this.c + this.m + this.e + b1 + b2);
}
sum.call(xiaoming, 5, 3);//call要用逗号罗列参数
sum.apply(xiaoming, [5, 3]);//apply要把参数写到数组中

到底使用call还是apply?

function fun1() {
fun2.apply(this, arguments);
}
function fun2(a, b) {
alert(a + b);
}
fun1(33, 44);

上下文规则总结

规则 上下文
对象.函数() 对象
函数() window
数组下标 数组
IIFE window
定时器 window
DOM事件处理函数 绑定DOM的元素
call和apply 任意指定

用new操作符调用函数

  • 现在,我们学习一种新的函数调用方式:
    new 函数()
  • 你可能知道new操作符和“面向对象”息息相关,但是现在,我们先不探讨它的“面向对象”意义,而是先把用new调用函数的执行步骤和它上下文弄清楚

用new操作符调用函数

  • JS规定,使用new操作符调用函数会进行“四步走”:
    1)函数体内会自动创建出一个空白对象
    2)函数的上下文(this)会指向这个对象
    3)函数体内的语句会执行
    4)函数会自动返回上下文对象,即使函数没有return语句
function fun() {
this.a = 3;
this.b = 5;
}
var obj = new fun();
console.log(obj);
  • 第1步:函数体内会自动创建出一个空白对象
    第2步:函数的上下文(this)会指向这个对象
    第3步:执行函数体中的语句
    第4步:函数会自动返回上下文对象,即使函数没有return语句

什么是构造函数

function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var xiaoming = new People('小明', 12, '男');
var xiaohong = new People('小红', 10, '女');
var xiaogang = new People('小刚', 13, '男');
  • 用new调用一个函数,这个函数就被称为“构造函数”,任何函数都可以是构造函数,只需要用new调用它
    顾名思义,构造函数用来“构造新对象”,它内部的语句将为新对象添加若干属性和方法,完成对象的初始化
    构造函数必须用new关键字调用,否则不能正常工作,正因如此,开发者约定构造函数命名时首字母要大写

错误的:一个函数名称首字母大写了,它就是构造函数

  • 一定要记住:一个函数是不是构造函数,要看它是否用new调用,而至于名称首字母大写,完全是开发者的习惯约定

如果不用new调用构造函数

function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
People('小明', 12, '男');
People('小红', 10, '女');
People('小刚', 13, '男');

构造函数中的this不是函数本身

类好比是“蓝图”

  • 如同“蓝图”一样,类只描述对象会拥有哪些属性和方法,但是并不具体指明属性的值

  • “狗”是类,“史努比”是实例、“小白”是实例

  • Java、C++等是“面向对象”(object-oriented)语言
    JavaScript是“基于对象”(object-based)语言
    JavaScript中的构造函数可以类比于OO语言中的“类”,写法的确类似,但和真正OO语言还是有本质不同,在后续课程还将看见JS和其他OO语言完全不同的、特有的原型特性

什么是prototype

  • 任何函数都有prototype属性,prototype是英语“原型”的意思
  • prototype属性值是个对象,它默认拥constructor属性指回函数
  • 普通函数来说的prototype属性没有任何用处,而构造函数的prototype属性非常有用
  • 构造函数的prototype属性是它的实例的原型

原型链查找

  • JavaScript规定:实例可以打点访问它的原型的属性和方法,这被称为“原型链查找”
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
People.prototype.nationality = '中国';
var xiaoming = new People('小明', 12, '男');
console.log(xiaoming.nationality);
  • hasOwnProperty方法可以检查对象是否真正“自己拥有”某属性或者方法
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('age'); // true
xiaoming.hasOwnProperty('sex'); // true
xiaoming.hasOwnProperty('nationality'); // false
  • in运算符只能检查某个属性或方法是否可以被对象访问,不能检查是否是自己的属性或方法
'name' in xiaoming // true
'age' in xiaoming // true
'sex' in xiaoming // true
'nationality' in xiaoming // true
  • 把方法直接添加到实例身上的缺点:每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费
  • 解决办法:将方法写到prototype上
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
People.prototype.sayHello = function () {
console.log('我是' + this.name);
};
People.prototype.sleep = function () {
console.log(this.name + '开始睡觉,zzzz');
};

面向对象到底是什么

  • 面向对象的本质:定义不同的类,让类的实例工作
  • 面向对象的优点:程序编写更清晰、代码结构更严密、使代码更健壮更利于维护
  • 面向对象经常用到的场合:需要封装和复用性的场合(组件思维)

页面上做一个红绿灯,点击红灯就变黄,点击黄灯就变绿,点击绿灯就变回红灯.如果页面上有100个这样的红绿灯呢?使用面向对象编程,就能以“组件化”的思维解决大量红绿灯互相冲突的问题

  • 面向对象编程,最重要的就是编写类
    TrafficLight类
  • 请思考,红绿灯TrafficLight类有哪些属性和方法呢?
  • 属性:自己的当前颜色color、自己的DOM元素dom
  • 方法:初始化init()、切换颜色changeColor()、绑定事件bindEvent()
    Ball类的属性
属性名 意义
x 圆心坐标x
y 圆心坐标y
r 圆半径
opacity 透明度
color 颜色
dom DOM元素

Ball类的方法

属性名 意义
init 初始化
update 更新

如何实现多个小球动画
小球实例 小球实例 小球实例 小球实例

  • 把每个小球实例都放到同一个数组中
  • 只需要使用1个定时器,在每一帧遍历每个小球,调用它们的update方法

包装类

什么是包装类

  • Number()、String()和Boolean()分别是数字、字符串、布尔值的“包装类”
  • 很多编程语言都有“包装类”的设计,包装类的目的就是为了让基本类型值可以从它们的构造函数的prototype上获得方法
  • 请看下面的程序: a、b、c是基本类型值么?它们和普通的数字、字符串、布尔值有什么区别么?
var a = new Number(123);
var b = new String('慕课网');
var c = new Boolean(true);
  • Number()、String()和Boolean()的实例都是object类型,它们的PrimitiveValue属性存储它们的本身值

  • new出来的基本类型值可以正常参与运算

  • 包装类的目的就是为了让基本类型值可以从它们的构造函数的prototype上获得方法

  • 幂和开方:Math.pow()、Math.sqrt()

  • 向上取整和向下取整:Math.ceil()、Math.floor()

  • Math.round()可以将一个数字四舍五入为整数

  • Math.max()可以得到参数列表的最大值

  • Math.min()可以得到参数列表的最小值

  • Math.max()要求参数必须是“罗列出来”,而不能是数组

  • 还记得apply方法么?它可以指定函数的上下文,并且以数组的形式传入“零散值”当做函数的参数

  • Math.random()可以得到0~1之间的小数

  • 为了得到[a, b]区间内的整数,可以使用这个公式:
    Date()日期对象

  • 使用new Date()即可得到当前时间的日期对象,它是object类型值

  • 使用new Date(2020, 11, 1)即可得到指定日期的日期对象,注意第二个参数表示月份,从0开始算,11表示12月

  • 也可以是new Date(‘2020-12-01’)这样的写法

日期对象的常见的方法

方法 功能
getDate() 得到日期1~31
getDay() 得到星期0~6
getMonth() 得到月份0~11
getFullYear() 得到年份
getHours() 得到小时数0~23
getMinutes() 得到分钟数0~59
getSeconds() 得到秒数0~59

时间戳

  • 时间戳表示1970年1月1日零点整距离某时刻的毫秒数
  • 通过getTime()方法或者Date.parse()函数可以将日期对象变为时间戳
  • 通过new Date(时间戳)的写法,可以将时间戳变为日期对象
上一篇:装饰模式


下一篇:java 类与对象的创建