一、Js中对象和函数的关系
首先什么是对象?
Js中所有事物都是对象,对象是拥有属性和方法的数据,由此可以看出基本数据类型不是对象(number、Boolean、string、undefined);剩下的引用数据类型(函数、数组、null、。。。)都是对象。
对象是通过函数创建的,而函数又是一种对象。
函数是一种对象
- 函数里边可以添加属性
- 很明显,函数是一种对象,但是不能说函数是对象的一种。因为他俩之间没有包含关系
function test() {};console.log(test instanceof Object); // true
对象都是通过函数创建的
先看个例子
function test() {this.name="哈哈"};var test2=new test();console.log(test2 instanceof Object); //true
这个例子可以说明对象可以被函数创建。那为什么要说对象都是通过函数创建的,那对象字面量是不是也是通过函数来创建的,答案是肯定的,这是一种语法糖方式。举个简单的例子
var obj={name:"哈哈",age:"18"}typeof(obj);"object"var obj1 = new Object();typeof(obj1);"object"
上面的对象字面量其实是通过下面的构造函数来创建的。而其中的Object是一种函数:
typeof(Object);"function"
Object 是一种函数
**Object** 构造函数创建一个对象包装器。
语法
// 对象初始化器(Object initialiser)或对象字面量(literal){ [ nameValuePair1[, nameValuePair2[, ...nameValuePairN] ] ] }// 以构造函数形式来调用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();
```<a name="Z14Dg"></a>### 2、封装一个ary.push()方法```javascriptArray.prototype.Mypush=function(){for(var i=0;i<arguments.length;i++){this[this.length]=arguments[i];}return this.length;}var ary1=[1,2,3];var res=ary.Mypush(4,5,6);console.log(ary1);[4,5,6].Mypush(7,8,9);```<a name="Gvkyt"></a>### 3、链式调用> 想要实现一个需求:> var ary=[5,8,2,1,10] ;想要让这个数组先排序,然后再倒序,然后再往里面添加一个10,然后再删除第一项;```javascriptvar ary=[5,8,2,1,10];ary.sort(function(a,b){return a-b});ary.reverse();ary.push(10);ary.shift();```> 实现链式写法:保证每次函数执行完毕后的 返回结果是当前类的实例```javascriptvar ary=[5,8,2,1,10];ary.sort(function(a,b){return a-b}).reverse().push(10);// push();方法的返回值为数组的长度ary.shift();```<a name="biACn"></a>### 4、原型的重定向- **手动重定向的原型是没有constructor属性**,可以手动添加一个- 内置类的原型不允许重定向,但是你可以往他的原型上添加或者覆盖原有的方法```javascriptArray.prototype = 100;console.log(Array.prototype); // 还是原来的Array.prototype.push = function () {console.log("push")};ƒ () {console.log("push")} // 返回值var ary = [1,2,3];undefined // 返回值ary.push(4);VM361:1 push // 打印的pushundefined // 返回值ary(3) [1, 2, 3] // 原数组没变```**```javascript
function fn() {
this.x = 100;
} fn.prototype.getX = function () {
console.log(this.x);
} var f1 = new fn(); f1.getX(); // f2.getY(); // f2通过给构造函数fn创建的时候,fn的prototype被重新定向 console.log(fn.prototype.constructor);
// 手动重定向的原型没有constructor属性,可以手动添加一个 fn.prototype = {
// constructor : fn,getY : function () {console.log(this.x);}
} var f2 = new fn(); f2.getY(); // 被重新定向的fn的prototype , 没有constructor属性, // 所以通过proto(原型链)找到Object.prototype(其中的constructor值为Object); // (prototype为对象类型,所以proto执行Object.prototype) console.log(fn.prototype.constructor); ~~~
```javascriptfunction Fn(){this.x=100;}Fn.prototype.getX=function(){return this.x;}var f1=new Fn();Fn.prototype={//consturctor:Fn,getY:function(){return this.x}};var f2=new Fn();console.log(f1.getX()); // 100 跟console的位置没有关系,因为改变fn的prototype后,// f1仍然执行原来的fn.prototype;而f2指向新的fn.prototype.console.log(f2.getX()); // 报错console.log(f1.constructor);console.log(f2.constructor); // Object
5、在对象的原型上封装一个检测公有属性的方法
Object.prototype.hasPublicProperty = function (pro) {if (pro in this && !this.hasOwnProperty(pro)) {return true;}return false;};var obj = {name:"aaa",age : 18};obj.hasPublicProperty("name");[1,2,3].hasPublicProperty("length");[1,2,3].hasPublicProperty("hasOwnProperty")
三、原型深入
- 所有的函数:普通函数、类(内置类、自定义类),都是Function的实例,
- Function和Object都是Function的实例
- 所有的函数身上都有一个prototype和proto属性(每个实例都是对象,对象身上都有一个proto)

四、函数的三种角色
- 普通函数
- 构造函数
- 普通对象
function Fn(x,y){var total=x+y;this.a=x;this.b=y;this.total=total;}Fn(1,2); // 当成普通函数执行var f1=new Fn(3,5); // 构造函数Fn.myName="lili"; // 普通的对象console.log(Fn);console.log(Fn.myName); // myName是Fn的私有属性console.log(f1.myName); // 实例f1获取不到Fn的私有属性,只能查询到公有属性// fn.prototype上是公有属性.
阿里面试题
function Foo(){getName=function(){console.log(1);};return this;}Foo.getName=function(){console.log(2);}Foo.prototype.getName=function(){console.log(3);}var getName=function(){console.log(4);}function getName(){console.log(5);}Foo.getName();getName();Foo().getName();getName();new Foo.getName();new Foo().getName();new new Foo().getName();
答案
function Foo(){getName=function(){console.log(1);};return this;}// 下面的Foo当作对象,給Foo添加了getName属性Foo.getName=function(){console.log(2);}Foo.prototype.getName=function(){console.log(3);}var getName=function(){console.log(4);}function getName(){console.log(5);}Foo.getName(); //getName();Foo().getName();getName();new Foo.getName(); // 2new Foo().getName(); // new Foo();执行的结果是一个实例, 然后执行.getName();实例身上没有私有属性getName,通过原型链__proto__在Foo原型上找到getName属性new new Foo().getName(); // 先运算里层的 new Foo()(看成A),==>A.getName = function () {console.log(3)}// ==> new function () {console.log(3)};
练习题
1)!!
function Fn() {let a = 1;this.a = a;}Fn.prototype.say = function () {this.a = 2;}Fn.prototype = new Fn;let f1 = new Fn;Fn.prototype.b = function () {this.a = 3;};console.log(f1.a);console.log(f1.prototype);console.log(f1.b);console.log(f1.hasOwnProperty('b'));console.log('b' in f1);console.log(f1.constructor == Fn);
2)
function fun() {this.a = 0;this.b = function () {alert(this.a);}}fun.prototype = {b: function () {this.a = 20;alert(this.a);},c: function () {this.a = 30;alert(this.a)}}var my_fun = new fun();my_fun.b();my_fun.c();
3)
function C1(name) {if (name) {this.name = name;}}function C2(name) {this.name = name;}function C3(name) {this.name = name || 'join';}C1.prototype.name = 'Tom';C2.prototype.name = 'Tom';C3.prototype.name = 'Tom';alert((new C1().name) + (new C2().name) + (new C3().name));
4)
function Fn(num) {this.x = this.y = num;}Fn.prototype = {x: 20,sum: function () {console.log(this.x + this.y);}};let f = new Fn(10);console.log(f.sum === Fn.prototype.sum);f.sum();Fn.prototype.sum();console.log(f.constructor);
答案
// 1、function Fn() {let a = 1;this.a = a;}Fn.prototype.say = function () {this.a = 2;}Fn.prototype = new Fn;let f1 = new Fn;Fn.prototype.b = function () {this.a = 3;};console.log(f1.a); // 1console.log(f1.prototype); // undefined 所有的对象都没有prototype属性console.log(f1.b); // function () {this.a = 3};console.log(f1.hasOwnProperty('b')); // falseconsole.log('b' in f1); // trueconsole.log(f1.constructor == Fn); // f1.__proto__.__proto__.constructor = Fn

// 2function fun() { // my_fun的私有属性 a = 0; b = function() {alert(this.a)};this.a = 0;this.b = function () {alert(this.a);}}fun.prototype = {b: function () {this.a = 20;alert(this.a);},c: function () {this.a = 30;alert(this.a)}}var my_fun = new fun();my_fun.b(); // 有私有属性b 弹框打印 my_fun.a = 0my_fun.c(); // 公有属性c 弹框打印 my_fun.a = 30
// 3function C1(name) {if (name) {this.name = name;}}function C2(name) {this.name = name;}function C3(name) {this.name = name || 'join';}C1.prototype.name = 'Tom';C2.prototype.name = 'Tom';C3.prototype.name = 'Tom';alert((new C1().name) + (new C2().name) + (new C3().name)); // "Tomundefinedjoin"
// 4function Fn(num) {this.x = this.y = num;}Fn.prototype = {x: 20,sum: function () {console.log(this.x + this.y);}};let f = new Fn(10); // f的私有属性 x = y = 10console.log(f.sum === Fn.prototype.sum); // truef.sum(); // 10+10Fn.prototype.sum(); // 20 + undefined = NaNconsole.log(f.constructor); // Object
