function name([param[, param[, ... param]]]) {
statements
}
// name 函数名.
// param 传递给函数的参数的名称,一个函数最多能够有255个参数.
// statements 组成函数体的声明语句.
复制代码
函数声明语句“被提早”到外部脚本或外部函数做用域的顶部,因此能够被在它定义以前出现的代码所调用。javascript
var myFunction = function name([param[, param[, ... param]]]) {
statements
}
// name 函数名,能够省略。当省略函数名的时候,该函数就成为了匿名函数。
// param 与 statements的做用和函数声明中同样。
复制代码
函数表达式不会提高,因此不能在定义以前调用。java
([param] [, param]) => { statements }
param => expression
// param 参数名称. 零参数须要用()表示. 只有一个参数时不须要括号. (例如 foo => 1)
// statements or expression 多个声明statements须要用大括号括起来,而单个表达式时则不须要。表达式expression也是该函数的隐式返回值。
复制代码
由于函数是javascript中的特殊对象,因此它们也能够拥有属性和方法。程序员
函数的length属性是只读属性,他表明函数实参的数量。es6
了解更多请看这篇文章 juejin.im/post/5e6afa…express
同上编程
方法返回一个字符串,这个字符串和函数声明语句的语法有关,大多数(非所有)的toString()方法的实现都返回函数的完整源码。浏览器
所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。闭包
构造函数就是一个普通的函数app
var Animal = function () {
this.name = 'dog';
};
复制代码
上面代码中,Animal就是构造函数。为了与普通函数区别,构造函数名字的第一个字母一般大写。ide
构造函数的特色有两个。
new命令的做用,就是执行构造函数,返回一个实例对象。
var Animal = function () {
this.name = 'dog';
};
var v = new Animal();
v.name // dog
复制代码
解析:
若是忘了使用new命令,直接调用构造函数时,构造函数就变成了普通函数,并不会生成实例对象。
使用new命令时,它后面的函数依次执行下面的步骤。
解析: 也就是说,构造函数内部,this指的是一个新生成的空对象,全部针对this的操做,都会发生在这个空对象上。构造函数之因此叫“构造函数”,就是说这个函数的目的,就是操做一个空对象(即this对象),将其“构造”为须要的样子。
function _new() {
var obj = new Object(); // 1.建立一个空对象,做为将要返回的对象实例。
var Constructor = [].shift.call(arguments); // 取出构造函数。
obj.__proto__ = Constructor.prototype; // 2.将这个空对象的原型,指向构造函数的prototype属性。
var ret = Constructor.apply(obj, arguments); // 3.将这个空对象赋值给函数内部的this关键字。4.开始执行构造函数内部的代码。
return typeof ret === 'object' ? ret : obj;
}
复制代码
JavaScript 的设计是一个简单的基于对象的范式。一个对象就是一系列属性的集合,一个属性包含一个名和一个值。一个属性的值能够是函数,这种状况下属性也被称为方法。除了浏览器里面预约义的那些对象以外,你也能够定义你本身的对象。
对象基础知识请看这三篇文章
为了定义对象类型,为对象类型建立一个函数以声明类型的名称、属性和方法。例如,你想为汽车建立一个类型,而且将这类对象称为 car ,而且拥有属性 make, model, 和 year,你能够建立以下的函数:
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
// 注意经过使用 this 将传入函数的值赋给对象的属性。
复制代码
你能够经过调用 new 建立任意数量的 car 对象。例如:
var kenscar = new Car("Nissan", "300ZX", 1992);
var vpgscar = new Car("Mazda", "Miata", 1990);
// 这就是上文讨论的构造函数的做用
复制代码
对象也能够用 Object.create()方法建立。该方法很是有用,由于它容许你为建立的对象选择一个原型对象,而不用定义构造函数。
var Animal = {
type: "Invertebrates", // 属性默认值
displayType : function() { // 用于显示type属性的方法
console.log(this.type);
}
}
// 建立一种新的动物——animal1
var animal1 = Object.create(Animal); // Animal 是一个普通对象,不是构造函数,咱们也能创造出新动物。
animal1.displayType(); // Invertebrates
复制代码
每个javascript对象(null除外)都和另外一个对象相关联。另外一个对象就是咱们所说的原型,每个对象都从原型继承属性。
每一个实例对象( object )都有一个私有属性(称之为 _ _ proto _ _)指向它的构造函数的原型对象(prototype )。该原型对象也有一个本身的原型对象( _ _ proto _ _ ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并做为这个原型链中的最后一个环节。
从上文可知,全部的函数会有一个特别的属性 —— prototype
function wqh(){};
console.log( wqh.prototype );
复制代码
能够看到输出的prototype是一个对象,有两个属性constructor和 _ _ proto _ _
让咱们点开 _ _ proto _ _ 查看更多内容
由上文咱们知道对象的_ _ proto _ _指向他的它的构造函数的原型对象(prototype),查看截图咱们知道,这里指向了Object原型
function wqh(){};
wqh.prototype.age = 18
console.log( wqh.prototype );
复制代码
让咱们来查看输出结果
function wqh(){};
wqh.prototype.age = 18;
var good = new wqh();
good.height = 178;
console.log( good.age );
console.log( good );
复制代码
让咱们来查看输出结果
可知,new出来的实例对象的_ _ proto _ _属性与wqh构造函数的prototype属性如出一辙。因此实例对象的 _ _ proto _ _ 指向它的构造函数的原型对象(prototype )
这一层一层错的_ _ proto _ _就是原型链。当实例上没有age属性时,他会去 _ _ proto _ _原型上查找,若是尚未会继续往上层查找,这个过程就是原型链查找。
根据上文讨论,画图得
因此当咱们写构造函数时,若是想写一些公共的(可继承的)属性或方法,能够写在prototype原型上。
还有个好处是能够节省内存;例如,在构造函数上写了一个方法,若是new了100个实例,那这个方法将会被构造生成100次,若是将这个方法写在构造函数的原型上,那它只会构造生成一次,new出的实例会在原型链上查找这个方法,大大节省内存。
继承这个概念术语我最先是从java里接触到的,但咱们js里的这个原型链是继承吗?
引用《你不知道的JavaScript》中的话:继承意味着复制操做,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间建立一个关联,这样,一个对象就能够经过委托访问另外一个对象的属性和函数,因此与其叫继承,委托的说法反而更准确些。
但咱们通常仍是会说继承,由于从理解层面来讲意思是同样的,这样跟非javascript程序员就能够正常交流,和同门的js程序员交流必定要讲原型链和原型链查找,这样更准确。
类的概念:一组具备相同属性和行为的对象的抽象。Javascipt语法(es6前)不支持"类"(class)
因此总结来讲:js(es6后)中的类仍是原型和基于原型链的‘继承’来写的构造函数。只是为了语法简洁,通用,便于理解(理解类比理解原型链简单多了)封装的语法。
// 定义构造函数
// 这里遵循一个常见的编程约定:从某种意义上讲,定义构造函数既是定义类,而且类名首字母要大写。
function People(name, age) {
this.name = name;
this.age = age;
};
People.prototype.showName = function () {
console.log(this.name);
};
// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);
复制代码
查看输出结果咱们发现:
function People(name, age) {
this.name = name;
this.age = age;
};
People.prototype = {
showName: function () {
console.log(this.name);
}
}
// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);
复制代码
咱们发现当prototype重定义为一个对象时,这个新定义的原型对象不含有constructor属性,所以类的实例也不含有constructor属性。
显式给原型添加一个构造函数
function People(name, age) {
this.name = name;
this.age = age;
};
People.prototype = {
constructor: People,
showName: function () {
console.log(this.name);
}
}
// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);
复制代码
class People {
constructor (name, age) {
this.name = name;
this.age = age;
}
showName () {
console.log(this.name);
}
};
// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);
复制代码
class People {
constructor() {
// ...
}
showName() {
// ...
}
}
// 等同于
People.prototype = {
constructor() {},
showName() {},
};
// 在类的实例上面调用方法,其实就是调用原型上的方法。
// p2.constructor === People.prototype.constructor // true
复制代码
class People {
hello = 'hello';
world = 'world';
constructor (name, age) {
this.name = name;
this.age = age;
}
showName () {
console.log(this.name);
}
};
// 使用构造函数
var p1 = new People('wqh', 18);
p1.showName();
var p2 = new People('w', 19);
var p3 = new People('q', 20);
console.log(p1, p2, p3);
复制代码
常常据说一句话 ——— ‘js一切皆对象’(排除基本类型)。咱们一开始就说函数是特殊的对象,因此从函数到类其实都是对象,类也是函数,由于类的数据类型就是函数。因此在js世界里,一切皆对象是真实存在的。
因此下次打算梳理 ——— ‘js面向对象编程’。