阅读《JavaScript设计模式》第二章心得

面向对象编程

面向对象编程就是将你的需求抽象成一个对象。然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为类。面向对象编程思想其中的一个特点就是封装。

1、私有属性、私有方法、特权方法、对象公有属性、对象公有方法、构造器和类静态公有属性、类静态公有方法、公有属性、公有方法

var Book = function (id,name,price){
  //私有属性
  var num = 1;
  //私有方法
  function checkId(){};
  //特权方法
  this.getName = function(){};
  this.getPrice = function(){};
  this.setName = function(){};
  this.setPrice = function(){};
  //对象公有属性
  this.id=id;
  //对象公有方法
  this.copy=function(){};
  //构造器
  this.setName(name);
  this.setPrice(price);
};
//类静态公有属性(对象不能访问)
Book.isChinese = true;
//类静态公有方法(对象不能访问)
Book.resetTime = function(){
  console.log('new Tiem')
};
Book.prototype = {
  //公有属性
  isJSBook : false;
  display : function(){}
}
测试代码如下
var b = new Book(11,22,33);
console.log(b.num);        //undefined
console.log(b.isJSBook);     //false
console.log(b.id);                    //11
console.log(b.isChinese);    //undefined
console.log(Book.isChinese);     //true
Book.resetTime();                         //new Tiem

2、闭包实现

闭包是有权访问另一个函数作用域中变量的函数,即在一个函数中创建另一个函数。

new关键字的作用可以看作是对当前对象的this不停的赋值。如果实例化的时候不写new就相当于在全局作用域中执行了实例化函数,那么实例化就会出现问题

由于小程序中没有window对象,所以在全局实例化不带new时候就会报错,但是网页中就不会报错。

解决忘记写new的方法是使用安全模式,代码如下:

var Book = function (title, time, type){

  //判断执行过程中this是否是当前这个对象(如果是说明是用new创建的)

  // 判断 foo 是否是 Foo 类的实例
  //function Foo(){}
  //var foo = new Foo();
  //console.log(foo instanceof Foo)//true

 

  if(this instanceof Book){  //这里的instance是指this指向的对象是否是Book的实例,而不是指this是否指向Book

    this.title = title;

    this.time = time;

    this.type = type;  

  }else{

    return new Book(title,time,type);

  }

}

3、继承

 new之后的变量是没有prototype的 ,只有__proto__属性,也就是实例化之后就没有prototype原型了,但是prototype是等于实例化之后的__proto__的。实例化之后的变量的__proto__中的constructor是等于实例化之前的构造函数的。

但是在打印实例化之后的构造函数时可以这样:

console.log(a.__proto__.constructor)

也可以这样

console.log(a.constructor)

打印出来的都是实例化之前的构造函数,因为如果查找一个属性在变量中找不到就会去变量的隐藏属性__proto__中去找。

查找是没有什么 区别,但是添加方法的作用域不同

如果写a.__proto__.b,那么这个b方法将在__proto__中执行,this指向的是a.__proto__的作用域

如果写a.b,那么这个b方法将在a中执行,this指向的是a的作用域

JavaScript中除了数字、字符串、布尔值、null和undefined之外的就是对象了,所以数组是对象,对象之间相互赋值只是更换的内存地址,内存地址所指向的值都是一样的,是会相互影响的。

详情请戳这      JavaScript中值类型和引用类型的区别 

下面放寄生组合式继承实例:

 1 function inheritObject(o){
 2   function F(){}
 3   F.prototype = o;
 4   return new F();
 5 }
 6 
 7 function inheritPrototype(subClass,superClass){
 8   var p = inheritObject(superClass.prototype);
 9   console.log(p)
10   console.log(superClass)
11   p.constructor = subClass;
12   subClass.prototype = p
13 }
14 
15 function SuperClass(name){
16   this.name = name;
17   this.colors = ["red","blue","green"];
18 }
19 SuperClass.prototype.getName = function(){
20   console.log(this.name)
21 }
22 function SubClass(name,time){
23   SuperClass.call(this,name)
24   this.time = time;
25 }
26 
27 
28 inheritPrototype(SubClass,SuperClass);
29 SubClass.prototype.getTime = function(){
30   console.log(this.time)
31 }
32 var instance1 = new SubClass("js book",2014)
33 var instance2 = new SubClass("css book",2013)
34 
35 instance1.colors.push("black")
36 console.log(instance1.colors)
37 console.log(instance2.colors)
38 instance2.getName();
39 instance2.getTime();

 4、多继承

 关于js中的for  in和in用法

 for in 用法可以遍历一个对象中的属性或者方法,可以像遍历数组一样简单。

关于js中arguments用法

 arguments可以用来遍历那些传参数量不确定的函数,不用写形参就可以获取到实参的值和数量。该对象还封装了callee方法,该方法可用来实现递归。

 

 1 Object.prototype.mix = function () {
 2   var i = 0,
 3     len = arguments.length
 4   var arg;
 5   for (; i < len; i++) {
 6     arg = arguments[i];
 7     for (var p in arg) {
 8       this[p] = arg[p]
 9     }
10   }
11 }
12 
13 var book1 = {
14   name: "javascript设计模式",
15   alike: ['css', 'html', "javascript"]
16 }
17 var book2 = {
18   color: "blue"
19 }
20 var otherBook1 = {
21   aa: "11"
22 }
23 var otherBook2 = {
24   bb:"22"
25 }
26 otherBook1.mix(book1, book2)
27 otherBook1.alike.push("ajax")
28 console.log(otherBook1)
29 
30 otherBook2.mix(book1, book2)
31 console.log(otherBook2)

这里可以看到引用类型属性还是共用的。

浅复制中的复制对象的方法对象实质是一种指向引用,所以我们在深复制中要把该对象中的引用类型属性细化成值类型拷贝到目标对象中。

这是本章最后的一个问题,如何实现深复制。

然后我又回头看看之前写的单继承怎么实现的引用类型属性不共用的(之前还真的没有仔细看过如何引用类型属性不共用的),然后发现原来在构造函数继承的地方就已经实现了应用类型属性不共用的方法。

使用call改变函数作用的环境就可以实现。(这让我想到之前每次调用别的函数时都使用call,现在才知道call改变函数作用环境的目的不仅仅是改变this的指向,也可以实现应用类型属性不共用,从而达到真正复制该方法的作用)

但是这里并没有用到构造函数的方法。

 1 Object.prototype.mix = function () {
 2   var i = 0,
 3     len = arguments.length
 4   var arg;
 5   for (; i < len; i++) {
 6     arg = arguments[i];
 7     for (var p in arg) {
 8       if (typeof arg[p] == 'object') {
 9         var str = JSON.stringify(arg[p])
10         this[p] = JSON.parse(str);
11       } else {
12         this[p] = arg[p]
13       }
14       console.log(typeof arg[p])
15 
16     }
17   }
18 }
19 
20 var book1 = {
21   name: "javascript设计模式",
22   alike: ['css', 'html', "javascript"]
23 }
24 var book2 = {
25   color: "blue"
26 }
27 var otherBook1 = {
28   aa: "11"
29 }
30 var otherBook2 = {
31   bb: "22"
32 }
33 otherBook1.mix(book1, book2)
34 otherBook1.alike.push("ajax")
35 console.log(otherBook1)
36 
37 otherBook2.mix(book1, book2)
38 console.log(otherBook2)

 这样就实现了多继承的深复制

5、多态

 这里的多态就是同一种方法多中调用方式,实质就是上面arguments的用法,根据传参的数量不同而调用的方法不同。

 

 本人处于学习阶段,如有误欢迎大家的指出。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/Juaoie/p/9190905.html