一、包装类
引用值就是一种对象(泛泛的概括类对象),包括数组、函数、对象。在内存里面存储。
原始值不能有属性和方法,引用值才可以有
但是经过包装类,原始值就能有属性和方法
通过原始值访问属性和方法,系统为了让语法好用,不报错,系统会帮我们进行一个js内部机制包装类
<script>
var str = "abc";
//new String("abc").length
console.log(str.length);
</script>
思路:即隐式的new String构造出一个字符串对象,然后把字符串内容与原来保持一致new String(“abc”),因为我们进行了str.length操作,那么他也加上.length,变成了隐式new String,变成了隐式new String(“abc”).length
这里虽然写的是console.log(str.length),实际上执行的是console.log(new String(“abc”).length)
这样隐式的执行过程就是包装类
<script>
var num = 123;
num.abc = "abc";
//new Number(num).abc="abc"--->delete
//
//new Number(num)..abc
console.log(num.abc);//undefined
</script>
思路:
当 num.abc = “abc”时,系统会进行包装类,隐式的 new
Number(num).abc = “abc”;
执行完这一步以后就会 delete 掉这个隐式的值,并不保
留
等下一步又遇到 num.abc 时,又隐式的 new 了一个 number。
但是这个和上一个是两个 new Number,是两个彼此独立的对象。
new.Number(123).abc 和 var num = new Number(123); num.abc 是一样的
二、原型
任何函数上都有原型,包括构造函数,这是一个构造函数,原型需要基于构造函数,没有原型的构造函数没有意义,任何一个函数都会有prototype
<script>
Person.prototype.lastName = "deng";
function Person() {
//var this={
//
// __proto__: Person.prototype
//}
}
var person = new Person();
console.log(person.lastName); //deng
</script>
三、create
Object.create();是创建的对象,对象必须要有原型,Object.create();需要指定创建对象的原型是谁,括号里面就要填谁(所以括号里面一定要填值)
<script>
var demo = {
lastName: "deng"
}
var obj = Object.create(demo);
obj = {
__proto__: demo
}
</script>
Object.create(prototype,definedProperty)还能填第二个参数。
第一个填的prototype表示你的原型是谁,第二个参数definedProprety是特性(可读可写都是特性)
<script>
var num = 123;
</script>
这个num算window的属性。写在全局的属性
一旦经历了var的操作,所得出的属性window,这种属性叫做不可配置的属性,delete不掉
直接增加的属性叫可配置属性,delete只能删除可配置的属性
<script>
var obj = {
}
obj.num = 234;
</script>
直接在控制台操作对比,发现var 过的属性是不可配置的属性,delete不掉
四、this call
- 1、预编译 this==>window
- 2、谁调用的,this指向谁
- 3、call和apply能改变this指向
- 4、全局this==>window
注释掉的是预编译的过程
<script>
function test() {
var num = 123;
function a() {
}
}
test() -- > AO {
arguments; {},
this: window,
num: undefined,
a: function() {}
}
</script>
test();完全等于test.call();执行
其实test()执行会内部转换成test.call();执行
<script>
function test() {
console.log(this);
}
test();
</script>
如果我们在test.call();里面传值,第一个值就会作为函数执行时的this环境
<script>
function test() {
console.log(this);
}
// test();
test.call({
name: "deng"
});
// test()-->AbortController{
// arguments:{},
// this:{name:"deng"},
// num:undefined,
// a:function(){}
// }
</script>
<script>
var name = "window";
var obj = {
name: "obj",
say: function() {
console.log(this.name);
}
}
obj.say(); //obj
</script>
<script>
var name = "window";
var obj = {
name: "obj",
say: function() {
console.log(this.name);
}
}
obj.say.call(window);//window
</script>
obj.say.call(windwo);有call就打破一切规则,call()里面传的是谁,就是谁
<script>
var name = "window";
var obj = {
name: "obj",
say: function() {
console.log(this.name);
}
}
var fun = obj.say;
fun(); //window
</script>
var fun=obj.say相当于var fun=say:function(){}里面的函数体
fun();相当于让say:function 在这函数的全局范围内自调用,不是谁调用的,就只能走预编译,this就是window
<script>
var name = "window";
var obj = {
name: "obj",
say: function() {
console.log(this.name);
}
}
var fun = obj.say;
fun.call(obj);//obj
</script>
想让Person实现Stundent的功能
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age, sex) {
//var this=Object.create(Student.prototype);
this.name = name;
this.age = age;
//上面两句可以简化Person.call(this,name,age);
this.sex = sex;
}
var student = new Student("cheng", 18, "male");
</script>
五、闭包
闭包表象:一个函数套着另外一个函数,你把被嵌套的函数保存到套他的函数外面(a套着b,你把b弄出a里面),就形成了闭包(不一定要return)
下面两种方法都能实现闭包
<script>
//一
function a() {
function b() {
}
return b;
}
//二
var obj = {};
function a() {
function b() {
}
obj.fun = b;
}
</script>
<script>
var obj = {};
function a() {
var aa = 123;
function b() {
console.log(aa);
}
obj.fun = b;
}
a();
</script>
<script>
var a = 132;
//this call
// Go {
// a: 123
// }
// AO {
// a: undefined
// }
function test() {
a = 1;
var a;
}
test();
</script>
六、构造函数
通过构造函数构造对象的时候用 new,执行函数的时候就不用 new
构造对象必须是 new 加上构造函数执行(如 person();)才能构造出对象
有了 new 之后,才会发生两步隐式变化(var this = {}; return this)
<script>
function Person() {
//var this={}
this.name = "abc";
this.age = 123;
//return this;
}
var person = new Person();
</script>
没有var person=new Person();只Person会走预编译,此时this指向window
私有化属性看不到var money=100;
外部看不到 var money
下面这个就是闭包的应用
<script>
function Person() {
//var this={
//
// makeMoney:function(){}
// offer:function(){}
// }
var money = 100;
this.name = name;
this.makeMoney = function() {
money++;
}
this.offer = function() {
money--;
}
//return this;
}
var person = new Person();
</script>
<script>
var inherit = (function() {
var F = function() {};
return function(Target, Origin) {
F.prototype = Origin.prototype;
Target.prototype = new F();
}
}());
</script>
立即执行函数执行完就成下面这样了
<script>
var inherit = function(Target, Origin) {
F.prototype = Origin.prototype;
Target.prototype = new F();
}
</script>
数组不等于数组,因为里面的地址不一样
七、克隆
<script>
var obj = {
name: "abc"
}
var obj1 = {
}
for (var prop in obj) {
obj1[prop] = obj[prop];
}
</script>
浅克隆:当拷贝引用值的时候就不行了
<script>
var obj = {
name: "abc",
card: ['visa', 'master']
}
var obj1 = {
}
for (var prop in obj) {
obj1[prop] = obj[prop];
}
</script>
这样浅克隆,克隆的是地址,缺点是你改我也改
深度克隆解决的就是引用值
<script>
var obj = {
name: "abc",
wife: {
name: "xiaoxu",
son: {
name: "xiaowen"
}
}
}
var obj1 = {
}
for (var prop in obj) {
obj1[prop] = obj[prop];
}
</script>
深度克隆不拷贝地址,是新建一个来拷贝对象
<script>
var obj1 = {
name: obj.name,
wife: {
name: obj.wife.name,
son: {
name: obj.wife.son.name
}
}
}
</script>
null和undefined不能和数字进行比较,不会进行类型转换,他们不作为比较值存在
下面考私有化变量
打印 1,2,1
例:选择你熟悉的一种方式实现 JavaScript 对象的继承