js的构造函数
2021-03-30 19:25
标签:空间 生成 关于 ceo 语法糖 变量声明 define 存在 var 首先何为函数,简单的说函数就是重复执行的代码块。函数是一段只定义一次但可能被执行或调用任意次的JavaScript 代码。 函数的定义方式分为以下几种: 1.函数声明: function 函数名 () { 函数体 };这种定义方式,会出现函数声明提升(在执行代码之前会先读取函数声明,也就是说,可以把函数声明放在调用它的语句后面)它会被提升到该函数所在作用域的最开头。 2.函数表达式:let fun = function () { 函数体 };(匿名函数)此方式定义的函数,只能在该作用域中,在使用前必须先赋值,再通过fun()调用函数,否则,由于变量声明提升,fun === undefined。 3.new Function 形式: var fun1 = new Function (arg1 , arg2 ,arg3 ,…, argN , body );Function构造函数所有的参数都是字符串类型。除了最后一个参数, 其余的参数都作为生成函数的参数即形参。这里可以没有参数。最后一个参数, 表示的是要创建函数的函数体。 总结: 1 、第一种和第二种函数的定义的方式其实是第三种new Function 的语法糖,当我们定义函数的时候都会通过 new Function 来创建一个函数,只是前两种为我们进行了封装,我们看不见了而已,js 中任意函数都是Function 的实例。 2、ECMAScript 定义的函数实际上是功能完整的对象。 3、函数声明和函数表达式的区别:用函数声明创建的函数可以在函数解析后调用(解析时进行等逻辑处理);而用函数表达式创建的函数是在运行时进行赋值,且要等到表达式赋值完成后才能调用。这本质远原因体现在JavaScript function hoisting(函数提升)和运行时机(解析时/运行时)上的差异。函数声明在JS解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用。而函数表达式的值是在JS运行时确定,并且在表达式赋值完成后,该函数才能调用。 定义:通过 new 函数名 来实例化对象的函数叫构造函数,构造函数首字母一般大写 。任何的函数都可以作为构造函数存在。之所以有构造函数与普通函数之分,主要是从功能上进行区分,构造函数的主要功能为 初始化对象,特点是和new 一起使用。new就是在创建对象,从无到有,构造函数就是在为初始化的对象添加属性和方法。 对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通过new创建的字符串、数字是引用类型,而是非值类型。 1、常用的构造函数: 1. var arr = []; 其实是 var arr = new Array(); 的语法糖。 2. var obj = {} 其实是 var obj = new Object(); 的语法糖 3. var date = new Date(); 4. function Foo (){ }; 其实是 var Foo = new Function(); 2、构造函数的执行过程: 先看个例子 当一个函数创建好以后,虽然函数名为大写,我们也不能确定它是不是构造函数。只有当一个函数以 OK,继续,下面我们只讨论构造函数的执行过程,也就是以 此时,构造函数会有以下几个执行过程: 1> 当以 2> 函数体内部的 通过以上两步,我们就可以得出这样的结论。 每当创建一个实例的时候,就会创建一个新的内存空间(#f2, #f3),创建 #f2 的时候,函数体内部的 this 指向 #f2, 创建 #f3 的时候,函数体内部的 this 指向 #f3。 3> 执行函数体内的代码 通过上面的讲解,你就可以知道,给 this 添加属性,就相当于给实例添加属性。 4> 默认返回 由于函数体内部的 以上就是构造函数的整个执行过程。 3、构造函数的返回值 构造函数执行过程的最后一步是默认返回 (1)没有手动添加返回值,默认返回 (2) 手动添加一个基本数据类型的返回值,最终还是返回 (3) 手动添加一个复杂数据类型(对象)的返回值,最终返回该对象 tips:同上例,如果指定了返回对象,那么,this对象可能会丢失。(自己可以试一下) 4、用new和不要new调用构造函数的区别 1)使用new操作符调用函数 用new调用构造函数,函数内部会发生如下变化: 创建一个this变量,该变量指向一个空对象。并且该对象继承函数的原型; 属性和方法被加入到this引用的对象中; 隐式返回this对象(如果没有显性返回其他对象) 用伪程序来展示上述变化: 可以看出,用new调用构造函数,最大特点为,this对象指向构造函数生成的对象,所以,person1.say()会返回字符串: “I am nicole”。 2)直接调用函数 如果直接调用函数,那么,this对象指向的是window,而且不会默认返回任何对象(除非显性声明返回值)。在上面得例子也有提到过。 还是拿Person函数为例,直接调用Person函数: 可见,直接调用构造函数的结果,并不是我们想要的。 3)技术提升(强行调用new关键字) 为了防止因为忘记使用new关键字而调用构造函数,可以加一些判断条件强行调用new关键字,代码如下: class 为 构造函数的语法糖,即 class 的本质是 构造函数。class的继承 extends 本质 为构造函数的原型链的继承。 例如: 类的写法 构造函数的写法 总结:通过class定义的类 和通过构造函数定义的类 二者本质相同。并且在js执行时,会将第一种转会为第二种执行。所以 ES6 class的写法实质就是构造函数。 js的构造函数 标签:空间 生成 关于 ceo 语法糖 变量声明 define 存在 var 原文地址:https://www.cnblogs.com/yeluo-Blog/p/js_constructor_es6_class.html一、js函数
二、构造函数
1 function Pen(color) {
2 this.color = color;
3 }
new
关键字来调用的时候,我们才能说它是一个构造函数。就像下面这样:1 var dog = new Pen("blue");
new
关键字来调用的情况。1 function Person(name, gender, hobby) {
2 this.name = name;
3 this.gender = gender;
4 this.hobby = hobby;
5 this.age = 6;
6 }
7
8 var p1 = new Person(‘zs‘, ‘男‘, ‘basketball‘);
new
关键字调用时,会创建一个新的内存空间,标记为 Person 的实例this
指向该内存1 var p2 = new Person(‘ls‘, ‘女‘, ‘dancing‘); // 创建一个新的内存 #f2
2 var p3 = new Person(‘ww‘, ‘女‘, ‘singing‘); // 创建一个新的内存 #f3
this
this
指向新创建的内存空间,默认返回 this
,就相当于默认返回了该内存空间,也就是上图中的 #f1。此时,#f1的内存空间被变量 p1
所接受。也就是说 p1
这个变量,保存的内存地址就是 #f1,同时被标记为 Person 的实例。this
。言外之意,构造函数的返回值还有其它情况。下面我们就来聊聊关于构造函数返回值的问题。this
。1 function Foo(name, age) {
2 this.name = name;
3 this.age = age;
4 this.class = ‘class-1‘;
5 // return this //默认有这一行,即便不写也会默认返回 this
6 }
7 var f = new Foo(‘hanri‘, 20);
new
关键字调用时,产生一个新的内存空间 #f11,并标记为 Foo的实例;接着,函数体内部的 this
指向该内存空间 #f11;执行函数体内部的代码;由于函数体内部的 this
指向该内存空间,而该内存空间又被变量 f 所接收,所以 f 中就会有一个 name
属性,属性值为 ‘hanri‘。1 f: {
2 name: "hanri";
3 age: 20;
4 class: "class-1";
5 }
this
。 1 function Foo(name, age) {
2 this.name = name;
3 this.age = age;
4 this.class = ‘class-1‘;
5
6 return 1;
7 }
8 var f = new Foo(‘hanri‘, 20);
9 console.log(f.age); // 构造函数 20 还是返回this
10 var f1 = Foo(‘hanri‘, 20);
11 console.log(f1); // 1 一个普通函数的调用,那么返回值就是 1。
12 //如果没有显性声明 return 1 的话,他是没有默认返回值的
1 f: {
2 name: "hanri";
3 age: 20;
4 class: "class-1";
5 }
1 function Person1() {
2 this.height = ‘170‘;
3 return [‘a‘, ‘b‘, ‘c‘];
4 }
5
6 var p1 = new Person1();
7 console.log(p1.height); // undefined this对象丢失
8 console.log(p1.length); // 3
9 console.log(p1[0]); // ‘a‘
1 function Person(name){
2 this.name = name;
3 this.say = function(){
4 return "I am " + this.name;
5 }
6 var that = {};
7 that.name = "It is that!";
8 return that;
9 }
10
11 var person1 = new Person(‘nicole‘);
12 person1.name; // "It is that!"
1 function Person(name){
2 this.name = name;
3 this.say = function(){
4 return "I am " + this.name;
5 }
6 }
7
8 var person1 = new Person(‘nicole‘);
9 person1.say(); // "I am nicole"
1 function Person(name){
2 // 创建this变量,指向空对象
3 var this = {};
4 // 属性和方法被加入到this引用的对象中
5 this.name = name;
6 this.say = function(){
7 return "I am " + this.name;
8 }
9 // 返回this对象
10 return this;
11 }
1 var person1 = Person(‘nicole‘);
2 person1; // undefined
3 window.name; // nicole
1 function Person(name){
2 if (!(this instanceof Person)) {
3 return new Person(name);
4 }
5 this.name = name;
6 this.say = function(){
7 return "I am " + this.name;
8 }
9 }
10
11 var person1 = Person(‘nicole‘);
12 console.log(person1.say()); // I am nicole
13 var person2 = new Person(‘lisa‘);
14 console.log(person2.say()); // I am lisa
三、ES6 中 class 与构造函数的关系
1 class Person{ //定义一个名字为Person的类
2
3 constructor(name,age){ //constructor是一个构造方法,用来接收参数
4
5 this.name = name; //this代表实例对象
6
7 this.age = age;
8
9 }
10
11 say(){ //这是一个类的方法,注意千万不要加上function
12
13 return this.name + this.age
14
15 }
16
17 }
18
19 var obj = new Person(‘老铁‘,18);
20
21 console.log(obj.say());
1 function Person(name,age){ //构造函数和实例化构造名相同且大写(非强制,但这么写有助于区分构造函数和普通函数)
2
3 if(!(this instanceof Person)){ //避免使用者不小心讲Person当作普通函数执行
4
5 throw new Error(‘‘请使用 new Person"); //仿ES6 class 中的写法
6
7 }
8
9 this.name = name;
10
11 this.age = age;
12
13 }
14
15 Person.prototype.say = function(){
16
17 return this.name + this.age
18
19 }
20
21
22
23 var obj = new Person(‘老铁‘,18); //通过构造函数创建对象,必须使用new运算符
24
25 console.log(obj.say());