JavaScript 对象
JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。对象是拥有属性和方法的数据。
创建新对象有两种不同的方法:
1. 定义并创建对象的实例
2. 使用函数来定义对象,然后创建新的对象实例
创建直接的实例
- 本例创建名为 “person” 的对象,并为其添加了四个属性:
person=new Object();
person.firstname="Bill";
person.lastname="Gates";
person.age=56;
person.eyecolor="blue";
person.getAge = function(){
return this.age;
}
//访问对象的属性:objectName.propertyName
document.write(person.firstname);
//访问对象的方法:objectName.methodName()
document.write(person.getAge());
- 替代语法(使用对象 literals):
对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔:
var person={
firstname : "Bill",
lastname : "Gates",
age : 56,
getAge : function(){
return this.age;
}
};
使用对象构造器
本例使用函数来构造对象:
function Person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
function getAge()
{
return this.age;
}
}
Person.height =180; // 可以新加属性或方法
Person.prototype.weight =150; //可以对对象原型添加属性或方法
//有了对象构造器,就可以创建新的对象实例
var myFather=new Person("Bill","Gates",56,"blue");
myFather.getAge() //56
myFather.height //undefine,无法访问新加的属性
Person.height //180 可以对象自己访问
myFather.weight //150 原型属性和方法可以直接访问
myFather.height = 180; //可以给直接实例对象添加属性和方法,实例对象自己能访问
- 对象属性有两种寻址方式:
name=person.lastname;
name=person["lastname"];
可以通过将变量的值设置为 null 来清空变量:person=null;
JavaScript 是面向对象的语言,但 JavaScript 不使用类。JavaScript 基于 prototype,而不是基于类的。ES6新增了class关键字,但也是基于prototype。
- 声明变量类型
当您声明新变量时,可以使用关键词 “new” 来声明其类型:
var carname=new String;
var x= new Number;
var y= new Boolean;
var cars= new Array;
var person= new Object;
JavaScript 变量均为对象。当您声明一个变量时,就创建了一个新的对象。
- JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。如果您把值赋给尚未声明的变量,该变量将被自动作为全局变量声明。
carname="Volvo";
将声明一个全局变量 carname,即使它在函数内执行。
等于,“==”(等于),“=== 全等(值和类型)”
for/in - 循环遍历对象的属性
所有 JavaScript 数字均为 64 位,如果前缀为 0,则 JavaScript 会把数值常量解释为八进制数,如果前缀为 0 和 “x”,则解释为十六进制数。
日期对象也可用于比较两个日期。
//将当前日期与 2008 年 8 月 9 日做了比较
var myDate=new Date();
myDate.setFullYear(2008,8,9); //设置具体的日期
var today = new Date();
if (myDate>today)
{
alert("Today is before 9th August 2008");
}
else
{
alert("Today is after 9th August 2008");
}
对象引用
在 ECMAScript 中,不能访问对象的物理表示,只能访问对象的引用。每次创建对象,存储在变量中的都是该对象的引用,而不是对象本身。
对象废除
ECMAScript 拥有无用存储单元收集程序(garbage collection routine),意味着不必专门销毁对象来释放内存。当再没有对对象的引用时,称该对象被废除(dereference)了。每当函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其他不可预知的情况下,无用存储单元收集程序也会运行。
把对象的所有引用都设置为 null,可以强制性地废除对象。
对象作用域
作用域指的是变量的适用范围。
ECMAScript 中只存在一种作用域 - 公用作用域。ECMAScript 中的所有对象的所有属性和方法都是公用的。因此,定义自己的类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的!
关键字 this
this用在对象的方法中。关键字 this 总是指向调用该方法的对象,例如:
var oCar = new Object;
oCar.color = "red";
oCar.showColor = function() {
alert(this.color);
};
oCar.showColor();
在上面的代码中,关键字 this 用在对象的 showColor() 方法中。在此环境中,this 等于 oCar。
注意,引用对象的属性时,必须使用 this 关键字。例如,如果采用下面的代码,showColor() 方法不能运行:
function showColor() {
alert(color);
};
如果不用对象或 this 关键字引用变量,ECMAScript 就会把它看作局部变量或全局变量。然后该函数将查找名为 color 的局部或全局变量,但是不会找到。结果该函数将在警告中显示 “null”。
定义类或对象
工厂方式:
function createCar(sColor,iDoors,iMpg) {
var oTempCar = new Object;
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function() {
alert(this.color);
};
return oTempCar;
}
var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);
oCar1.showColor(); //输出 "red"
oCar2.showColor(); //输出 "blue"
用上面这种方式创建对象的方法,每次调用函数 createCar(),都要创建新函数 showColor(),意味着每个对象都有自己的 showColor() 版本。而事实上,每个对象都共享同一个函数。
有些开发者在工厂函数外定义对象的方法,然后通过属性指向该方法,从而避免这个问题:
function showColor() {
alert(this.color);
}
function createCar(sColor,iDoors,iMpg) {
var oTempCar = new Object;
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);
oCar1.showColor(); //输出 "red"
oCar2.showColor(); //输出 "blue"
在上面这段重写的代码中,在函数 createCar() 之前定义了函数 showColor()。在 createCar() 内部,赋予对象一个指向已经存在的 showColor() 函数的指针。从功能上讲,这样解决了重复创建函数对象的问题;但是从语义上讲,该函数不太像是对象的方法。
构造函数方式
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {
alert(this.color);
};
}
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
首先在构造函数内没有创建对象,而是使用 this 关键字。使用 new 运算符构造函数时,在执行第一行代码前先创建一个对象,只有用 this 才能访问该对象。然后可以直接赋予 this 属性。
就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂函数相似,也可以用外部函数重写构造函数。
原型方式
function Car() {
}
Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.drivers = new Array("Mike","John");
Car.prototype.showColor = function () {
console.log(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.showColor(); //输出 blue
oCar2.showColor(); //输出 blue
oCar2.color = "red"
console.log(oCar1.mpg) //输出 25
console.log(oCar1.color) //输出 blue
console.log(oCar2.color) //输出 red
oCar1.drivers.push("Bill");
console.log(oCar1.drivers); //输出 "Mike,John,Bill"
console.log(oCar2.drivers); //输出 "Mike,John,Bill"
首先定义构造函数(Car),其中无任何代码。接下来,通过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。调用 new Car() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Car 实例存放的都是指向 showColor() 函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面两种方式存在重复构造函数的问题。但是在prototype 属性指向的是对象,而不是函数时。函数共享不会造成问题,但对象却会被所有实例共享。如上面的drivers属性指向一个数组,oCar1实例更改这个数组后,oCar2也变化了。
动态原型方法
function Car(sColor, iDoors, iMpg) {
this.color = sColor; //this.color 代表的是当前对象
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike", "John");
//Car._initialized 这里代表的是是Car的类属性,所以所有实例都会有这个属性
if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function () {
console.log(this.color);
};
Car._initialized = true;
}
}
var oCar1 = new Car("blue", 4, 25);
var oCar2 = new Car("blue", 4, 25);
oCar1.showColor(); //输出 blue
oCar2.showColor(); //输出 blue
oCar2.color = "red"
console.log(oCar1.mpg) //输出 25
console.log(oCar1.color) //输出 blue
console.log(oCar2.color) //输出 red
oCar1.drivers.push("Bill");
console.log(oCar1.drivers); //输出 "Mike,John,Bill"
console.log(oCar2.drivers); //输出 "Mike,John"
动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。给对象添加方法时,会检查 typeof Car._initialized 是否等于 “undefined” ,这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把 Car._initialized 设置为 true。如果这个值定义了(它的值为 true 时,typeof 的值为 Boolean),那么就不再创建该方法。
ECMAScript 继承机制实现
继承,即创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。
对象冒充
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function () {
console.log(this.color);
};
}
function ClassB(sColor, sName) {
this.newMethod = ClassA;
this.newMethod(sColor); //调用ClassA的构造方法,会给ClassB增加ClassA的属性和方法
//删除newMethod属性,newMethod代表ClalassA对象,上面已经添加了ClassA的方法和属性了
delete this.newMethod;
this.name = sName; //添加自己的属性,方法
this.sayName = function () {
console.log(this.name);
};
}
var objA = new ClassA("blue");
var objB = new ClassB("red", "John");
objA.sayColor(); //输出 "blue"
objB.sayColor(); //输出 "red"
objB.sayName(); //输出 "John"
有趣的是,对象冒充可以支持多重继承。也就是说,一个类可以继承多个超类。但如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY后继承,则会用ClassY的同名属性覆盖ClassX的同名属性或方法。
call() 方法 和 apply() 方法
call() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。
apply() 方法有两个参数,用作 this 的对象和要传递给函数的参数的数组。
function ClassB(sColor, sName) {
//this.newMethod = ClassA;
//this.newMethod(color);
//delete this.newMethod;
ClassA.call(this, sColor); //ClassA.apply(this, new Array(sColor));
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
原型链(prototype chaining)
继承这种形式在 ECMAScript 中原本是用于原型链的,prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
function ClassA() {
this.num = 111, //添加自身对象属性
this.sayNum = function(){ //添加自身对象方法
console.log(this.num)
}
}
ClassA.prototype.color = "prototype.color blue"; //添加ClassA原型属性
ClassA.prototype.sayColor = function () { //添加ClassA原型方法
console.log(this.color);
};
function ClassB() { }
//给ClassB 添加原型对象ClassA实例,这时ClassB拥有ClassA的所有属性,包括原型属性
//默认所有类的原型对象是Object, 这里变成ClassA()实例
ClassB.prototype = new ClassA();
//下面相当于给上面的ClassA()实例添加新的属性和方法
ClassB.prototype.name = "prototype.name John";
ClassB.prototype.sayName = function () {
console.log(this.name);
};
var objA = new ClassA();
var objB = new ClassB();
objA.color = "yellow"; //这里给objA实例对象添加一个color属性
objA.sayNum() //输出 111
// objB.name = "John";
objA.sayColor(); //输出 yellow, 这里不会输出"prototype.color blue",
//当有自身属性和原型属性同名时,输出自身属性,当找不到自身属性才找原型属性
objB.sayColor(); //输出 prototype.color blue
objB.sayName(); //输出 prototype.name John
objB.sayNum() //输出 111
alert(objB instanceof ClassA); //输出 "true"
alert(objB instanceof ClassB); //输出 "true"
原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
Window 对象
所有浏览器都支持 window 对象。它表示浏览器窗口。
所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。
全局变量是 window 对象的属性。
全局函数是 window 对象的方法。
Window Location
window.location 对象在编写时可不使用 window 这个前缀。
一些例子:
location.hostname 返回 web 主机的域名
location.pathname 返回当前页面的路径和文件名
location.port 返回 web 主机的端口 (80 或 443)
location.protocol 返回所使用的 web 协议(http:// 或 https://)
location.href 属性返回当前页面的 URL
location.pathname 属性返回 URL 的路径名
location.assign() 方法加载新的文档URLwindow.history
window.history对象包含浏览器的历史。
history.back() - 与在浏览器点击后退按钮相同
history.forward() - 与在浏览器中点击按钮向前相同
JavaScript 计时事件
setTimeout() : 未来的某时执行代码
var t=setTimeout("javascript语句",毫秒)
clearTimeout() : 取消setTimeout()
clearTimeout(setTimeout_variable)
setInterval() : 按照指定的周期(以毫秒计)来调用函数或计算表达式。
clearInterval() : 取消周期性执行的值
var t = setInterval(code,millisec)
clearInterval(t)
完
更多精彩Android技术可以关注我们的微信公众号,扫一扫下方的二维码或搜索关注公共号:
Android老鸟