1 实例属性/方法

都是绑定在使用构造函数创建出来的对象p上; 最终使用的时候也是使用对象p来进行访问;

  1. function Person(name, age, doFunc) {
  2. this.name = name;
  3. this.age = age;
  4. this.doFunc = doFunc;
  5. }
  6. var p1 = new Person('sz', 18, function () {
  7. console.log('sz在上课');
  8. });
  9. var p2 = new Person('王二小', 18, function () {
  10. console.log('王二小在放羊');
  11. });

2 静态属性/方法

函数本质也是一个对象, 既然是个对象, 那么就可以动态的添加属性和方法

只要函数存在, 那么绑定在它身上的属性和方法, 也会一直存在

eg,记录总共创建了多少个人对象:

2.1 全局变量

  1. // 1. 设置一个全局的变量
  2. var personCount = 0;
  3. function Person(name, age, doFunc) {
  4. this.name = name;
  5. this.age = age;
  6. this.doFunc = doFunc;
  7. personCount++;
  8. }
  9. var p1 = new Person('sz', 18, function () {
  10. console.log('sz在上课');
  11. });
  12. var p2 = new Person('王二小', 18, function () {
  13. console.log('王二小在放羊');
  14. });
  15. console.log('总共创建了'+ personCount + '个人'); //2

2.2 静态属性/方法

  1. function Person(name, age, doFunc) {
  2. this.name = name;
  3. this.age = age;
  4. this.doFunc = doFunc;
  5. if (!Person.personCount) {
  6. Person.personCount = 0; //创建静态属性
  7. }
  8. Person.personCount++;
  9. }
  10. //创建静态方法
  11. Person.printPersonCount = function () {
  12. console.log('总共创建了'+ Person.personCount + '个人');
  13. };
  14. var p1 = new Person('sz', 18, function () {
  15. console.log('sz在上课');
  16. });
  17. var p2 = new Person('王二小', 18, function () {
  18. console.log('王二小在放羊');
  19. });
  20. Person.printPersonCount();

3 类型获取

3.1 内置对象类型获取

内置对象

• String

• Number

• Boolean

• Object

• Function

• Array

• Date

• RegExp

• Error

获取根据自己声明的构造函数创建的对象

  1. console.info("-->str")
  2. var str = "aaa";
  3. console.log(typeof str); //string
  4. console.log(str.constructor.name); //String
  5. console.log(Object.prototype.toString.call(str)); //[object String]
  6. console.info("-->obj")
  7. var obj = { 'name': '张三' };
  8. console.log(typeof obj); //object
  9. console.log(obj.toString()); //[object Object]
  10. console.log(obj.constructor.name); //Object
  11. console.log(Object.prototype.toString.call(obj)); //[object Object]
  12. console.info("-->arr")
  13. var arr = [1, 2, 3];
  14. console.log(typeof arr); //object
  15. console.log(arr.toString()); //1,2,3
  16. console.log(arr.constructor.name); //Array
  17. console.log(Object.prototype.toString.call(arr)); //[object Array]
  18. console.info("-->date")
  19. var date = new Date();
  20. console.log(typeof date); //object
  21. console.log(date.toString()); //Wed Oct 09 2019 00:08:15 GMT+0800 (中国标准时间)
  22. console.log(date.constructor.name); //Date
  23. console.log(Object.prototype.toString.call(date)); //[object Date]

3.2 自定义类型获取

还是使用 实例化对象.constructor.name

  1. function Person(name, age) {
  2. // var this = new Object(); 自定义类型系统都把this指向Object,所以Object.prototype.toString.call(...) 获取都是 [object Object]
  3. this.name = name;
  4. this.age = age;
  5. }
  6. function Dog(name, age) {
  7. this.name = name;
  8. this.age = age;
  9. }
  10. function Cat(name, age) {
  11. this.name = name;
  12. this.age = age;
  13. }
  14. // 1. 实例化-->实例
  15. var p = new Person('zs', 18);
  16. var d = new Dog('小花', 8);
  17. var c = new Cat('小猫', 3);
  18. // object
  19. console.log(typeof p);
  20. console.log(typeof d);
  21. console.log(typeof c);
  22. // [object Object]
  23. console.log(p.toString());
  24. console.log(d.toString());
  25. console.log(c.toString());
  26. // [object Object]
  27. console.log(Object.prototype.toString.call(p));
  28. console.log(Object.prototype.toString.call(d));
  29. console.log(Object.prototype.toString.call(c));
  30. console.log(p.constructor.name); //Person
  31. console.log(d.constructor.name); //Dog
  32. console.log(c.constructor.name); //Cat

3.3 类型验证 instanceof

类型验证使用 instanceof

  1. function Person(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. function Dog(name, age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. function Cat(name, age) {
  10. this.name = name;
  11. this.age = age;
  12. }
  13. // 1. 实例化-->实例
  14. var p = new Person('zs', 18);
  15. var d = new Dog('小花', 8);
  16. var c = new Cat('小猫', 3);
  17. //true
  18. console.log(p instanceof Person);
  19. console.log(d instanceof Dog);
  20. console.log(c instanceof Cat);
  21. //true
  22. console.log(p instanceof Object);
  23. console.log(d instanceof Object);
  24. console.log(c instanceof Object);
  25. //false
  26. console.log(p instanceof Dog);
  27. console.log(d instanceof Cat);
  28. console.log(c instanceof Person);
  29. console.log(p);
  30. console.log(d);
  31. console.log(c);
  32. //true
  33. console.log([] instanceof Object);

4 访问函数原型对象

  1. function Person(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. // 原型对象
  6. Person.prototype.run = function () {
  7. console.log('跑');
  8. };

4.1 方式一:函数名.prototype

  1. console.log(Person.prototype);

浏览器

  1. > {run: ƒ, constructor: ƒ}
  2. > run: ƒ ()
  3. > constructor: ƒ Person(name, age)
  4. > __proto__: Object

4.2 方式二:对象.proto(不推荐)

.__proto__看起来很像一个属性,但是实际上它更像一个getter/setter

  1. var p = new Person();
  2. console.log(p.__proto__);

浏览器

  1. > {run: ƒ, constructor: ƒ}
  2. > run: ƒ ()
  3. > constructor: ƒ Person(name, age)
  4. > __proto__: Object

__proto__是一个非标准属性

即ECMAScript中并不包含该属性,这只是某些浏览器为了方便开发人员开发和调试而提供的一个属性,不具备通用性

建议:在调试的时候可以使用该属性,但不能出现在正式的代码中

4.2.1 __proto__可以设置

.__proto__是可设置属性,可以使用ES6的Object.setPrototypeOf(..)进行设置。然而,通常来说你不需要修改已有对象的[[Prototype]]。

  1. var newYX = {
  2. 'add': function () {
  3. console.log('sum');
  4. }
  5. };
  6. p.__proto__ = newYX;
  7. console.log(p.__proto__);

浏览器

  1. > {add: ƒ}
  2. > add: ƒ ()
  3. > __proto__: Object

5 判断原型对象是否存在某属性

5.1 in 属性

in 判断一个对象, 是否拥有某个属性(如果对象身上没有, 会到原型对象里面查找)

  1. function Person(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Person.prototype.address = '上海';
  6. var p = new Person('撩课', 18);
  7. // console.log(name in p); // false
  8. console.log('name' in p); // true
  9. console.log('address' in p); // true

5.2 hasOwnProperty 属性

只到对象自身查找

  1. function Person(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Person.prototype.address = '上海';
  6. var p = new Person('张三', 20);
  7. console.log(p.hasOwnProperty('name')); // true
  8. console.log(p.hasOwnProperty('address')); // false

6 判断一个对象的原型 isPrototypeOf 和 instanceOf

是的,它们执行相同的操作,都遍历原型链以查找其中的特定对象。

两者的区别在于它们是什么,以及如何使用它们,例如isPrototypeOf是对象上可用的函数。它允许您测试一个特定对象是否在另一个对象的prototype链中,因为此方法是在object上定义的原型,它对所有对象都可用。

instanceof是一个操作符,它需要两个操作数,一个对象和一个构造函数,它将测试传递的函数原型属性是否存在于对象链上(通过[[HasInstance]](V)内部操作,仅在函数对象中可用)。

B.isPrototypeOf(a) 判断的是A对象是否存在于B对象的原型链之中,检查B

a instanceof B 判断的是B.prototype是否存在与A的原型链之中,检查B.prototype

isPrototypeOf() 与 instanceof 运算符不同。在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。

  1. function A () {
  2. this.a = 1;
  3. }
  4. function B () {
  5. this.b = 2;
  6. }
  7. B.prototype = new A();
  8. B.prototype.constructor = B;
  9. function C () {
  10. this.c = 3;
  11. }
  12. C.prototype = new B();
  13. C.prototype.constructor = C;
  14. var c = new C();
  15. // instanceof expects a constructor function
  16. c instanceof A; // true
  17. c instanceof B; // true
  18. c instanceof C; // true
  19. // isPrototypeOf, can be used on any object
  20. A.prototype.isPrototypeOf(c); // true
  21. B.prototype.isPrototypeOf(c); // true
  22. C.prototype.isPrototypeOf(c); // true

7 继承(MDN)

7.1 定义 Teacher() 构造器函数

  1. function Person(first, last, age, gender, interests) {
  2. this.name = {
  3. first,
  4. last
  5. };
  6. this.age = age;
  7. this.gender = gender;
  8. this.interests = interests;
  9. };
  10. Person.prototype.greeting = function() {
  11. console.log('Hi! I\'m ' + this.name.first + '.');
  12. };
  13. function Teacher(first, last, age, gender, interests, subject) {
  14. Person.call(this, first, last, age, gender, interests); //用的是传送给Teacher(),而不是Person()的值
  15. this.subject = subject;
  16. }
  17. var p = new Person("张","三",22,"男",["篮球","KTV"]);
  18. var t = new Teacher("李","四",18,"男",["英语","计算机"],"编程");
  19. t.greeting();
  20. //TypeError: t.greeting is not a function
  21. //这里 Teacher 不能获取 greeting...

这里主要调用Person.call(this, first, last, age, gender, interests);定义 Teacher() 构造器函数,

我们很有效的在Teacher()构造函数里运行了Person()构造函数,得到了和在Teacher()里定义的一样的属性,但是用的是传送给Teacher(),而不是Person()的值(我们简单使用这里的this作为传给call()的this,意味着this指向Teacher()函数)。

7.2 设置 Teacher() 的原型

我们需要让Teacher()从Person()的原型对象里继承方法

  1. Teacher.prototype = Object.create(Person.prototype);

在这个例子里我们用这个函数来创建一个和Person.prototype一样的新的原型属性值(这个属性指向一个包括属性和方法的对象),然后将其作为Teacher.prototype的属性值。

7.2.1 为什么不能使用 Teacher.prototype = Person.prototype

看看比较

7.3 设置 Teacher() 构造器引用

现在Teacher()的prototype的constructor属性指向的是Person(), 这是由我们生成Teacher()的方式决定的。

这或许会成为很大的问题,所以我们需要将其正确设置——您可以回到源代码,在底下加上这一行代码来解决:

  1. Teacher.prototype.constructor = Teacher;

注:每一个函数对象(Function)都有一个prototype属性,并且只有函数对象有prototype属性,因为prototype本身就是定义在Function对象下的属性。当我们输入类似var person1=new Person(...)来构造对象时,JavaScript实际上参考的是Person.prototype指向的对象来生成person1。另一方面,Person()函数是Person.prototype的构造函数,也就是说Person===Person.prototype.constructor(不信的话可以试试)。

在定义新的构造函数Teacher时,我们通过function.call来调用父类的构造函数,但是这样无法自动指定Teacher.prototype的值,这样Teacher.prototype就只能包含在构造函数里构造的属性,而没有方法。因此我们利用Object.create()方法将Person.prototype作为Teacher.prototype的原型对象,并改变其构造器指向,使之与Teacher关联。

任何您想要被继承的方法都应该定义在构造函数的prototype对象里,并且永远使用父类的prototype来创造子类的prototype,这样才不会打乱类继承结构。

new 与 Object.create 区别

  1. new的话只能是class(即函数),但是Object.create()的参数可以为对象也可以为函数,
  2. 如果Object.create()的参数是对象的话,那么新的对象会继承原对象的属性;如果参数是类(函数)的话,Object.create()的参数为类(函数)原型,如您所说的,它没有绑定this,并没有属性被继承。
  3. Object.create(null)可以实现一个空对象,即没有原型的对象,但使用new就办不到。

7.4 多对象继承

Object.assign(目标对象, ...源对象) 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

  1. //再创建一个基类
  2. function Animal(age) {
  3. this.age = age;
  4. }
  5. Animal.prototype.say = function(language) {
  6. console.log('you say ' + language);
  7. }
  8. function Student(name, sex, age) {
  9. Person.call(this, name, sex);
  10. Animal.call(this, age);
  11. }
  12. //原型链拼接
  13. Student.prototype = Object.create(Person.prototype);
  14. Object.assign(Student.prototype, Animal.prototype);
  15. Student.prototype.constructor = Student;
  16. Student.prototype.getInfo = function() {
  17. console.log('getInfo: [name:' + this.name + ', sex:' + this.sex + ', age:' +this.age + '].');
  18. };
  19. var s = new Student('coco', 'femal', 25);

7.5 JS继承练习

  1. function Animal(name, age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  5. Animal.prototype.eat = function () {
  6. console.log('吃');
  7. };
  8. Animal.prototype.run = function () {
  9. console.log('跑');
  10. }
  11. function Person(name, age, job) {
  12. Animal.call(this, name, age);
  13. this.job = job;
  14. }
  15. Person.prototype = Object.create(Animal.prototype);
  16. Person.prototype.constructor = Person;
  17. //Person.prototype.jump 原型方法必须写在继承后
  18. Person.prototype.jump = function () {
  19. console.log('跳');
  20. };
  21. function Student(name, age, job, className) {
  22. Animal.call(this, name, age);
  23. Person.call(this, name, age, job);
  24. this.className = className;
  25. }
  26. Student.prototype = Object.create(Person.prototype);
  27. Student.prototype.constructor = Student;
  28. //原型方法必须写在继承后
  29. Student.prototype.study = function () {
  30. console.log('学习');
  31. }
  32. function Adolescent(name, age, job, className,sex) {
  33. Animal.call(this, name, age);
  34. Person.call(this, name, age, job);
  35. Person.call(this, name, age, job,className);
  36. this.sex = sex;
  37. }
  38. Adolescent.prototype = Object.create(Student.prototype);
  39. Adolescent.prototype.constructor = Adolescent;
  40. //原型方法必须写在继承后
  41. Student.prototype.play = function () {
  42. console.log('跳绳');
  43. }
  44. this.a2 = new Adolescent('张同学',18,'学生','高2.1版',"女");
  45. this.s1 = new Student('张同学',18,'学生','高2.1版');
  46. this.p1 = new Person('王老师',26,'教师');
  47. this.a1 = new Animal('校长',44);

原型方法必须写在设置原型 XXX.prototype = Object.create(...)和设置构造器引用XXX.prototype.constructor = xxx之后,不容会丢失。

7.6 内置对象的扩展

方式1(失败)

  1. 直接给对象动态添加属性和方法
  2. 弊端:
  3. 如果操作很多个对象, 则无法共享
  4. 代码比较冗余

例子:arr2的run不能执行~

  1. var arr = [1,2,3];
  2. arr.run = function () {
  3. console.log('跑');
  4. }
  5. arr.run();
  6. var arr2 = [2];
  7. arr.run = function () {
  8. console.log('跑');
  9. }

方式2(容易覆盖)

  1. 直接给Array原型对象添加方法
  2. 弊端:
  3. 可能会产生覆盖的情况

例子:覆盖push

  1. Array.prototype.push = function () {
  2. console.log('跑');
  3. };
  4. var arr = [1,2,3];
  5. arr.push();
  6. var arr2 = [2];
  7. arr2.push();

方式3(推荐)

  1. 提供一个新的构造函数
  2. 修改构造函数的原型指向为数组的原型对象
  3. 为了能够获取数组里面的属性和方法
  4. 问题:
  5. 依然会修改数组原型对象内容
  6. 优化
  7. 原型对象就是一个对象
  8. 可以直接根据Array创建一个对象, 给新创建的函数原型对象进行赋值
  1. function MyArray() {}
  2. MyArray.prototype = new Array();
  3. MyArray.prototype.run = function () {
  4. console.log('跑');
  5. };
  6. var arr = new MyArray();
  7. arr.run();

8 深拷贝与浅拷贝

8.1 浅拷贝

8.1.1 遍历

  1. var obj1 = {name: '张三', age: 18};
  2. var obj2 = {};
  3. for (var key in obj1) {
  4. obj2[key] = obj1[key];
  5. }
  6. console.log(obj2);

8.1.2 Object.assign(目标对象, ...源对象)

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

  1. var obj3 = {className: '六班'};
  2. Object.assign(obj3, obj1, {address: '重庆'});
  3. console.log(obj3);

具有相同的,则属性将被源对象中的属性覆盖

  1. const target = { a: 1, b: 3 };
  2. const source = { b: 4, c: 5 };
  3. const returnedTarget = Object.assign(target, source);
  4. console.log(returnedTarget);
  5. // expected output: Object { a: 1, b: 4, c: 5 }

8.2 深拷贝

深拷贝/浅拷贝

区别:在于对引用值的处理

  • 浅拷贝, 直接拷贝一份地址
  • 深拷贝-拷贝地址对应的具体内容

深拷贝实现

  1. 提供一个函数,两个参数(元对象,要拷贝属性的对象)
  2. 在函数中先检查第一个参数是否有值,如果没有值那么就初始化一个空的对象
  3. for..in循环来变量参数2
    1. 检查当前的属性值是什么类型
    2. 如果是值类型,那么就直接拷贝赋值
    3. 如果是引用类型,那么就再调用一次这个方法,去内部拷贝这个对象的所有属性
  1. var obj = {
  2. name: "唐三三",
  3. age: 30,
  4. friend: ['张森', '夏赢'],
  5. address: {
  6. city: '重庆',
  7. county: '渝北'
  8. },
  9. play: function () {
  10. console.log(this.name + '喜欢桌球');
  11. }
  12. }
  13. //deep Copy
  14. function deepCopySource2Target(source, target) {
  15. for (var key in source) {
  16. var sourceValue = source[key];
  17. if (!(sourceValue instanceof Object)) {
  18. //value object
  19. target[key] = sourceValue;
  20. }
  21. else {
  22. //object object
  23. var temp = new sourceValue.constructor;
  24. deepCopySource2Target(sourceValue, temp);
  25. target[key] = temp;
  26. }
  27. }
  28. }
  29. var newObj = {};
  30. deepCopySource2Target(obj, newObj);
  31. console.log(newObj);
  32. newObj.play();

参考:

js继承实现之Object.create - 太阳的眼睛

javascript中继承-MDN

继承与原型链-MDN

ObjectPlayground.com - 一个非常有用的、用于了解对象的交互式学习网站。

彻底搞懂JavaScript中的继承- 掘金

JS高级:面向对象解析的更多相关文章

  1. js高级-面向对象继承

    一.工厂模式创建对象及优缺点 继承就是把公共的部分抽象出来作为父类,基类.吃饭,跑步等 var a = {}; //批量创建不方便,不能重复设置公共属性的代码 //工厂模式出现了,创建10个Cat对象 ...

  2. JS高级 - 面向对象5(继承,引用)

    <script type="text/javascript"> //------------------Person类 //(Person)的构造函数 function ...

  3. JS高级 - 面向对象1(this,Object ,工厂方式,new )

    面向对象三要素: 封装 继承 多态 1.this 详解,事件处理中this的本质 window this -- 函数属于谁 <script type="text/javascript& ...

  4. JS高级---面向对象的编程思想(贪吃蛇梳理)

    面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...

  5. JS高级 - 面向对象4(json方式面向对象)

    把方法包在一个Json里 var p1 = { name: "唐三", sex: "男", dreamdu: { URL: "www.dreamdu. ...

  6. JS高级 - 面向对象3(面向过程改写面向对象)

    改写: 1.前提:所有东西都在 onload 里 2.改写:不能有函数嵌套,可以有全局变量 onload --> 构造函数 全局变量 --> 属性 函数 --> 方法 4.改错: t ...

  7. JS高级 - 面向对象2(prototype定义)

    定义和用法 prototype 属性允许您向对象添加属性和方法 注意: Prototype 是全局属性,适用于所有的Javascript对象. 语法 object.prototype.name=val ...

  8. JS高级——面向对象方式解决tab栏切换问题

    注意事项 1.给li元素注册事件,函数里面的this指的li元素,那么我们可以在注册事件之前将Tab对象用that=this进行保存 2.使用沙箱模式,所以暴露给外面的变量使用的是window.tab ...

  9. JS高级——面向对象方式解决歌曲管理问题

    需要注意的问题: 1.其他模块若是使用构造函数MP3创建对象,唯一不同的就是他们传入的音乐库是不一样的,所以构造函数中存在一个songList属性,其他一样的就被添加到了构造函数的原型对象之中 2.原 ...

  10. 《JS高级程序设计》笔记 —— 解析查询字符串

    今天在继续翻阅<JS高级程序设计>的时候,正好翻到location对象这一小节,其中有一部分就是讲的解析查询字符串.看到这个内容立马想到了做去哪儿秋招笔试题的时候有这么一道题. 去哪儿笔试 ...

随机推荐

  1. 经典sql server基础语句不全

    1.几个简单的基本的sql语句 选择: select * from table1 where 范围 插入: insert into table1(field1,field2) values(value ...

  2. myEclipse项目部署点击Finish按钮没反应

    -- 问题描述:myEclipse项目部署点击Finish按钮没反应. -- 问题原因:Tomcat没有不熟JDK. -- 解决办法:window->preferences->servic ...

  3. beta版本——第七次冲刺

    第七次冲刺 (1)SCRUM部分☁️ 成员描述: 姓名 李星晨 完成了哪个任务 编写个人信息修改界面的js 花了多少时间 3h 还剩余多少时间 0h 遇到什么困难 密码验证部分出现问题 这两天解决的进 ...

  4. Qualification Rounds(Codeforces Round #438 by Sberbank and Barcelona Bootcamp (Div. 1 + Div. 2 combined)+状态压缩)

    题目链接 传送门 题意 现总共有\(n\)个题目\(k\)支参赛队伍,已知每个题目各队伍是否会写,现问你能否从题目中选出一个子序列使得每支队伍最多只会写一半的题目. 思路 对于每个题目我们用二进制压缩 ...

  5. python 打印html源码中xpath

    实例: #coding:utf-8 from lxml import etree import urllib url=urllib.urlopen('http://www.baidu.com').re ...

  6. 项目Alpha冲刺(团队)-第七天冲刺

    格式描述 课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(团队) 团队名称:为了交项目干杯 作业目标:描述第七天冲刺的项目进展.问题困难.心得体会 队员姓名与学号 队员学号 ...

  7. http请求头出现provisional headers are shown

    http请求头出现provisional headers are shown Provisional headers are shown provisional 详细用法>> 英 [prə ...

  8. kvm创建windows2008虚拟机

    virt-install -n win2008-fushi001 -r 16384 --vcpus=4 --os-type=windows --accelerate -c /data/kvm/imag ...

  9. vs下载代码

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012605477/article/details/62222919Visual Studio 20 ...

  10. 思科ASA基本配置

    ------------恢复内容开始------------ ASA基本配置 ciscoasa#show running-config        //讲解已作的默认配置 ciscoasa#conf ...