深入一点-使用bind的时候发生了什么呢

从规范来看,Function.prototype.bind 是如何工作,以及如何来模拟bind操作。 简单示例如下简单示例,普通对象 testObj 内部有一个b函数,接受一个普通参数,若参数为空则输出 this.a。 const testObj = { a: 3, b: function(args) { console.log(args || this.a); },};testObj.b()testObj.b(23)const c = testObj.bc()c(23)const c1 = testObj.b.bind(testObj, 50)c1(70)查看结果: testObj.b 被重新赋值给 c 后,函数的的执行上下文已经改变,导致输出为 undefined。通过上面例子,如果采用 bind 后,则可以改变 testObj的执行上下文,并可以把默认值传递到参数函数列表. 倘若在 testObj.b内,加入 console.log(arguments), 则可以看到如下输出: 50 70bind 函数bind函数是,Function 原型链上的函数,主要是改变函数执行上下文的同时,可以传入函数参数值,并返回新的函数 如图是mdn上的定义, bind产生的函数就一个偏函数,就是说使用bind可以参数一个函数,然后接受新的参数。 In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.详细可看: https://github.com/mqyqingfeng/Blog/issues/43规范定义在EcmaScript的规范 15.3.4.5 中如下截图: ...

November 5, 2019 · 2 min · jiezi

JavaScript基础学习面向对象部分属性类型

前言JavaScript发明之始,从技术上来讲就是一门面向对象的语言,但在ES6之前,JS的很多特性和传统的面向对象语言有所不同,比如没有类的概念(ES6有了class)。今天结合《JS高编》第六章开始回顾和深入学习面向对象部分,包括对象、原型、原型链、继承等部分。 一、理解对象谈JS的对象之前,先复习一下面向对象的基础概念和特点吧。面向对象OOP(Object-oriented programming),结合维基百科和百度百科的阐述,再谈谈我的理解。 官方解释:面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统 我的理解:在JavaScript的世界中,万物皆对象。任何事和物你都可以将其定义为一个对象,程序员界有个笑话就是单身狗可以new一个对象嘛......我的粗浅理解,如果我是一个上帝,这个世界的任何人和事相对于我而言都是一个对象。有了控制对象的权力,我就可以对他们进行任何操作。针对事,我可以发布一个号令,发布一个政策,告诉别人怎么执行,什么时候开始,什么时候结束。针对人,我可以把他们分为男人、女人,这就是类。然后我可以限制他们的儿子是男人还是女人,是男人那就必须有和爸爸一样的性别特征,这就是继承。我还可以控制他们什么时间做什么事等等,整个过程我都是围绕某个对象来展开的,那么这个过程叫做面向对象。 特点:1.类2.继承3.封装4.多态具体的在后面学习和复习时再谈。 二、对象的属性类型1.数据属性:[[Configurable]],[[Enumerable]],[[Writable]],[[Value]]2.访问器属性:[[Configurable]],[[Enumerable]],[[Get]],[[Set]] 书上讲到属性类型时,只是简单提了一下是为了表示对象的特性,描述了属性的特征,并且在JS中不能直接访问。光看介绍不太理解到底是干什么的,但是看了数据属性的内容之后,发现不难理解。 我的理解,数据属性就是我们可以从根源去控制一个对象的属性是否能被修改、删除、循环等,并可以通过访问器属性在别人不知道的情况下进行数据处理。通过Object.defineProperty()这个方法,我们可以去设置这些限制对象属性操作的值,从而限制别人对某个对象属性的操作。举个例子,上面的obj这个对象的name属性的值是“勾鑫宇”,从现在起我不想任何人能够修改它的值,那么我就通过数据属性来将这个属性设置为不可修改,别人用obj.name = "张三"来修改就不会生效了。而我如果想在修改name属性的值后同时让age也跟着改变,那么此时就可以用访问器属性来进行数据处理。 我们是通过Object.defineProperty()这个方法来进行两种属性的设置。那么首先了解一下Object.defineProperty()这个方法,它接收三个参数: Object.defineProperty(对象名,属性名,描述符对象)//举例Object.defineProperty(obj,"name",{ writable:false,//设置不可修改 enumerable:false//设置不可循环到该属性})可以在对象的constructor中找到该方法 同时,我们可以通过Object.getOwnPropertyDescriptor()方法来查看这四个特性的设置情况。接受两个参数: Object.getOwnPropertyDescriptor(对象名,属性名)数据属性数据属性包含一个数据值的位置。在这个位置可以读取和写入值,有4个描述其行为的特性。 下面就具体来对每个数据属性进行分析:1.[[Writable]]:英文意思译为“可写的”,可理解为“可修改的”。这个属性用来设置对象的某个属性是否能被修改,默认为true。 //举例let obj = { name:"勾鑫宇", age:23}Object.defineProperty(obj,"name",{ writable:false,//设置不可修改})//这时再进行修改就不会生效,严格模式下会报错obj.name = "张三"console.log(obj.name)//输出的还是勾鑫宇严格模式报错 2.[[Enumerable]]:英文译为“可数的,可枚举的”,是否支持for-in循环来返回属性,默认为true。 //举例let obj = { name:"勾鑫宇", age:23, gender:male}Object.defineProperty(obj,"name",{ enumerable:false,//设置不可通过for-in循环返回})//循环测试for(let i in obj){ console.log(i)//输出结果为age,gender,没有name属性,效果就像隐藏了这个属性。}//但这时我们的name属性还是存在的console.log(obj)3.[[value]]:这个就不说翻译了,大家都知道,就是值。这个特性是设置我们对象某个属性的值,读值、写值都在这里,默认值为undefined。 //举例let obj = { name:"勾鑫宇", age:23, gender:male}Object.defineProperty(obj,"name",{ value:"张三",//设置name的值为张三})console.log(obj.name)//输出为张三//设置value不影响后面再次修改值,value相当于修改了一次你最先定义的值而已。obj.name = "傻逼"concole.log(obj.name)//输出为“傻逼”4.[[Configurable]]:英文译为“可配置的”,这个和前面的Writable有什么区别呢?放到最后讲是有原因的。前面有设置修改,设置循环,设置值,但是还没有设置是否可删除。Configurable就是做这个事情的。它表示能否通过delete删除属性从而重新定义属性,默认值为true。 //举例let obj = { name:"勾鑫宇", age:23, gender:male}Object.defineProperty(obj,"name",{ configurable:false,//不允许删除属性})delete obj.name//报错"Uncaught TypeError: Cannot delete property 'name' of #<Object>"这个属性还有最重要的一个特点,就是当你设置为false过后,就不能再设为true了,即使你设置了也无效。书上说得个时候你再设置value,enumerable都不会生效,只能设置writable,那么我们来试试。 ...

April 28, 2019 · 1 min · jiezi

深入总结Javascript原型及原型链

本篇文章给大家详细分析了javascript原型及原型链的相关知识点以及用法分享,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。我们创建的每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个原型对象,而这个原型对象中拥有的属性和方法可以被所以实例共享function Person(){}Person.prototype.name = “Nicholas”;Person.prototype.age = 29;Person.prototype.sayName = function(){alert(this.name);};var person1 = new Person();person1.sayName(); //“Nicholas"var person2 = new Person();person2.sayName(); //“Nicholas"alert(person1.sayName == person2.sayName); //true//欢迎加入前端全栈开发交流圈一起学习交流:864305860一、理解原型对象无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 第 5 版中管这个指针叫 [[Prototype]] 。虽然在脚本中没有标准的方式访问 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性__proto__ ;而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。以前面使用 Person 构造函数和 Person.prototype 创建实例的代码为例,图 6-1 展示了各个对象之间的关系。在此, Person.prototype 指向了原型对象,而 Person.prototype.constructor 又指回了 Person 。person1 和 person2 都包含一个内部属性,该属性仅仅指向了 Person.prototype ;换句话说,它们与构造函数没有直接的关系。可以调用 person1.sayName() 。这是通过查找对象属性的过程来实现的。(会先在实例上搜索,如果搜索不到就会继续搜索原型。)用isPrototypeOf()方法判断实例与原型对象之间的关系<br>alert(Person.prototype.isPrototypeOf(person1)); //truealert(Person.prototype.isPrototypeOf(person2)) //true<br><br>用Object.getPrototypeOf() 方法返回实例的原型对象<br>alert(Object.getPrototypeOf(person1) == Person.prototype); //true<br><br>使用 hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是存在于原型中。<br>alert(person1.hasOwnProperty(“name”)); //false 来着原型<br>person1.name = “Greg”;<br>alert(person1.name); //“Greg”——来自实例<br>alert(person1.hasOwnProperty(“name”)); /true<br>//欢迎加入前端全栈开发交流圈一起学习交流:864305860二、更简单的原型语法前面例子中每添加一个属性和方法就要敲一遍 Person.prototype 。为减少不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象。function Person(){}Person.prototype = { name : “Nicholas”, age : 29, job: “Software Engineer”, sayName : function () { alert(this.name); }//欢迎加入前端全栈开发交流圈一起学习交流:864305860};在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外: constructor 属性不再指向 Person 了。前面曾经介绍过,每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性。var friend = new Person();alert(friend instanceof Object); //truealert(friend instanceof Person); //truealert(friend.constructor == Person); //falsealert(friend.constructor == Object); //true//欢迎加入前端全栈开发交流圈一起学习交流:864305860在此,用 instanceof 操作符测试 Object 和 Person 仍然返回 true ,但 constructor 属性则等于 Object 而不等于 Person 了。如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。function Person(){}Person.prototype = { constructor : Person, name : “Nicholas”, age : 29, job: “Software Engineer”, sayName : function () { alert(this.name); }//欢迎加入前端全栈开发交流圈一起学习交流:864305860};三、原生对象的原型所有原生引用类型( Object 、 Array 、 String ,等等)都在其构造函数的原型上定义了方法。例如,在 Array.prototype 中可以找到 sort() 方法,而在 String.prototype 中可以找到substring() 方法。尽管可以这样做,但不推荐修改原生对象的原型。四、原型对象的问题原型模式的最大问题是由其共享的本性所导致的。 修改其中的一个,另一个也会受影响。function Person(){}Person.prototype = {constructor: Person,name : “Nicholas”,age : 29,job : “Software Engineer”,friends : [“Shelby”, “Court”],sayName : function () {alert(this.name);}//欢迎加入前端全栈开发交流圈一起学习交流:864305860};var person1 = new Person();var person2 = new Person();person1.friends.push(“Van”);alert(person1.friends); //“Shelby,Court,Van"alert(person2.friends); //“Shelby,Court,Van"alert(person1.friends === person2.friends); //true五、原型链其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。然后层层递进,就构成了实例与原型的链条,这就是所谓原型链的基本概念。function SuperType(){ this.property = true;}//欢迎加入前端全栈开发交流圈一起学习交流:864305860SuperType.prototype.getSuperValue = function(){ return this.property;};function SubType(){ this.subproperty = false;}//欢迎加入前端全栈开发交流圈一起学习交流:864305860//继承了 SuperTypeSubType.prototype = new SuperType();SubType.prototype.getSubValue = function (){ return this.subproperty;};//欢迎加入前端全栈开发交流圈一起学习交流:864305860var instance = new SubType();alert(instance.getSuperValue()); //trueproperty 则位于 SubType.prototype 中。这是因为 property 是一个实例属性,而 getSuperValue() 则是一个原型方法。既然 SubType.prototype 现在是 SuperType的实例,那么 property 当然就位于该实例中了结语感谢您的观看,如有不足之处,欢迎批评指正。 ...

December 13, 2018 · 2 min · jiezi