​---- 本系列仅为个人学习总结,基于阮一峰大佬的《>>JavaScript 教程<<》​​---

目录

​一.new 命令​

​作用: 执行构造函数,返回一个实例对象​

​若不使用new命令,直接调用构造函数会怎样?​

​补充: ​

​new命令简化的内部流程,​

​new.target属性​

​Object.creat()方法​

​二.this 关键字​

​设计目的:在函数体内部,指代函数当前的运行环境​

​>> this本质  <<​

​注意点​

​Ⅰ.避免多层 this​

​Ⅱ.避免数组处理方法中的 this​

​//Ⅲ.避免回调函数中的 this​

​>> ※绑定 this 的方法 <<​

​三.对象的继承​

​四.Object 对象的相关方法​

​五.严格模式​


 典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)

JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

构造函数的特点:

  1. 函数体内部使用了​​this​​关键字,代表了所要生成的对象实例
  2. 生成对象的时候,必须使用​​new​​命令


一.new 命令

作用: 执行构造函数,返回一个实例对象

var Vehicle = function () {
this.price = 1000;
};

var v = new Vehicle();
v.price // 1000


new命令执行时,构造函数内部的this,就代表了新生成的实例对象

​new​​命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号, 但是为了表示这里是函数调用,推荐使用括号。

若不使用​​new​​命令,直接调用构造函数会怎样?

此时

  • 构造函数变成了普通函数,并不会生成实例对象
  • ​this​​代表了全局对象
var Vehicle = function (){
this.price = 1000;
};

var v = Vehicle();
v // undefined
price // 1000 ,(全局变量)

原本this在最外层代码中便是全局对象, 即[JavaStript学习记录] 二.面向对象 (loading...)_javascript

 [JavaStript学习记录] 二.面向对象 (loading...)_前端_02

补充: 

        博客园 / ~_~ / ​​>>全局对象和this指针<<​

        以及阮一峰老师的文章 ​​>>JavaScript 的 this 原理<<​

  • 为了保证构造函数必须与​​new​​命令一起使用,一个解决办法是,构造函数内部使用严格模式,即第一行加上​​use strict​​。这样的话,一旦忘了使用​​new​​命令,直接调用构造函数就会报错。 
function Animal(age){
'use strict';
this._age = age;
};

var cat = Animal();
//Uncaught TypeError: Cannot set property '_age' of undefined
at Animal

var dog = new Animal(22);
dog._age //22
  • 另一个解决办法,构造函数内部判断是否使用​​new​​命令,如果发现没有使用,则直接返回一个实例对象。 
function Animal(age){
if(!(this instanceof Animal)){
return new Animal(age);
}
this._age=age;
};

var cat = Animal(11);
cat._age;//11

var dog = new Animal(22);
dog._age //22

​new​​命令简化的内部流程,

可以用下面的代码表示

function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
// 将 arguments 对象转为数组
var args = [].slice.call(arguments);
// 取出构造函数
var constructor = args.shift();
// 创建一个空对象,继承构造函数的 prototype 属性
var context = Object.create(constructor.prototype);
// 执行构造函数
var result = constructor.apply(context, args);
// 如果返回结果是对象,就直接返回,否则返回 context 对象
return (typeof result === 'object' && result != null) ? result : context;
}

// 实例
var actor = _new(Person, '张三', 28);

new.target属性

函数内部可以使用new.target属性。如果当前函数是​​new​​​命令调用,​​new.target​​​指向当前函数,否则为​​undefined, ​​​使用这个属性,可以判断函数调用的时候,是否使用​​new​​命令。

function f() {
if (!new.target) {
throw new Error('请使用 new 命令调用!');
}
// ...
}

f() // Uncaught Error: 请使用 new 命令调用!

Object.creat()方法

构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.creat()方法

var catA = {
name : 'mimi',
age : 2,
talk: function(){
console.log('Miao~,my name is '+this.name+'\n');
}
};

var catB = Object.create(catA);
catB.talk(); // Miao~,my name is mimi
catB.age //2

 对象​​catA​​​是​​catB​​的模板,后者继承了前者的属性和方法

二.this 关键字

设计目的:在函数体内部,指代函数当前的运行环境

var f = function () {
console.log(this.x);
}

var x = 1;
var obj = {
f: f,
x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

JavaScript 支持运行环境动态切换,也就是说,​​this​​的指向是动态的,没有办法事先确定到底指向哪个对象

  • 由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即​​this​​的指向是可变的。
var A = {
name: '张三',
describe: function () {
return '姓名:'+ this.name;
}
};

var B = {
name: '李四'
};

B.describe = A.describe;
B.describe()
// "姓名:李四"

如果​​this​​所在的方法不在对象的第一层,这时​​this​​只是指向当前一层的对象,而不会继承更上面的层。

var a = {
p: 'Hello',
b: {
m: function() {
console.log(this.p);
}
}
};

a.b.m() // undefined

上面代码中,​​a.b.m​​​方法在​​a​​​对象的第二层,该方法内部的​​this​​​不是指向​​a​​​,而是指向​​a.b​​,因为实际执行的是下面的代码。

var b = {
m: function() {
console.log(this.p);
}
};

var a = {
p: 'Hello',
b: b
};

(a.b).m() // 等同于 b.m()

如果要达到预期效果,只有写成下面这样。

var a = {
b: {
m: function() {
console.log(this.p);
},
p: 'Hello'
}
};

如果这时将嵌套对象内部的方法赋值给一个变量,​​this​​依然会指向全局对象。

var a = {
b: {
m: function() {
console.log(this.p);
},
p: 'Hello'
}
};

var hello = a.b.m;
hello() // undefined

上面代码中,​​m​​​是多层对象内部的一个方法。为求简便,将其赋值给​​hello​​​变量,结果调用时,​​this​​​指向了顶层对象。为了避免这个问题,可以只将​​m​​​所在的对象赋值给​​hello​​​,这样调用时,​​this​​的指向就不会变。

var hello = a.b;
hello.m() // Hello

​>> this本质  <<​

注意点

Ⅰ.避免多层 this

var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
}();
}
}

o.f1()
// Object
// Window

★实际执行的是下面的代码

var temp = function () {
console.log(this);
};

var o = {
f1: function () {
console.log(this);
var f2 = temp();
}
}

①一个常见的解决方法是在第二层改用一个指向外层​​this​​的变量

var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}

o.f1()
// Object
// Object

②JavaScript 提供了严格模式,也可以硬性避免这种问题。严格模式下,如果函数内部的​​this​​指向顶层对象,就会报错。

var counter = {
count: 0
};
counter.inc = function () {
'use strict';
this.count++
};
var f = counter.inc;
f()
// TypeError: Cannot read property 'count' of undefined

上面代码中,​​inc​​​方法通过​​'use strict'​​​声明采用严格模式,这时内部的​​this​​一旦指向顶层对象,就会报错。

Ⅱ.避免数组处理方法中的 this

var o = {
v: 'hello',
p:['玛卡巴卡','唔西迪西'],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
});
}
}

o.f()

>>undefined a1
>>undefined a2


解决方法👇👇👇
-----------------------
法一:使用中间变量固定this
var o={
v:'hello',
p:['玛卡巴卡','唔西迪西'],
f:function f(){
var that=this;
this.p.forEach(function(item){console.log(that.v+' '+item)});
}
}
o.f()

>>hello 玛卡巴卡
>>hello 唔西迪西

------------------------
法二:将this当作foreach方法的第二个参数,固定它的运行环境
var o = {
v: 'hello',
p:['玛卡巴卡','唔西迪西'],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
}, this);
}
}

o.f()

>>hello 玛卡巴卡
>>hello 唔西迪西

//Ⅲ.避免回调函数中的 this

​>> ※绑定 this 的方法 <<​

​(使用call​​、​​apply​​、​​bind​​这三个方法,来切换/固定​​this​​的指向。)

三.对象的继承

四.Object 对象的相关方法

五.严格模式