一、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()方法
```javascript
Array.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,然后再删除第一项;
```javascript
var ary=[5,8,2,1,10];
ary.sort(function(a,b){return a-b});
ary.reverse();
ary.push(10);
ary.shift();
```
> 实现链式写法:保证每次函数执行完毕后的 返回结果是当前类的实例
```javascript
var 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属性**,可以手动添加一个
- 内置类的原型不允许重定向,但是你可以往他的原型上添加或者覆盖原有的方法
```javascript
Array.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 // 打印的push
undefined // 返回值
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); ~~~
```javascript
function 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(); // 2
new 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); // 1
console.log(f1.prototype); // undefined 所有的对象都没有prototype属性
console.log(f1.b); // function () {this.a = 3};
console.log(f1.hasOwnProperty('b')); // false
console.log('b' in f1); // true
console.log(f1.constructor == Fn); // f1.__proto__.__proto__.constructor = Fn
// 2
function 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 = 0
my_fun.c(); // 公有属性c 弹框打印 my_fun.a = 30
// 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)); // "Tomundefinedjoin"
// 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); // f的私有属性 x = y = 10
console.log(f.sum === Fn.prototype.sum); // true
f.sum(); // 10+10
Fn.prototype.sum(); // 20 + undefined = NaN
console.log(f.constructor); // Object