一、Js中对象和函数的关系

首先什么是对象?

Js中所有事物都是对象,对象是拥有属性和方法的数据,由此可以看出基本数据类型不是对象(number、Boolean、string、undefined);剩下的引用数据类型(函数、数组、null、。。。)都是对象。

对象是通过函数创建的,而函数又是一种对象。

  • 函数是一种对象

    • 函数里边可以添加属性
    • 很明显,函数是一种对象,但是不能说函数是对象的一种。因为他俩之间没有包含关系
      1. function test() {};
      2. console.log(test instanceof Object); // true
  • 对象都是通过函数创建的

    先看个例子

  1. function test() {
  2. this.name="哈哈"
  3. };
  4. var test2=new test();
  5. console.log(test2 instanceof Object); //true

这个例子可以说明对象可以被函数创建。那为什么要说对象都是通过函数创建的,那对象字面量是不是也是通过函数来创建的,答案是肯定的,这是一种语法糖方式。举个简单的例子

  1. var obj={
  2. name:"哈哈",
  3. age:"18"
  4. }
  5. typeof(obj);
  6. "object"
  7. var obj1 = new Object();
  8. typeof(obj1);
  9. "object"

上面的对象字面量其实是通过下面的构造函数来创建的。而其中的Object是一种函数:

  1. typeof(Object);
  2. "function"

Object 是一种函数

**Object** 构造函数创建一个对象包装器。

语法
  1. // 对象初始化器(Object initialiser)或对象字面量(literal)
  2. { [ nameValuePair1[, nameValuePair2[, ...nameValuePairN] ] ] }
  3. // 以构造函数形式来调用
  4. new Object([value])

描述

在JavaScript中,几乎所有的对象都是Object类型的实例,他们都会从Object.protorype继承属性和方法。Object构造函数为给定值创建一个对象包装器。Object构造函数,会根据给定的参数创建对象:

  • 如果给定值为null和undefined,将会创建并返回一个空对象;
  • 如果传进去的是一个基本类型的值,则会构造其包装类型的对象;
  • 如果传进去的是引用数据类型,任然会返回这个值,经他们复制的变量 保有与源对象相同的引用地址。

    函数的三种形式:普通函数、构造函数、普通对象

    二、原型拓展

    1、在原型上拓展方法

    ```javascript ~~~ function Fn (name,age) { this.name = name; this.age = age; } // 在原型链上拓展公有属性和方法 Fn.prototype.sayFn = function () { // 谁调用这个函数,里边的this就指向谁 alert(“我的名字是:” + this.name + “ “ + “我的年龄是:” + this.age); } var f1 = new Fn(“lili”,20); var f2 = new Fn(“dalili”,22);

f1.sayFn(); f2.sayFn();

  1. ```
  2. <a name="Z14Dg"></a>
  3. ### 2、封装一个ary.push()方法
  4. ```javascript
  5. Array.prototype.Mypush=function(){
  6. for(var i=0;i<arguments.length;i++){
  7. this[this.length]=arguments[i];
  8. }
  9. return this.length;
  10. }
  11. var ary1=[1,2,3];
  12. var res=ary.Mypush(4,5,6);
  13. console.log(ary1);
  14. [4,5,6].Mypush(7,8,9);
  15. ```
  16. <a name="Gvkyt"></a>
  17. ### 3、链式调用
  18. > 想要实现一个需求:
  19. > var ary=[5,8,2,1,10] ;想要让这个数组先排序,然后再倒序,然后再往里面添加一个10,然后再删除第一项;
  20. ```javascript
  21. var ary=[5,8,2,1,10];
  22. ary.sort(function(a,b){return a-b});
  23. ary.reverse();
  24. ary.push(10);
  25. ary.shift();
  26. ```
  27. > 实现链式写法:保证每次函数执行完毕后的 返回结果是当前类的实例
  28. ```javascript
  29. var ary=[5,8,2,1,10];
  30. ary.sort(function(a,b){return a-b}).reverse().push(10);
  31. // push();方法的返回值为数组的长度
  32. ary.shift();
  33. ```
  34. <a name="biACn"></a>
  35. ### 4、原型的重定向
  36. - **手动重定向的原型是没有constructor属性**,可以手动添加一个
  37. - 内置类的原型不允许重定向,但是你可以往他的原型上添加或者覆盖原有的方法
  38. ```javascript
  39. Array.prototype = 100;
  40. console.log(Array.prototype); // 还是原来的
  41. Array.prototype.push = function () {console.log("push")};
  42. ƒ () {console.log("push")} // 返回值
  43. var ary = [1,2,3];
  44. undefined // 返回值
  45. ary.push(4);
  46. VM361:1 push // 打印的push
  47. undefined // 返回值
  48. ary
  49. (3) [1, 2, 3] // 原数组没变
  50. ```
  51. **
  52. ```javascript

function fn() {

  1. this.x = 100;

} fn.prototype.getX = function () {

  1. console.log(this.x);

} var f1 = new fn(); f1.getX(); // f2.getY(); // f2通过给构造函数fn创建的时候,fn的prototype被重新定向 console.log(fn.prototype.constructor);

// 手动重定向的原型没有constructor属性,可以手动添加一个 fn.prototype = {

  1. // constructor : fn,
  2. getY : function () {
  3. console.log(this.x);
  4. }

} var f2 = new fn(); f2.getY(); // 被重新定向的fn的prototype , 没有constructor属性, // 所以通过proto(原型链)找到Object.prototype(其中的constructor值为Object); // (prototype为对象类型,所以proto执行Object.prototype) console.log(fn.prototype.constructor); ~~~

  1. ```javascript
  2. function Fn(){
  3. this.x=100;
  4. }
  5. Fn.prototype.getX=function(){
  6. return this.x;
  7. }
  8. var f1=new Fn();
  9. Fn.prototype={
  10. //consturctor:Fn,
  11. getY:function(){
  12. return this.x
  13. }
  14. };
  15. var f2=new Fn();
  16. console.log(f1.getX()); // 100 跟console的位置没有关系,因为改变fn的prototype后,
  17. // f1仍然执行原来的fn.prototype;而f2指向新的fn.prototype.
  18. console.log(f2.getX()); // 报错
  19. console.log(f1.constructor);
  20. console.log(f2.constructor); // Object

5、在对象的原型上封装一个检测公有属性的方法

  1. Object.prototype.hasPublicProperty = function (pro) {
  2. if (pro in this && !this.hasOwnProperty(pro)) {
  3. return true;
  4. }
  5. return false;
  6. };
  7. var obj = {
  8. name:"aaa",
  9. age : 18
  10. };
  11. obj.hasPublicProperty("name");
  12. [1,2,3].hasPublicProperty("length");
  13. [1,2,3].hasPublicProperty("hasOwnProperty")

三、原型深入

  • 所有的函数:普通函数、类(内置类、自定义类),都是Function的实例,
  • Function和Object都是Function的实例
  • 所有的函数身上都有一个prototype和proto属性(每个实例都是对象,对象身上都有一个proto

原型链3.png

原型链4.png

四、函数的三种角色

  • 普通函数
  • 构造函数
  • 普通对象
  1. function Fn(x,y){
  2. var total=x+y;
  3. this.a=x;
  4. this.b=y;
  5. this.total=total;
  6. }
  7. Fn(1,2); // 当成普通函数执行
  8. var f1=new Fn(3,5); // 构造函数
  9. Fn.myName="lili"; // 普通的对象
  10. console.log(Fn);
  11. console.log(Fn.myName); // myName是Fn的私有属性
  12. console.log(f1.myName); // 实例f1获取不到Fn的私有属性,只能查询到公有属性
  13. // fn.prototype上是公有属性.

阿里面试题

  1. function Foo(){
  2. getName=function(){
  3. console.log(1);
  4. };
  5. return this;
  6. }
  7. Foo.getName=function(){
  8. console.log(2);
  9. }
  10. Foo.prototype.getName=function(){
  11. console.log(3);
  12. }
  13. var getName=function(){
  14. console.log(4);
  15. }
  16. function getName(){
  17. console.log(5);
  18. }
  19. Foo.getName();
  20. getName();
  21. Foo().getName();
  22. getName();
  23. new Foo.getName();
  24. new Foo().getName();
  25. new new Foo().getName();

答案

  1. function Foo(){
  2. getName=function(){
  3. console.log(1);
  4. };
  5. return this;
  6. }
  7. // 下面的Foo当作对象,給Foo添加了getName属性
  8. Foo.getName=function(){
  9. console.log(2);
  10. }
  11. Foo.prototype.getName=function(){
  12. console.log(3);
  13. }
  14. var getName=function(){
  15. console.log(4);
  16. }
  17. function getName(){
  18. console.log(5);
  19. }
  20. Foo.getName(); //
  21. getName();
  22. Foo().getName();
  23. getName();
  24. new Foo.getName(); // 2
  25. new Foo().getName(); // new Foo();执行的结果是一个实例, 然后执行.getName();实例身上没有私有属性getName,通过原型链__proto__在Foo原型上找到getName属性
  26. new new Foo().getName(); // 先运算里层的 new Foo()(看成A),==>A.getName = function () {console.log(3)}
  27. // ==> new function () {console.log(3)};

练习题

1)!!
  1. function Fn() {
  2. let a = 1;
  3. this.a = a;
  4. }
  5. Fn.prototype.say = function () {
  6. this.a = 2;
  7. }
  8. Fn.prototype = new Fn;
  9. let f1 = new Fn;
  10. Fn.prototype.b = function () {
  11. this.a = 3;
  12. };
  13. console.log(f1.a);
  14. console.log(f1.prototype);
  15. console.log(f1.b);
  16. console.log(f1.hasOwnProperty('b'));
  17. console.log('b' in f1);
  18. console.log(f1.constructor == Fn);

2)

  1. function fun() {
  2. this.a = 0;
  3. this.b = function () {
  4. alert(this.a);
  5. }
  6. }
  7. fun.prototype = {
  8. b: function () {
  9. this.a = 20;
  10. alert(this.a);
  11. },
  12. c: function () {
  13. this.a = 30;
  14. alert(this.a)
  15. }
  16. }
  17. var my_fun = new fun();
  18. my_fun.b();
  19. my_fun.c();

3)

  1. function C1(name) {
  2. if (name) {
  3. this.name = name;
  4. }
  5. }
  6. function C2(name) {
  7. this.name = name;
  8. }
  9. function C3(name) {
  10. this.name = name || 'join';
  11. }
  12. C1.prototype.name = 'Tom';
  13. C2.prototype.name = 'Tom';
  14. C3.prototype.name = 'Tom';
  15. alert((new C1().name) + (new C2().name) + (new C3().name));

4)

  1. function Fn(num) {
  2. this.x = this.y = num;
  3. }
  4. Fn.prototype = {
  5. x: 20,
  6. sum: function () {
  7. console.log(this.x + this.y);
  8. }
  9. };
  10. let f = new Fn(10);
  11. console.log(f.sum === Fn.prototype.sum);
  12. f.sum();
  13. Fn.prototype.sum();
  14. console.log(f.constructor);

答案

  1. // 1、
  2. function Fn() {
  3. let a = 1;
  4. this.a = a;
  5. }
  6. Fn.prototype.say = function () {
  7. this.a = 2;
  8. }
  9. Fn.prototype = new Fn;
  10. let f1 = new Fn;
  11. Fn.prototype.b = function () {
  12. this.a = 3;
  13. };
  14. console.log(f1.a); // 1
  15. console.log(f1.prototype); // undefined 所有的对象都没有prototype属性
  16. console.log(f1.b); // function () {this.a = 3};
  17. console.log(f1.hasOwnProperty('b')); // false
  18. console.log('b' in f1); // true
  19. console.log(f1.constructor == Fn); // f1.__proto__.__proto__.constructor = Fn

day16原型链练习题1.png

  1. // 2
  2. function fun() { // my_fun的私有属性 a = 0; b = function() {alert(this.a)};
  3. this.a = 0;
  4. this.b = function () {
  5. alert(this.a);
  6. }
  7. }
  8. fun.prototype = {
  9. b: function () {
  10. this.a = 20;
  11. alert(this.a);
  12. },
  13. c: function () {
  14. this.a = 30;
  15. alert(this.a)
  16. }
  17. }
  18. var my_fun = new fun();
  19. my_fun.b(); // 有私有属性b 弹框打印 my_fun.a = 0
  20. my_fun.c(); // 公有属性c 弹框打印 my_fun.a = 30
  1. // 3
  2. function C1(name) {
  3. if (name) {
  4. this.name = name;
  5. }
  6. }
  7. function C2(name) {
  8. this.name = name;
  9. }
  10. function C3(name) {
  11. this.name = name || 'join';
  12. }
  13. C1.prototype.name = 'Tom';
  14. C2.prototype.name = 'Tom';
  15. C3.prototype.name = 'Tom';
  16. alert((new C1().name) + (new C2().name) + (new C3().name)); // "Tomundefinedjoin"
  1. // 4
  2. function Fn(num) {
  3. this.x = this.y = num;
  4. }
  5. Fn.prototype = {
  6. x: 20,
  7. sum: function () {
  8. console.log(this.x + this.y);
  9. }
  10. };
  11. let f = new Fn(10); // f的私有属性 x = y = 10
  12. console.log(f.sum === Fn.prototype.sum); // true
  13. f.sum(); // 10+10
  14. Fn.prototype.sum(); // 20 + undefined = NaN
  15. console.log(f.constructor); // Object