eyasliu / blog

博客文章
179 stars 13 forks source link

JavaScript基础知识与面向对象编程 #9

Open eyasliu opened 8 years ago

eyasliu commented 8 years ago

目标:熟练掌握JavaScript基础知识与面向对象概念

大纲

JavaScript的语法借鉴C语言语法,与php基本一致

一共5种基本数据类型

使用 typeof 可以查看数据类型

Undefined && Null

Undefined 与 Null 类型都是只有一个值

undefined 表示变量未定义,或者定义了但是未赋值 null 表示空对象指针,不指向任何对象,本质上他是Object类型

Boolean

Boolean 类型共两个值 truefalse,表示真和假

基本类型转换时,会将以下值转换为false

其他都会转为 true

Number

Number() 可以把任何值转换为数值,parseInt()parseFloat()将字符串转换为数值。

转换规则

引用类型是一种数据结构,用于将数据和功能组织在一起。

Object 类型

创建一个Object

// 使用 new
var person = new Object();
person.name = 'Eyas'

// 使用字面量
var person = {
  name: 'Eyas'
}

以面向对象概念理解的话,Object类型是所有引用类型的基类,Array,Function,包装类型等都属于Object的子类

Array 类型

创建Array

// 使用new
var persons = new Array

// 使用字面量
var persons = []

栈方法

push : 将元素添加到数组末尾,返回数组长度 pop: 返回最后一项元素并删除

队列方法

shift: 返回第一项并删除 unshift: 将元素添加带数组第一项,返回数组长度

迭代方法

定义

// 函数声明
function say(str){}

// 函数表达式
var say = function(str){}

注意事项

为了便于操作基本类型数据,每当读取一个基本类型值的时候,后台会创建一个对应的基本包装类型的对象,让我们能够调用一些方法来操作这些数据

执行环境定义了变量或函数有权访问的其他数据,决定了他们的各自行为。每个执行环境都有一个与之关联的变量对象,环境中的所有变量和函数都保存在这个变量中,但是我们无法访问这个变量,在解析器执行时会在后台使用

作用域链

每个函数都有自己的执行环境,当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问

var Name = 'Tenmic';
var Version = '1.0.0'

function appName(){
  var fullName = function(name, version){
    return name + ' V' + version
  }

  return fullName(Name, Version)
}

appName() // Tenmic V1.0.0

闭包

闭包是指有权访问另一个函数作用域中的变量的函数,创建方式就是在一个函数内部创建另一个函数

var addNum = function(num){
  return function(num2){
    return num + num2
  }
}

var addOne = addNum(1);
var addTen = addNum(10);

addOne(3)  // 4
addTen(15) // 25

this

this对象是在运行时基于函数的作用域绑定的,在全局函数中,this等于window,当函数被某个对象的方法调用时,this等于那个对象。在编写闭包中,this依情况而定

function say(){
  // this === window
}

// jQuery 
$('body').show()  // show 里面的this指向 $('body')

var obj = {
  name: 'Tenmic',
  getNameFun: function(){
    // this == obj
    return this.name
  }
}

绑定this

在运行中,this变量可以显式的绑定

// 工厂模式
function createPerson(name, age){
  var o = {
    name: name,
    age: age
  }

  return o;
}
var person = createPerson('Eyas', 24)

构造函数模式

// 构造函数
function Person(name, age){
  this.name = name;
  this.age = age;
  this.getInfo = function(){
    return this.name + '-' + this.age
  }
}

var peroson = new Person('Eyas', 24)

new 关键字的执行过程

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(this 指向新对象)
  3. 执行代码
  4. 返回新对象

构造函数就是一个普通的函数,与一般函数没有什么不同,任何函数都可以用 new 来调用。

缺点 每个函数都要创建一次

原型模式

我们创建的每个函数都有一个prototype,这是一个指向一个对象的指针,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。

prototype 是通过调用构造函数而创建的那个对象实例的原型对象

function Person(){}

Person.prototype.name = 'Eyas';
Person.prototype.age = 24;
Person.prototype.getInfo = function(){
  return this.name + '-' + this.age
}

var person = new Person()

person.name // Eyas
person.getInfo() // Eyas-24
理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。所有原型对象自动获得一个constructor属性,constructor指向函数本身

function hello(){}
hello.prototype
hello.prototype.constructor === hello  // true

在查找对象属性时,首先获取对象内部属性,如果获取不到,则沿着原型链逐步往上查找,最终仍未找到则返回undefined

继承

JavaScript是基于原型链的继承。利用原型让一个引用类型继承另一个引用类型的属性和方法。

原型继承

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。如果我们手动的让原型对象等于另一个原型的实例,此时的原型对象将包含另一个原型的实例。如此层层递进,构成实例与原型的链条,实现了继承

function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  }
}

function Student(){}
Student.prototype = new Peroson()

var student = new Student
student.getName()  // getName 来自于 Person

借用构造函数继承

很明显的,上述原型继承无法控制Person的传入参数,我们使用借用构造函数方式继承

function Person(name, age){
  this.name = name;
  this.age = age;
}
function Student(){
  Person.apply(this, arguments);
}
Student.prototype = new Person

这种方式,虽然解决了参数传递,但是依然解决得不彻底,参数的限制太大了

组合式继承

function Person(name){
  this.name = name;
  this.age = age;
}
function Student(name, age){
  Person.call(this, name);
  this.age = age
}
Student.prototype = new Person

这种继承方式综合了上述两者继承方式,可以近乎完美实现继承