2018-10-22面向对象

[参考文章1]https://www.cnblogs.com/linququ/p/8733079.html
[参考文件2]https://blog.csdn.net/xuexiaodong009/article/details/37693345
[参考文章3]https://www.jianshu.com/p/1488be295383
[参考文章4]https://www.cnblogs.com/humin/p/4556820.html
[参考文章5]https://www.jianshu.com/p/15ac7393bc1f


tag: 面向对象, 原型, 原型链,继承, 变量类型判断, 变量属性


1、创建对象的方法

1.1 对象直接量

var student={name:'Tom', age:11}

直接量:花括号包裹键值对,冒号分隔键值,两个键值对之间使用逗号分开
键名:标识符、字符串直接量(包含空字符)、Symbol值
值:任意js表达式(原始或对象)

var book = {
  "main book": "helloJS", //有空格的键必须使用字符串
  "sub-title": "helloNode", //有连接符必须使用字符串
  "for": "hello" //"for"属性名字里含有保留字,必须使用字符串
};

通过对象直接量创建的对象都具有相同的原型,Object.prototype
可以使用对象名.__proto__查看对象原型

1.2 Object.create()

  1. ES5中定义的方法
Object.create(proto[,propertiesObject])
  • 第一个参数是新创建对象的原型,任意的对象(包括原型对象)
  • 第二个参数是定义对象的属性,可选
var o =Object.create({name:'x',age:11})
//o继承了原型的属性name和age
o.__proto__ //{name:'x',age:11}
  1. null为原型
var n = Object.create(null);
//n不继承任何属性或方法,包括toString()方法
  1. 创建空对象,同{}new Object(),继承Object的原型即可
var o =Object.create(Object.prototype)

同理Date、Array等对象可以通过其原型创建新对象

  1. 定义属性


    定义属性
let o = Object.create(Object.prototype, {
  // foo会成为所创建对象的数据属性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar会成为所创建对象的访问器属性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});

扩展 定义属性Object.defineProperties,Object.defineProperty,

Object.defineProperty(obj, 'a', {
            value: true,
            writable: true,
            configurable: true,
            enumerable: true,
            getter: () => {},
            setter: () => {}
    })
  Object.defineProperties(obj, {
        'property1': {
            value: true,
            writable: true,
        },
        'property2': {
            value: true,
            writable: true,
        }
    })

1.3 工厂模式

var createPerson=function(name ,age){
    var obj=new Object; //es5的方法
    obj.name=name;
    obj.age=age;
    obj.getName=function(){
        return this.name
    }
  return obj 
}
var person=createPerson('tom',22)

缺点:

  1. 对象和实例之间没有联系
  2. 每个实例都有创建相同的方法造成资源浪费

1.4 构造函数模式

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function() {
    console.log(`My name is ${name}, i'm ${age} years old`);
  };
}
var p = new Person("Tom", 11);

解决了对象和实例之间的关系问题
缺点:资源浪费

new执行的过程(做了啥)
1、声明一个中间对象;
2、将中间对象的原型指向构造函数的原型;
3、将构造函数的this指向中间对象;
4、执行构造函数,为中间对象添加对象或方法,如果构造函数有返回值直接返回,结束执行;
5、返回该中间对象即实例对象。

new关键字的简单实现

function New(func) {
  //声明一个中间对象,该对象为返回的实例对象
  var res = {};
  if (func.prototype !== null) {
    //将实例对象的原型指向构造函数的原型
    res.__proto__ = func.prototype;
  }
  //ret为构造函数的执行结果,通过apply将构造函数内部的this指向修改为res,即实例对象,并添加对象和方法
  var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
  if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
    return ret;//构造函数有返回值
  }
  return res;//构造函数无返回值直接返回中间对象
}
var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        return this.name;
    }
}
// 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res
var p1 = New(Person, 'tom', 20);
console.log(p1.getName());

js一些内置对象提供了构造器,可以用new关键字创建新对象

var o = new Object();
var a = new Array();
var d = new Date();
var r = new RegExp("js");

新对象原型就是构造函数的prototype属性,a的原型是Array.prototype

a.__proto__ === Array.prototype //true

1.5 原型模式

var Person = function() {};
Person.prototype.name = "Lin";
Person.prototype.age = 11;
Person.prototype.getName = function() {
  return this.name;
};
var p1 = new Person();
var p2 = new Person();
console.log(p1.getName === p2.getName); //true
  • 构造函数通过prototype指向原型对象
  • 构造函数生成实例对象通过proto指向原型对象
  • 原型对象通过constructor指向构造函数
    优点:减少了代码重复
    缺点:构造函数调用时无法传参

1.6 构造函数和原型组合模式

var Person = function(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.friends = ["Shelby", "Court"];
};
Person.prototype = {
  sayName: function() {
    console.log(this.name);
  }
};
var p1 = new Person("Tom", 20, "student");
var p2 = new Person("Jerry", 21, "student");
p1.friends.push("Van"); 
console.log(p1.friends); //["Shelby", "Court", "Van"]
console.log(p2.friends); //["Shelby", "Court"]
console.log(p1.friends === p2.friends); //false
console.log(p1.sayName === p1.sayName); //true

函数用于定义实例属性,原型模式用来定义方法和共享属性。
每个实例可传递参数创建自有的属性,又共享共有的属性和方法,最大限度节省内存。

2、对象的属性

2.1 如何访问对象的属性

var person = {
    name: 'TOM',
    age: '20',
    getName: function() {
        return this.name
    }
}
person.name
// 或者
person['name']

当属性名是个变量时,一定要使用第二种

let name ='age'
person.name//'TOM'
person[name]; //20

同理在创建对象的时候,也可使用[name],创建key不确定的属性

let name ='age'
var person = {
    name: 'TOM',
    [name]: '20',  
}
person.name//'TOM'
person[name]; //20

另一个应用,遍历对象

Object.keys(person).forEach(key=>console.log(person[key]))
// TOM
// 20

2.2 判断对象是否包含某个属性

通过in来判断,一个对象是否拥有某一个属性/方法,无论是该属性/方法存在于实例对象还是原型对象。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

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

var p1 = new Person('tim', 10);

console.log('name' in p1); // true
console.log('getName' in p1); // true

判断当前页面是否在移动端打开

isMobile = 'ontouchstart' in document;

2.3.属性类型

1)在使用Object.defineProperty、Object.defineProperties 或 Object.create 函数的情况下添加数据属性,writable、enumerable和configurable默认值为false。
2)使用对象直接量创建的属性,writable、enumerable和configurable特性默认为true。

  • 数据属性

    • value:属性的值,默认为undefined
    • writable:是否为只读属性。为false时,value的值不能改变
    • enumerable:属性是否可被(for...in)遍历
    • configurable:表示是否可以删除该属性。为false时,writable和enumerable属性不能被改变,该属性也不能被删除
  • 访问器属性

    • enumerable:属性是否可被(for...in)遍历
    • configurable:表示是否可以删除该属性。为false时,writable和enumerable 属性不能被改变,该属性也不能被删除
    • get: 当我们通过person.name访问name的值时,get将被调用。该方法可以自定义返回的具体值时多少。get默认值为undefined
    • set: 当我们通过person.name = 'Jake'设置name的值时,set方法将被调用。该方法可以自定义设置值的具体方式。set默认值为undefined

注意不能同时设置value,writable,get,set的值(就是不能同时拥有数据属性和访问器属性)
可以通过Object.defineProperty来修改这些属性类型
configurable

var person={
  name:'tom'
}
delete person.name
//true 删除成功
//通过Object.defineProperty设置为person设置name属性
Object.defineProperty(person,'name',{
  value:'Jake'
})
delete person.name
//false,删除失败
person.name='jade'
person.name //'Jake'修改失败

enumerable

let  person={
    name:'tom',
    age:12
}
for(var key in person){
    console.log(key) //'name'  'age'
}

//Object.defineProperty添加的新属性默认enumerable为false,不可遍历
Object.defineProperty(person,'address',{
    value:'Lodon'
})
for(var key in person){
    console.log(key) //'name'  'age'
}

//修改name属性不可遍历
Object.defineProperty(person,'name',{
   enumerable:false
})-
for(var key in person){
    console.log(key) // 'age'
}

writable

let person={
    name:'TOM'
}
person.name='Jake'
person.name   //'Jake'修改成功
//设置name属性不能修改
Object.defineProperty(person,'name',{
  writable:false
})
person.name='Tom'
person.name //Jake 修改失败

value

var  person={}
Object.defineProperty(person,'name',{
    value:'Tom'
})
person.name //'Tom'

get/set

var person={}
//通过get、set自定义访问和设置name属性的方式
Object.defineProperty(person,'name',{
      get:function(){
          //始终返回TOM
          return 'TOM'
      },
      set:function(value){
          //设置name属性时返回该字符串的新值,value为新增
          console.log(value+' in set')
      }
})
console.log(person.name) //调用get方法,一直返回TOM
person.name='Alex'//调用set方法 'Alex in set'
console.log(person.name)//还是返回TOM

请尽量同时设置get和set。如果仅仅设置get我们无法设置该属性的值,如果仅仅设置set属性无法获取属性的值
同时设置多个属性的值,可以使用Object.defineProperties

var person={}
Object.defineProperties(person,{
    name:{
         value:'TOM',
         configurable:true
    },
    age:{
        get:function(){
          return this.value||12
        },
        set:function(value){
            this.value=value
        }
    }
 })
person.name//"TOM"
person.age //22

读取属性的特性值
Object.getOwnPropertyDescriptor方法读取某一个属性的特性值

var person={}
Object.defineProperty(person,'name',{
    value:'Alex'
})
var descriptor =Object.getOwnPropertyDescriptor(person,'name')
descriptor
//configurable: false
//enumerable: false
//value: "Alex"
//writable: false

3、变量类型检测

基本类型

  • undefined,表示未定义值,创建变量未初始化值
    undefined,不是关键字,建议使用void 0 代替。一般不会把变量值定义为undefined。

  • null,表示变量定义为空值
    null,关键字,直接赋值给变量

  • boolean,真假,true/false

  • string,字符串的UTF16编码,最长字符串编码长度为2^53-1
    一旦创建无法修改
    字符编码参考

  • number,浮点数
    共计2^64 - 2^53 + 3个值
    NaN、Infinity、-Infinity、+0、-0
    判断+0、-0的方法。1/x 是Infinity还是-Infinity
    浮点数不能用=====比较是否相等,而是使用比最小精度值小

 console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON)//true
  • symbol,一切非字符串的读写key的集合
    var mySymbol = Symbol("my symbol");

对象定义Symbol.iterator接口,可以使用for...of...循环遍历
具体参考ES6

  • object
    • Number
    • String
    • Boolean
    • Symbol
      Number、String、Boolean三个构造器,与new搭配产生对象,直接调用表示强制类型转换。
      Symbol不能使用new创建对象
      装箱操作
let symbolObj = (function(){return this}).call(Symbol('my symbol')
typeof symbolObj
//"object"

3.1 typeof

判断基本类型

typeof undefined; //'undefined'
typeof null; //"object"
typeof "string"; //'string'
typeof 1;  //"number"
typeof true; //"boolean"
typeof Symbol("my"); //"symbol"
typeof function() {}; //"function"
typeof []; //"object"
typeof {}; //"object"
typeof new String('string'); //'object'

无法区分null, {}, []等对象

3.2 instanceof

实例 instanceof 对象
判断变量是否是某个对象的实例,返回布尔值

var obj = {};
var foo = function() {};
obj instanceof Object; //true
foo instanceof Function; //true
Function instanceof Object; //true
Function instanceof Function; //true

let s = new String("string");
let str = "string";
s instanceof String; //true
str instanceof String; //false
[] instanceof Array; //true
[] instanceof Object; //true

3.3 constructor

根据实例的构造函数判断

[].constructor === Array //true
null.constructor === Object  //Cannot read property 'constructor' of null
undefined.constructor === undefined//Cannot read property 'constructor' of null

3.4 Object.prototype.toString.call();

Object.prototype.toString.call("");  //"[object String]"
Object.prototype.toString.call(new String(true));   //"[object String]"
Object.prototype.toString.call(1);  //"[object Number]"
Object.prototype.toString.call(new Number(1)); //"[object Number]"
Object.prototype.toString.call(true); //"[object Boolean]"
Object.prototype.toString.call(new Boolean(true)); ; //"[object Boolean]"

Object.prototype.toString.call([]);  //"[object Array]"
Object.prototype.toString.call({});  //"[object Object]"
Object.prototype.toString.call(function(){}); //"[object Function]"
Object.prototype.toString.call(new Date()); //"[object Date]"
//构造函数
Object.prototype.toString.call(Function); //"[object Function]"
Object.prototype.toString.call(Array); //"[object Function]"
Object.prototype.toString.call(Object); //"[object Function]"

class Person{}
class p extends Person{}
Object.prototype.toString.call(p); //"[object Function]"

3.5 Array.prototype.isPrototypeOf(obj)

用于判断对象的原型是否为数组

Array.prototype.isPrototypeOf([]); //true
Array.prototype.isPrototypeOf({}); //false
Object.prototype.isPrototypeOf({});//true
Object.prototype.isPrototypeOf([]);//true

3.6 Array.isArray()

精准的判断数组

Array.isArray([]) //true

3.7 综合函数判断函数

function type(o) {
    var t, c, n;  // type, class, name
    // 是null类型:
    if (o === null) return "null";
    // 是数值中的特殊类型: NaN :
    if (o !== o) return "NaN";
    // 使用 typeof 检测除去 "object"类型为的其他类型.   
    if ((t = typeof o) !== "object") return t;
    // typeof检测为"object"类型,则进一步检测
    // 可以检测出大部分内置类型
    if ((c = classof(o)) !== "Object") return c;
    // classof(o)返回为"Object"时,检测constructor
    if (o.constructor && typeof o.constructor === "function" &&
        (n = o.constructor.getName())) return n;
    // 无法识别的其他类型,默认为"Object"
    return "Object";
}
function classof(o) {
    return Object.prototype.toString.call(o).slice(8,-1);
};
    
// 返回function的名称,可能为""或者 null
Function.prototype.getName = function() {
    if ("name" in this) return this.name;
    return this.name = this.toString().match(/function\s*([^(]*)\(/)[1];
};

3.8 JQuery检测类型

jQuery.isArray(obj)测试对象是否为数组。
jQuery.isFunction(obj) 测试对象是否为函数。
jQuery.isEmptyObject(obj) jQuery 1.4 中,这个方法既检测对象本身的属性,也检测从原型继承的属性(因此没有使用hasOwnProperty)。
jQuery.isPlainObject(obj) 测试对象是否是纯粹的对象(通过 "{}" 或者 "new Object" 创建的)。
jQuery.isWindow(obj) 测试对象是否是窗口(有可能是Frame)。
jQuery.type(obj) 检测obj的数据类型。
jQuery.isNumeric(value) 确定它的参数是否是一个数字,包含16进制数

4、继承

父类

//定义一个类-动物
function Animal(name) {
  //属性
  this.name = name || "Animal";
  //实例方法
  this.sleep = function() {
    console.log(this.name + "正在睡觉!");
  };
}
//原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + "正在吃" + food);
};

4.1 原型的继承

父类的实例作为子类的原型

function Cat() {}
Cat.prototype = new Animal();
Cat.prototype.name = "cat";

var cat = new Cat();
cat.name; //'cat'
cat.eat('fish'); //cat正在吃fish
cat.sleep(); // cat正在睡觉!
cat instanceof Animal; //true
cat instanceof Cat;  //true

优点:

  • 实例是子类的实例也是父类的实例
  • 父类新增原型方法/原型属性,子类都能访问

缺点:

  • 必须在实例化后才能为原型新增属性和方法
  • 无法实现多继承
  • 当原型链中包含引用类型值的原型时,该引用类型值会被所有实例共享;
  • 创建子类实例时,无法向父类构造函数传参

4.2 构造函数的继承

使用父类的构造函数来增强子类实例。等于复制父类的实例属性给子类

function Cat(name) {
  Animal.call(this);
  this.name = name || "Tom";
}
var cat = new Cat();
cat.name; //Tom
cat.sleep() //Tom正在睡觉!
cat instanceof Animal; //false
cat instanceof Cat; //true

优点:

  • 子类实例共享父类的属性
  • 创建子类时可以向父类传参
  • 可以实现多继承(调用多个父类.call)
    缺点:
  • 实例只是子类的实例,不是父类的实例
  • 只能继承父类的实例属性和方法,不能继承原型的属性和方法
  • 无法实现函数复用。

4.3 实例继承

为父类实例添加新特性,作为子类实例返回

function Cat(name) {
  var instance = new Animal();
  instance.name = name || "Tom";
  return instance;
}

var cat = new Cat();
cat.name; //Tom
cat.sleep();//Tom正在睡觉!
cat instanceof Animal;  //true
cat instanceof Cat;  //false

优点:

  • 不限制调用方式,不论使用new或是直接函数调用都能返回实例
    缺点:
  • 实例时父类的实例,不是子类的实例
  • 不支持多继承

4.4 拷贝继承

将父类的属性循环拷贝到子类的原型上

function Cat(name) {
  var animal = new Animal();
  for (var p in animal) {
    Cat.prototype[p] = animal[p];
  }
}
Cat.prototype.name = name || "Tom";
var cat = new Cat();
cat.name; //Tom
cat.sleep();//Tom正在睡觉!
cat instanceof Animal;  //false
cat instanceof Cat;  //true

优点:

  • 支持多继承

缺点:

  • 效率低,内存占用高
  • 无法获取父类的不可枚举方法(for in)

4.5 组合继承

通过调用父类构造函数,继承父类构造函数的属性并保留传参优点,通过父类的实例作为子类的原型,实现函数复用

function Cat(name) {
  Animal.call(this);
  this.name = name || "Tom";
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat; //构造函数指向修复

var cat = new Cat();
cat.name; //Tom
cat.sleep();//Tom正在睡觉!
cat instanceof Animal;  //true
cat instanceof Cat;  //true
组合继承(不知道理解的对不对)

优点:

  • 既可以继承实例属性和方法,也可以继承原型属性和方法
  • 既是子类的实例也是父类的实例
  • 不存在引用属性共享问题
  • 可传参
  • 函数可以复用

缺点:

  • 调用了两次父类构造函数,生产了两份实例

4.6 寄生组合继承

通过寄生方式,砍掉父类的实例属性,调用两次父类构造函数的时候,不会初始化两次实例方法和属性,避免组合继承的缺点

function Cat(name) {
  Animal.call(this);
  this.name = name || "Tom";
}
(function() {
  //创建一个没有实例方法的类
  var Super = function() {};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
 Cat.prototype.constructor = Cat; //构造函数指向修复
})();

var cat = new Cat();
cat.name; //Tom
cat.sleep();//Tom正在睡觉!
cat instanceof Animal;  //true
cat instanceof Cat;  //true

没毛病,实现复杂

4.7 ES6继承

class Cat extends Animal{
    constructor(name = 'Tom'){
        super(name)
    }
}

var cat = new Cat();
cat.name; //'Tom'
cat.eat('fish'); //Tom正在吃fish
cat.sleep(); // Tom正在睡觉!
cat instanceof Animal; //true
cat instanceof Cat;  //true

5、更好的继承

封装一个方法,根据父类对象创建一个实例,该实例将会作为子类对象的原型

function  create(proto ,options){
    let  tmp={}
    tmp.__proto__=proto  //实例的原型指向父类的原型
    //传入的方法都挂载到新对象上,新对象作为子类的原型对象
    Object.defineProperties(tmp , options)
    return tmp
}

利用create实现对象的继承

Student.prototype=create(Person.prototype,{
     constructor:{
          value:Student
    }
    getGread:{
        value:function(){
                return this.grade
        }
    }
})

利用Object.create方法代替create

function Person(name , age){
    this.name=name;
    this.age=age
}
Person.prototype.getName=function(){
    return this.name
}
Person.prototype.getAge=function(){
    return this.age
}
function Student(name ,age ,grade){
    //构造函数的继承
    Person.call(this ,name ,age)
    this.grade=grade
}
// 原型继承
Student.prototype = Object.create(Person.prototype, {
    // 不要忘了重新指定构造函数
    constructor: {
        value: Student
    }
    getGrade: {
        value: function() {
            return this.grade
        }
    }
})

6、原型链

function add(){}
image.png
  1. Object构造函数,是函数,所以Object.__proto__指向Function.prototype
  2. 同理,构造函数Function也是函数Function.__proto__指向Function.prototype
  3. Function.prototype是原型对象,所以他的构造函数是Object,所以Function.prototype.__proto__指向Object.prototype

函数add是Function的实例对象,Function原型对象同时又是Object原型的实例。原型链和作用域链相同都是单向查找,因此add可以访问到Object的原型对象的toString方法
前端进阶系列,这一系列文章看了好几遍了,总算看懂了一点(2019-12-4)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,093评论 0 6
  • 面向对象的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。ECMAScr...
    DHFE阅读 960评论 0 4
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,401评论 3 12
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,096评论 0 21
  • 本章内容 理解对象属性 理解并创建对象 理解继承 面向对象语言有一个标志,那就是它们都有类的概念,而通过类可以创建...
    闷油瓶小张阅读 841评论 0 1