码迷,mamicode.com
首页 > 编程语言 > 详细

《Javascript面向对象精要》笔记

时间:2016-04-16 22:47:17      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

刚读过《Javascript面向对象精要》这本书,在现有的知识体系里面有一些新鲜的认识,记录一下。
 

原始类型和引用类型

Javascript存在两种类型:原始类型和引用类型。原始类型包括String、Number、Boolean、Null、Undefined,引用类型保存对象,其本质是对象所在内存位置的引用。
原始类型的赋值或者给函数传参,实际上都是传递原始类型值的拷贝;
引用类型则是引用的拷贝。修改其中一个引用的话,其他引用也会受到影响。如果对象中的某个属性也是对象,在对象拷贝时就会引入深拷贝和浅拷贝的区别。
var a = {"name": "Hello"};
var b = a;

a.name; // "Hello"

b.name = "World";

a.name; // "World"

关于正则表达式的字面形式

     Javascript允许使用字面形式定义正则表达式,与RegExp构造函数的区别在于,构造函数的参数涉及到转义。
var reg = /\d+/g;

//等价于

var reg = new RegExp("\\d+", "g");

关于原始封装类型

     String、Number和Boolean有原始封装类型,读取这些类型的值时,自动创建临时的原始封装类型的对象,使用后立即删除。
   引用一个较为诡异的问题:
var name = "Nicholas";
name.last = "Zakas";

console.log(name.last); // undefined

     这段代码实际的执行过程如下:

var name = "Nicholas";
var temp = new String(name);
temp.last = "Zakas";
temp = null;

var temp = new String(name);
console.log(temp.last); // undefined
temp = null;

   所以在获取时,读取的都是临时变量,用后即焚。

 

关于函数重载

     面向对象编程的一个重要特性就是函数重载。Javascript中的函数没有原型的概念,就更提不到重载。
function showMessage(message) {
  console.log("Parameter: " + message);    
}

function showMessage() {
  console.log("No Parameter");
}

showMessage("Hello"); // "No Parameter"

    利用原始封装类型的概念帮助理解执行过程如下:

var showMessage = new Function("message", "console.log(\"Parameter: \" + message)");
showMessage = new Function("console.log(\"No Parameter\")");

showMessage("Hello"); // "No Parameter"

    重载的本质在于参数列表的不同,可以通过判断参数的个数、类型等执行不同的处理过程,实现重载。

     1)arguments对象——类似数组类型的对象,可循环遍历,可检查其length属性;
  注意:arguments其实不是数组类型的对象,Array.isArray(arguments)永远返回false;使用arguments的弊端在于如果代码复杂或很长,容易漏掉代码中对于参数的处理。
     2)鉴于以上提到的弊端,实际上检查命名参数是否未定义,或通过typeof/instanceof检查其类型的方法更常见
 

关于继承

     Javascript通过原型链实现继承,每个对象都有一个prototype对象作为其原型对象,继承其属性和方法。for-in循环会遍历继承而来的属性,可通过hasOwnProperty检查是否为自有属性。
     修改原型对象时,会导致所有的对象实例都受到影响,并且影响是实时的;通过构造函数继承的办法,可以实现继承自同一原型对象,但构造过程不同的对象实例的初始化。
function Rectangle(length, width) {
  this.length = length;
  this.width = width;
}

Rectangle.prototype.getArea = function() {
  return this.length * this.width;
}

Rectangle.prototype.toString = function() {
  return "[Rectangle " + this.length + " x " + this.width + "]";
}

function Square(size) {
  this.length = size;
  this.width = size;
}

Square.prototype = Object.create(Rectangle.prototype, {
  constructor: {
    configurable: true,
    enumerable: true,
    value: Square,
    writable: true
  }
};

Square.prototype.toString = function() {
  return "[Square " + this.length + " x " + this.width + "]";
}

var rect = new Rectangle(5, 10);
var square = new Square(6);

console.log(rect.getArea()); // 50
console.log(square.getArea()); // 36

console.log(rect.toString()); // "[Rectangle 5x10]"
console.log(square.toString()); // "[Square 6x6]"

console.log(rect instanceof Rectangle); // true
console.log(rect instanceof Object); // true

console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
console.log(square instanceof Object); // true

私有成员

     Javascript对象的属性都是public的,通过闭包实现属性的私有化。
     1)模块模式
   person对象被赋值为一个立即执行的函数,该函数返回一个包含name属性和getAge、growOlder方法的对象。由于Javascript的函数作用域限制,函数内的变量是无法被函数以外的上下文访问的,这就保证了只有函数内部可以访问age变量。实际上就是利用了闭包。
var person = (function(){
  var age = 25;

  return {
    name: "Nicholas",
    getAge: function() {
      return age;
    },
    growOlder: function() {
      age++;
    }
  };
}());

console.log(person.name); // "Nicholas"
console.log(person.getAge()); // 25

person.age = 100;
console.log(person.getAge()); // 25

person.growOlder();
console.log(person.getAge()); // 26
     2)构造函数的私有成员
function Person(name){
  var age = 25;

  this.name = name;
  this.getAge = function() {
    return age;
  };
  this.growOlder = function() {
    age++;
  };
}

var person = new Person("Nicholas");

console.log(person.name); // "Nicholas"
console.log(person.getAge()); // 25

person.age = 100;
console.log(person.getAge()); // 25

person.growOlder();
console.log(person.getAge()); // 26
     3)以上二者结合
     构造函数的私有成员示例中,虽然实现了成员的私有化,但是getAge和growOlder方法被对象实例独有,如果需要所有实例共享私有数据,可通过结合模块模式和构造函数来实现。
var Person = (function(){
  var age = 25;

  function realPerson(name) {
    this.name = name;
  }

  realPerson.prototype.getAge = function() {
    return age;
  }

  realPerson.prototype.growOlder = function() {
    age++;
  }

  return realPerson;
}());

var Nicholas = new Person("Nicholas");
var Greg      = new Person("Greg");

console.log(Nicholas.name); // "Nicholas"
console.log(Nicholas.getAge()); // 25

console.log(Greg.name); // "Nicholas"
console.log(Greg.getAge()); // 25

Nicholas.growOlder();
console.log(Nicholas.getAge()); // 26
console.log(Greg.getAge()); // 26

作用域安全的构造函数

     这个问题的出现来自于创建对象实例时,很容易漏写new关键字。构造函数也是函数,所以可以不用new操作符直接调用它们来改变this的值。在非严格模式下,this被强制指向全局对象;在严格模式下,构造函数抛出错误。解决这个问题,可在构造函数中进行检查。

function Person(name) {
  if(this instanceof Person) {
    this.name = name;
  }
  else {
    return new Person(name);
  }
}

《Javascript面向对象精要》笔记

标签:

原文地址:http://www.cnblogs.com/SheldonWr/p/5399327.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!