• Javascript高级程序设计3笔记


     

    完全是笔记,99.9%摘录自高程3,方便学习复习。

    • 对象认识
    • “类”
    • 原型
    • 继承
     

    一、对象认识

    最原始的创建对象方式:

     
    1 var person = new Object(); //new一个Object对象 person
    2 person.name = "hank"; //给person添加属性name,初值为hank
    3 person.age = 28; //..
    4 person.job = "eat"; //...
    5 person.sayName = function(){ //给person添加方法sayName
    6     alert(this.name);
    7 }

    看上去有点笨重,后来就流行字面量了:

    1 var person{
    2     name : "hank",
    3     age : 28,
    4     job : "eat",
    5     sayName : function(){
    6         alert(this.name);
    7     }
    8 }    

     

    以上两种的缺点:如果创建很多对象,就会产生大量的重复代码。所以,开始有“类”的出现了。一个类,想要多少实例,自己new。

    二、类(意义上的)

    1.工厂模式

    ECMAScript无法创建类。那么,就用一个函数将第一种封装起来。如此这般,可通过调用ceartPerson来创建多个相似对象。但是无法识别对象类型.

     1 function creatPerson(name,age,job){
     2     var o = new Object(); //new
     3     o.name = name; //添加属性
     4     o.age = age; //..
     5     o.job = job; //..
     6     o.sayName = function(){ //添加方法
     7         alert(this.name);
     8     }
     9     return o; //将new好的对象返回
    10 }

    2.构造函数模式

     1 function Person(name, age, job){
     2     //没有new对象
     3     this.name = name; //属性和方法赋值给this对象
     4     this.age = age;
     5     this.job = job;
     6     this.sayName = function(){
     7         alert(this.name);
     8     };
     9     //没有return
    10 }
    11 var person1 = new Person("Nicholas", 29, "Software Engineer");
    12 var person2 = new Person("Greg", 27, "Doctor");    

     

    person1和person2分别保存着Person的一个不同的实例。都有一个constructor(构造函数)属性,指向Person“person1.constructor == Person”。如此这般之后,就能instanceof出构造函数(对象类型)而不都是Object了。 
    -调用方式

     1 // 当作构造函数使用
     2 var person = new Person("Nicholas", 29, "Software Engineer");
     3 person.sayName(); //"Nicholas"
     4 // 作为普通函数调用
     5 Person("Greg", 27, "Doctor"); // 添加到 window
     6 window.sayName(); //"Greg"
     7 // 在另一个对象的作用域中调用
     8 var o = new Object();
     9 Person.call(o, "Kristen", 25, "Nurse");// 添加到 o
    10 o.sayName(); //"Kristen"

     

    缺点:每个方法都要在每个实例上重新创建一遍。不同实例上的同名函数是不相等的,所以alert(person1.sayName == person2.sayName); //false。通过把函数定义转移到构造函数外部来解决这个问题

     1 function Person(name, age, job){
     2     this.name = name;
     3     this.age = age;
     4     this.job = job;
     5     this.sayName = sayName;
     6 }
     7 function sayName(){
     8     alert(this.name);
     9 }
    10 var person1 = new Person("Nicholas", 29, "Software Engineer");
    11 var person2 = new Person("Greg", 27, "Doctor");
    12 alert(person1.sayName == person2.sayName); //true

     

    可是新问题又来了:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。而更让人无法接受的是:如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了。好在,这些问题可以通过使用原型模式来解决。

    三、原型

    每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象。这个对象使得所有实例共享属性和方法。

     1 function Person(){
     2 }
     3 Person.prototype.name = "Nicholas";
     4 Person.prototype.age = 29;
     5 Person.prototype.job = "Software Engineer";
     6 Person.prototype.sayName = function(){
     7     alert(this.name);
     8 };
     9 var person1 = new Person();
    10 person1.sayName(); //"Nicholas"
    11 var person2 = new Person();
    12 person2.sayName(); //"Nicholas"
    13 alert(person1.sayName == person2.sayName); //true

     

    和构造函数模式不同的是,实例共享属性方法。实例访问的实例和方法都是同一个。 
    此处输入图片的描述

    查找对象属性:在对象实体中找,找不到就到原型对象中找。能访问,但是不能修改。即,实例中添加同名属性后,只是在该实例中存在。

     
     1 function Person(){
     2 }
     3 Person.prototype.name = "Nicholas";
     4 Person.prototype.age = 29;
     5 Person.prototype.job = "Software Engineer";
     6 Person.prototype.sayName = function(){
     7     alert(this.name);
     8 };
     9 var person1 = new Person();
    10 var person2 = new Person();
    11 person1.name = "Greg";
    12 alert(person1.name); //"Greg" ——来自实例
    13 alert(person2.name); //"Nicholas" ——来自原型
    14 delete person1.name;
    15 alert(person1.name); //"Nicholas"——来自原型

     

    使用 hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是存在于原型中.只在给定属性存在于对象实例中时,才会返回 true。 
    in的话,是分不清在属性存在于原型还是实例中的。因此只要 in 操作符返回 true 而 hasOwnProperty() 返回 false,就可以确定属性是原型中的属性,下面封装一个方法:

    1 function hasPrototypeProperty(object, name){
    2     //属性是原型中的属性
    3     return !object.hasOwnProperty(name) && (name in object);
    4 }

     

    用字面量写法,让原型模式更简洁

     1 function Person(){
     2 }
     3 Person.prototype = {
     4     name : "Nicholas",
     5     age : 29,
     6     job: "Software Engineer",
     7     sayName : function () {
     8         alert(this.name);
     9     }
    10 };

     

    这样写后,constructor就不会再指向Person,因为重写了Person.prototype。需要重新指定constructor的指向。

     1 function Person(){
     2 }
     3 Person.prototype = {
     4     constructor : Person,
     5     name : "Nicholas",
     6     age : 29,
     7     job: "Software Engineer",
     8     sayName : function () {
     9         alert(this.name);
    10     }
    11 };

     

    原型动态性,实例与原型之间的链接是一个指针,而非一个副本。所以,原型上的任何修改都能立即在实例上表现出来,即使是实例创建在先。

    1 var friend = new Person();
    2 Person.prototype.sayHi = function(){
    3     alert("hi");
    4 };
    5 friend.sayHi(); //"hi" (没有问题!)

     

    但是如果是重写整个原型对象(字面量形式),那就不一样了(先实例后原型)

     1 function Person(){
     2 }
     3 var friend = new Person();
     4 Person.prototype = {
     5     constructor: Person,
     6     name : "Nicholas",
     7     age : 29,
     8     job : "Software Engineer",
     9     sayName : function () {
    10         alert(this.name);
    11     }
    12 };
    13 friend.sayName(); //error

     

    此处输入图片的描述 
    原型模式的缺点,对于包含引用类型值的属性来说,某个实例的属性赋值,会影响到所有实例。

     
     1 function Person(){
     2 }
     3 Person.prototype = {
     4     constructor: Person,
     5     name : "Nicholas",
     6     age : 29,
     7     job : "Software Engineer",
     8     friends : ["Shelby", "Court"],
     9     sayName : function () {
    10         alert(this.name);
    11     }
    12 };
    13 var person1 = new Person();
    14 var person2 = new Person();
    15 //person1.friends = [];//如果先创建的话,那么这个friends就是person1的,但是这样就没法保留原型中的值。
    16 person1.friends.push("Van");//这个friends是原型的。
    17 alert(person1.friends); //"Shelby,Court,Van"
    18 alert(person2.friends); //"Shelby,Court,Van"
    19 alert(person1.friends === person2.friends); //true

     

    所以开始引入构造函数+原型模式 :构造函数模式用于指定实例属性,原型模式用于定义方法和共享的属性。

     1 function Person(name, age, job){
     2     this.name = name;
     3     this.age = age;
     4     this.job = job;
     5     this.friends = ["Shelby", "Court"];
     6 }
     7 Person.prototype = {
     8     constructor : Person,
     9     sayName : function(){
    10         alert(this.name);
    11     }
    12 }
    13 var person1 = new Person("Nicholas", 29, "Software Engineer");
    14 var person2 = new Person("Greg", 27, "Doctor");
    15 person1.friends.push("Van");
    16 alert(person1.friends); //"Shelby,Count,Van"
    17 alert(person2.friends); //"Shelby,Count"
    18 alert(person1.friends === person2.friends); //false
    19 alert(person1.sayName === person2.sayName); //true

     

    最完美的模式来了,动态原型模式。不能使用对象字面量重写原型。和构造函数+原型的区别是,new的时候才会给原型添加属性。

     1 function Person(name, age, job){
     2     //属性
     3     this.name = name;
     4     this.age = age;
     5     this.job = job;
     6     //方法
     7     if (typeof this.sayName != "function"){
     8         Person.prototype.sayName = function(){
     9             alert(this.name);
    10         };
    11     }
    12 }
    13 var friend = new Person("Nicholas", 29, "Software Engineer");
    14 friend.sayName();

    四、继承

     最完美的继承:寄生组合式继承

     1  function object(o){
     2    function F(){}
     3    F.prototype = o;
     4    return new F();
     5   }
     6   function inheritPrototype(subType, superType){
     7    var prototype = object(superType.prototype); //创建对象
     8    prototype.constructor = subType; //增强对象
     9    subType.prototype = prototype; //指定对象
    10   }
    11   function SuperType(){
    12     this.property = true;
    13     this.arr = [1,2,3];
    14   }
    15   SuperType.prototype.getSuperValue=function(){
    16     return this.property;
    17   }
    18   function SubType(){
    19     SuperType.call(this);
    20     this.subproperty = false;
    21   }
    22   inheritPrototype(SubType,SuperType);
    23 
    24   SubType.prototype.getSubValue=function(){
    25     return this.subproperty;
    26   }
    27   var o = new SubType();
    28   console.log(o);
  • 相关阅读:
    一分钟教你解决前端分流问题
    win7 mysql 数据库轻松实现数据库定时备份
    mysql 修改密码
    what is yaml ?
    php实现监控在线服务应用程序小栗子
    Python装饰器小代码
    2,构造代码块
    1,匿名对象,封装
    7,random
    测试错题
  • 原文地址:https://www.cnblogs.com/huipinpuzi/p/4644990.html
Copyright © 2020-2023  润新知