Javascript学习笔记二

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() 方法加载新的文档URL

  • window.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老鸟
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值